From d17067624f3c602b2df32e34ec12ac21c1d94b4b Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Thu, 22 May 2025 15:48:05 +0800 Subject: [PATCH 01/30] feat(ui): integrate devtools plugin and add dark mode support --- packages/ui/package.json | 3 +- packages/ui/src/devtools.css | 558 --------------------------------- packages/ui/src/global.css | 106 +++++++ packages/ui/tailwind.config.js | 21 +- packages/ui/vite.config.mts | 12 +- pnpm-lock.yaml | 3 + 6 files changed, 141 insertions(+), 562 deletions(-) delete mode 100644 packages/ui/src/devtools.css diff --git a/packages/ui/package.json b/packages/ui/package.json index 1bcf73a..162c9ff 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -33,7 +33,8 @@ "qwik": "qwik" }, "peerDependencies": { - "@qwik.dev/core": "^2.0.0-alpha.9" + "@qwik.dev/core": "^2.0.0-alpha.9", + "@devtools/plugin": "workspace:*" }, "devDependencies": { "@devtools/kit": "workspace:*", diff --git a/packages/ui/src/devtools.css b/packages/ui/src/devtools.css deleted file mode 100644 index 518bd15..0000000 --- a/packages/ui/src/devtools.css +++ /dev/null @@ -1,558 +0,0 @@ -.devtools-container { - position: fixed; - bottom: 0; - right: 0; - z-index: 9999; - font-family: - system-ui, - -apple-system, - sans-serif; -} - -.devtools-toggle { - position: fixed; - bottom: 16px; - right: 16px; - width: 36px; - height: 36px; - background: #18181b; - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - box-shadow: - 0 4px 12px rgba(0, 0, 0, 0.15), - inset 0 1px 1px rgba(255, 255, 255, 0.1); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - transform-origin: center; - overflow: hidden; - backdrop-filter: blur(8px); - animation: glow 2s ease-in-out infinite; -} - -@keyframes glow { - 0% { - box-shadow: - 0 4px 12px rgba(0, 0, 0, 0.15), - inset 0 1px 1px rgba(255, 255, 255, 0.1); - } - 50% { - box-shadow: - 0 4px 12px rgba(0, 220, 130, 0.35), - inset 0 1px 1px rgba(255, 255, 255, 0.1), - 0 0 25px rgba(0, 220, 130, 0.25); - border-color: rgba(0, 220, 130, 0.5); - } - 100% { - box-shadow: - 0 4px 12px rgba(0, 0, 0, 0.15), - inset 0 1px 1px rgba(255, 255, 255, 0.1); - } -} - -.devtools-toggle:hover { - transform: scale(1.05); - box-shadow: - 0 6px 16px rgba(0, 220, 130, 0.4), - inset 0 1px 1px rgba(255, 255, 255, 0.15), - 0 0 30px rgba(0, 220, 130, 0.3); - border-color: rgba(0, 220, 130, 0.6); - background: #1c1c1f; - animation: none; -} - -.devtools-toggle:active { - transform: scale(0.98); - box-shadow: - 0 2px 8px rgba(0, 0, 0, 0.15), - inset 0 1px 1px rgba(255, 255, 255, 0.1); - animation: none; -} - -.devtools-toggle.is-open { - transform: rotate(90deg); - background: #1c1c1f; - animation: none; - border-color: rgba(0, 220, 130, 0.5); - box-shadow: - 0 4px 12px rgba(0, 220, 130, 0.35), - inset 0 1px 1px rgba(255, 255, 255, 0.1), - 0 0 25px rgba(0, 220, 130, 0.25); -} - -.devtools-toggle.is-open:hover { - transform: rotate(90deg) scale(1.05); - box-shadow: - 0 6px 16px rgba(0, 220, 130, 0.4), - inset 0 1px 1px rgba(255, 255, 255, 0.15), - 0 0 30px rgba(0, 220, 130, 0.3); -} - -.devtools-panel { - position: fixed; - bottom: 0; - right: 0; - width: 100%; - height: 50vh; - background: #18181b; - border-top: 1px solid rgba(255, 255, 255, 0.1); - color: #fff; - box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.15); - display: flex; - transform: translateY(100%); - transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); - backdrop-filter: blur(16px); -} - -.devtools-open .devtools-panel { - transform: translateY(0); -} - -@media (min-width: 640px) { - .devtools-panel { - width: 60%; - right: 0; - } -} - -.devtools-header { - padding: 12px; - border-bottom: 1px solid #27272a; -} - -.devtools-tabs { - display: flex; - flex-direction: column; - gap: 8px; - padding: 12px; - border-right: 1px solid #27272a; - background: #1c1c1f; -} - -.devtools-tabs button { - padding: 4px; - background: transparent; - border: none; - color: #a1a1aa; - cursor: pointer; - border-radius: 6px; - transition: all 0.2s ease; - display: flex; - align-items: center; - justify-content: center; - width: 36px; - height: 36px; -} - -.devtools-tabs button:hover { - background: #27272a; - color: #fff; -} - -.devtools-tabs button.tab-active { - background: #3b82f6; - color: white; -} - -.devtools-content { - padding: 16px; - height: 100%; - overflow-y: auto; - flex: 1; -} - -.tab-content h3 { - margin: 0 0 16px 0; - font-size: 18px; - font-weight: 600; -} - -.info-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 16px; -} - -.info-item { - background: #27272a; - padding: 12px; - border-radius: 8px; -} - -.info-label { - display: block; - color: #a1a1aa; - font-size: 12px; - margin-bottom: 4px; -} - -.info-value { - font-size: 14px; - font-weight: 500; -} - -/* Asset specific styles */ -.assets-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); - gap: 1.25rem; - margin-top: 1.5rem; - padding: 0.5rem; -} - -.asset-card { - background: rgba(255, 255, 255, 0.03); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 8px; - overflow: hidden; - transition: all 0.2s ease; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.asset-card:hover { - transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - border-color: rgba(255, 255, 255, 0.15); -} - -.asset-preview { - height: 120px; - background: rgba(0, 0, 0, 0.3); - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); -} - -.asset-preview img { - width: 70%; - height: 70%; - object-fit: contain; - padding: 0.5rem; -} - -.file-preview { - height: 120px; - background: rgba(0, 0, 0, 0.2); - display: flex; - align-items: center; - justify-content: center; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); -} - -.file-ext { - font-size: 1.5rem; - font-weight: 600; - color: rgba(255, 255, 255, 0.7); - text-transform: uppercase; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); -} - -.asset-info { - padding: 0.75rem; - background: rgba(0, 0, 0, 0.2); -} - -.asset-path { - color: #fff; - font-size: 0.875rem; - font-weight: 500; - margin-bottom: 0.5rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.asset-meta { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.5rem; -} - -.asset-size { - color: #94a3b8; - font-size: 0.75rem; -} - -.asset-type { - color: #94a3b8; - font-size: 0.75rem; - padding: 0.25rem 0.5rem; - background: rgba(255, 255, 255, 0.1); - border-radius: 4px; - letter-spacing: 0.025em; -} - -.tab-content.overview { - padding: 1.5rem; -} - -.metrics-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1.25rem; - margin-bottom: 2rem; -} - -.metric-card { - background: rgba(255, 255, 255, 0.03); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 12px; - padding: 1.25rem; - display: flex; - align-items: center; - gap: 1.25rem; - transition: all 0.2s ease; -} - -.metric-card:hover { - background: rgba(255, 255, 255, 0.05); - transform: translateY(-1px); -} - -.metric-icon { - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 10px; - padding: 0.875rem; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s ease; -} - -.metric-card:hover .metric-icon { - background: rgba(255, 255, 255, 0.08); -} - -.icon { - width: 1.5rem; - height: 1.5rem; - color: #10b981; -} - -.metric-content { - display: flex; - flex-direction: column; - gap: 0.25rem; -} - -.metric-value { - font-size: 1.75rem; - font-weight: 600; - color: #fff; - line-height: 1.2; -} - -.metric-label { - color: #94a3b8; - font-size: 0.875rem; - font-weight: 500; - letter-spacing: 0.01em; -} - -.performance-section { - background: rgba(255, 255, 255, 0.03); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 12px; - padding: 1.25rem; -} - -.performance-section h3 { - margin: 0 0 1.25rem 0; - font-size: 1rem; - font-weight: 600; - color: #fff; - letter-spacing: 0.01em; -} - -.performance-metrics { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.perf-item { - display: flex; - justify-content: space-between; - color: #94a3b8; - font-size: 0.875rem; - padding: 0.5rem 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.perf-item:last-child { - border-bottom: none; -} - -.perf-value { - color: #fff; - font-weight: 500; -} - -.header-section { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 2rem; - padding-bottom: 1.5rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.title-container { - display: flex; - align-items: center; - gap: 0.75rem; -} - -.qwik-logo { - width: 2rem; - height: 2rem; -} - -.title-container h1 { - font-size: 1.5rem; - font-weight: 600; - color: #fff; - margin: 0; -} - -.version { - font-size: 0.875rem; - color: #94a3b8; - font-weight: 500; - padding: 0.25rem 0.75rem; - background: rgba(255, 255, 255, 0.05); - border-radius: 9999px; - border: 1px solid rgba(255, 255, 255, 0.1); -} - -.packages-section { - background: rgba(255, 255, 255, 0.03); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 12px; - padding: 1.25rem; - margin-bottom: 1.25rem; -} - -.packages-section h3 { - margin: 0 0 1.25rem 0; - font-size: 1rem; - font-weight: 600; - color: #fff; - letter-spacing: 0.01em; -} - -.packages-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - gap: 0.75rem; -} - -.package-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.75rem 1rem; - background: rgba(255, 255, 255, 0.05); - border-radius: 8px; - transition: all 0.2s ease; -} - -.package-item:hover { - background: rgba(255, 255, 255, 0.08); -} - -.package-name { - color: #fff; - font-size: 0.875rem; - font-weight: 500; -} - -.package-version { - color: #94a3b8; - font-size: 0.75rem; - font-weight: 500; - padding: 0.25rem 0.5rem; - background: rgba(255, 255, 255, 0.05); - border-radius: 9999px; - border: 1px solid rgba(255, 255, 255, 0.1); -} - -.tab-content.assets { - padding: 1.5rem; -} - -.assets-stats { - display: flex; - gap: 1rem; -} - -.stat-item { - color: #94a3b8; - font-size: 0.875rem; - padding: 0.25rem 0.75rem; - background: rgba(255, 255, 255, 0.05); - border-radius: 9999px; - border: 1px solid rgba(255, 255, 255, 0.1); -} - -.routes-table { - background: #18181b; - border-radius: 8px; - overflow: hidden; -} - -.table-header { - display: grid; - grid-template-columns: 2fr 1fr 1fr 1fr; - padding: 12px 16px; - background: #27272a; - font-weight: 500; - border-bottom: 1px solid #3f3f46; -} - -.table-row { - display: grid; - grid-template-columns: 2fr 1fr 1fr 1fr; - padding: 12px 16px; - border-bottom: 1px solid #27272a; - align-items: center; -} - -.table-row:hover { - background: #27272a; -} - -.active-route { - background: #22c55e20; - color: #22c55e; - padding: 4px 8px; - border-radius: 4px; -} - -.col-route { - font-family: monospace; -} - -.custom-layout { - color: #3b82f6; -} - -.toggle-icon { - width: 20px; - height: 20px; - transition: all 0.3s ease; - filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2)); - opacity: 0.9; -} - -.devtools-toggle:hover .toggle-icon { - transform: scale(1.1); - filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.3)); - opacity: 1; -} diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index 8387839..21c00f3 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -5,6 +5,112 @@ @tailwind base; @tailwind components; @tailwind utilities; +:root { + --color-background: #FFFFFF; + --color-foreground: #000000; + --color-primary: #3B82F6; + --color-secondary: #6B7280; /* Tailwind's secondary.light */ + --color-border: #E5E7EB; + --color-card: #F3F4F6; + + /* Specific variables based on existing CSS (light theme equivalents) */ + --color-background-darker: #E5E7EB; /* Equivalent for #1c1c1f */ + --color-text-muted: #4B5563; /* Equivalent for #a1a1aa */ + --color-text-subtle: #9CA3AF; /* Equivalent for #94a3b8 */ + + --color-border-translucent: rgba(0, 0, 0, 0.05); /* For rgba(255, 255, 255, 0.1) */ + --color-border-strong-translucent: rgba(0, 0, 0, 0.1); /* For rgba(255,255,255,0.15) and 0.08 */ + --color-border-darker: #D1D5DB; /* For #3f3f46 */ + + --color-shadow-soft: rgba(0, 0, 0, 0.1); /* For general soft shadows like rgba(0,0,0,0.1), rgba(0,0,0,0.15) */ + --color-shadow-medium: rgba(0, 0, 0, 0.15); /* For rgba(0,0,0,0.2) */ + --color-shadow-strong: rgba(0, 0, 0, 0.2); /* For rgba(0,0,0,0.3) */ + + --color-glow-base: rgba(59, 130, 246, 0.2); /* Primary blue for glow */ + --color-glow-border: rgba(59, 130, 246, 0.3); + --color-glow-shadow: rgba(59, 130, 246, 0.15); + --color-glow-hover-base: rgba(59, 130, 246, 0.3); + --color-glow-hover-border: rgba(59, 130, 246, 0.4); + --color-glow-hover-shadow: rgba(59, 130, 246, 0.2); + + --color-icon-accent: #2563EB; /* For #10b981, using primary dark as a placeholder */ + --color-active-route-bg: rgba(59, 130, 246, 0.1); /* Primary with alpha */ + --color-active-route-text: #2563EB; /* Primary dark */ + + --color-card-item-bg: rgba(0, 0, 0, 0.02); /* For rgba(255,255,255,0.03) */ + --color-card-item-hover-bg: rgba(0, 0, 0, 0.03); /* For rgba(255,255,255,0.05) */ + --color-asset-type-bg: rgba(0, 0, 0, 0.05); /* For rgba(255,255,255,0.1) */ + --color-file-ext-text: rgba(0, 0, 0, 0.5); /* For rgba(255,255,255,0.7) */ + + /* Scrollbar variables */ + --color-scrollbar-thumb: #D1D5DB; + --color-scrollbar-thumb-hover: #A1A1AA; + + /* Tailwind semantic variables */ + --color-primary-foreground: #FFFFFF; + --color-secondary-foreground: #FFFFFF; /* Assuming secondary (#6B7280) is dark enough for white text */ + --color-muted: #9CA3AF; /* Similar to existing --color-text-subtle */ + --color-muted-foreground: #4B5563; /* Similar to existing --color-text-muted */ + --color-accent: #10B981; /* Green accent */ + --color-accent-foreground: #FFFFFF; + --color-input: var(--color-border); /* Alias to border */ + --color-ring: var(--color-primary); /* Alias to primary */ + --color-card-foreground: var(--color-foreground); /* Alias to foreground */ +} + +html.dark { + --color-background: #18181B; + --color-foreground: #FFFFFF; + --color-primary: #2563EB; /* Tailwind's primary.dark */ + --color-secondary: #9CA3AF; /* Tailwind's secondary.dark */ + --color-border: #374151; + --color-card: #27272A; + + /* Specific variables based on existing CSS (dark theme) */ + --color-background-darker: #1c1c1f; + --color-text-muted: #a1a1aa; + --color-text-subtle: #94a3b8; + + --color-border-translucent: rgba(255, 255, 255, 0.1); + --color-border-strong-translucent: rgba(255, 255, 255, 0.15); /* For 0.15 and 0.08 on dark */ + --color-border-darker: #3f3f46; + + --color-shadow-soft: rgba(0, 0, 0, 0.15); /* Existing value */ + --color-shadow-medium: rgba(0, 0, 0, 0.2); /* Existing value */ + --color-shadow-strong: rgba(0, 0, 0, 0.3); /* Existing value */ + + /* Glow colors are specific and don't directly map to the main palette */ + --color-glow-base: rgba(0, 220, 130, 0.35); + --color-glow-border: rgba(0, 220, 130, 0.5); + --color-glow-shadow: rgba(0, 220, 130, 0.25); + --color-glow-hover-base: rgba(0, 220, 130, 0.4); + --color-glow-hover-border: rgba(0, 220, 130, 0.6); + --color-glow-hover-shadow: rgba(0, 220, 130, 0.3); + + --color-icon-accent: #10b981; /* Original green */ + --color-active-route-bg: #22c55e20; /* Original green with alpha */ + --color-active-route-text: #22c55e; /* Original green */ + + --color-card-item-bg: rgba(255, 255, 255, 0.03); + --color-card-item-hover-bg: rgba(255, 255, 255, 0.05); + --color-asset-type-bg: rgba(255, 255, 255, 0.1); + --color-file-ext-text: rgba(255, 255, 255, 0.7); + + /* Scrollbar variables */ + --color-scrollbar-thumb: #3f3f46; + --color-scrollbar-thumb-hover: #52525b; + + /* Tailwind semantic variables */ + --color-primary-foreground: #FFFFFF; + --color-secondary-foreground: #FFFFFF; /* Assuming secondary (#9CA3AF) is dark enough for white text */ + --color-muted: #374151; /* Similar to existing html.dark --color-border */ + --color-muted-foreground: #9CA3AF; /* Similar to existing html.dark --color-secondary */ + --color-accent: #10B981; /* Matches existing html.dark --color-icon-accent */ + --color-accent-foreground: #FFFFFF; + --color-input: var(--color-border); /* Alias to border */ + --color-ring: var(--color-primary); /* Alias to primary */ + --color-card-foreground: var(--color-foreground); /* Alias to foreground */ +} @layer utilities { .custom-scrollbar { diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index 1fb56b6..0d9831e 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -1,8 +1,27 @@ /** @type {import('tailwindcss').Config} */ export default { + darkMode: 'class', content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], theme: { - extend: {}, + extend: { + colors: { + background: 'var(--color-background)', + foreground: 'var(--color-foreground)', + primary: 'var(--color-primary)', + 'primary-foreground': 'var(--color-primary-foreground)', // e.g., text on primary button + secondary: 'var(--color-secondary)', // e.g., muted button background or text + 'secondary-foreground': 'var(--color-secondary-foreground)', + muted: 'var(--color-muted)', // e.g., placeholder text or very subtle borders + 'muted-foreground': 'var(--color-muted-foreground)', + accent: 'var(--color-accent)', // e.g., for highlights, icons, or active states + 'accent-foreground': 'var(--color-accent-foreground)', + border: 'var(--color-border)', // default border color + input: 'var(--color-input)', // specific for input borders if different from general border + ring: 'var(--color-ring)', // for focus rings + card: 'var(--color-card)', // card backgrounds + 'card-foreground': 'var(--color-card-foreground)', // text on cards + }, + }, }, plugins: [], }; diff --git a/packages/ui/vite.config.mts b/packages/ui/vite.config.mts index 1ff50b1..ac10c1d 100644 --- a/packages/ui/vite.config.mts +++ b/packages/ui/vite.config.mts @@ -3,12 +3,20 @@ import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; import pkg from "./package.json"; import { qwikReact } from "@qwik.dev/react/vite"; +import { qwikDevtools } from '@devtools/plugin'; +import { createRequire } from "module"; const { dependencies = {}, peerDependencies = {} } = pkg as any; const makeRegex = (dep) => new RegExp(`^${dep}(/.*)?$`); const excludeAll = (obj) => Object.keys(obj).map(makeRegex); - +const require = createRequire(import.meta.url); export default defineConfig(() => { return { + resolve: { + alias: { + '@devtools/ui': require.resolve('.'), + '@qwik.dev/devtools/ui': require.resolve('.') + } + }, build: { target: "es2020", lib: { @@ -32,6 +40,6 @@ export default defineConfig(() => { ], }, }, - plugins: [qwikVite(), tsconfigPaths(), qwikReact()], + plugins: [qwikVite(), tsconfigPaths(), qwikReact(), qwikDevtools()], }; }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92d17a2..79df7f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -239,6 +239,9 @@ importers: packages/ui: dependencies: + '@devtools/plugin': + specifier: workspace:* + version: link:../plugin '@qwik.dev/core': specifier: ^2.0.0-alpha.9 version: 2.0.0-alpha.9(prettier@3.3.3)(vite@6.2.6(@types/node@20.14.11)(jiti@2.4.2)(tsx@4.19.2)(yaml@2.7.0)) From ab9b2d46579155155649804b41e379355f384587 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 23 May 2025 01:48:05 +0000 Subject: [PATCH 02/30] Add light and dark mode support using Tailwind CSS --- package-lock.json | 3389 +++++++++++++++++ .../DevtoolsButton/DevtoolsButton.tsx | 4 +- .../DevtoolsPanel/DevtoolsPanel.tsx | 8 +- packages/ui/src/components/Tab/Tab.tsx | 4 +- .../src/components/TabContent/TabContent.tsx | 2 +- .../components/ThemeToggle/ThemeToggle.tsx | 56 + packages/ui/src/devtools.tsx | 4 +- packages/ui/src/features/Assets/Assets.tsx | 8 +- .../ui/src/features/Components/Components.tsx | 8 +- .../ui/src/features/Overview/Overview.tsx | 42 +- .../ui/src/features/Packages/Packages.tsx | 10 +- .../InstallButton/InstallButton.tsx | 4 +- packages/ui/src/features/Routes/Routes.tsx | 16 +- packages/ui/src/features/inspect/Inspect.tsx | 2 +- packages/ui/src/global.css | 6 +- packages/ui/tailwind.config.js | 12 + 16 files changed, 3518 insertions(+), 57 deletions(-) create mode 100644 package-lock.json create mode 100644 packages/ui/src/components/ThemeToggle/ThemeToggle.tsx diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b7c6fec --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3389 @@ +{ + "name": "qwik-devtools-monorepo", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "qwik-devtools-monorepo", + "license": "MIT", + "devDependencies": { + "@changesets/cli": "^2.27.11", + "@changesets/get-github-info": "^0.6.0", + "@changesets/types": "^6.0.0", + "@types/node": "^22.10.5", + "tsdown": "^0.9.6", + "tsx": "^4.19.2" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@changesets/apply-release-plan": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.12.tgz", + "integrity": "sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/config": "^3.1.1", + "@changesets/get-version-range-type": "^0.4.0", + "@changesets/git": "^3.0.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.8.tgz", + "integrity": "sha512-y8+8LvZCkKJdbUlpXFuqcavpzJR80PN0OIfn8HZdwK7Sh6MgLXm4hKY5vu6/NDoKp8lAlM4ERZCqRMLxP4m+MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", + "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.29.4.tgz", + "integrity": "sha512-VW30x9oiFp/un/80+5jLeWgEU6Btj8IqOgI+X/zAYu4usVOWXjPIK5jSSlt5jsCU7/6Z7AxEkarxBxGUqkAmNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/apply-release-plan": "^7.0.12", + "@changesets/assemble-release-plan": "^6.0.8", + "@changesets/changelog-git": "^0.2.1", + "@changesets/config": "^3.1.1", + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/get-release-plan": "^4.0.12", + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.5", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@changesets/write": "^0.4.0", + "@manypkg/get-packages": "^1.1.3", + "ansi-colors": "^4.1.3", + "ci-info": "^3.7.0", + "enquirer": "^2.4.1", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "mri": "^1.2.0", + "p-limit": "^2.2.0", + "package-manager-detector": "^0.2.0", + "picocolors": "^1.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^3.0.1", + "term-size": "^2.1.0" + }, + "bin": { + "changeset": "bin.js" + } + }, + "node_modules/@changesets/config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.1.tgz", + "integrity": "sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/logger": "^0.1.1", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.8" + } + }, + "node_modules/@changesets/errors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", + "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", + "dev": true, + "license": "MIT", + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz", + "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "picocolors": "^1.1.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/get-github-info": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.6.0.tgz", + "integrity": "sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.12.tgz", + "integrity": "sha512-KukdEgaafnyGryUwpHG2kZ7xJquOmWWWk5mmoeQaSvZTWH1DC5D/Sw6ClgGFYtQnOMSQhgoEbDxAbpIIayKH1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/assemble-release-plan": "^6.0.8", + "@changesets/config": "^3.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.5", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", + "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", + "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.8", + "spawndamnit": "^3.0.1" + } + }, + "node_modules/@changesets/logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", + "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.1.tgz", + "integrity": "sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "js-yaml": "^3.13.1" + } + }, + "node_modules/@changesets/pre": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", + "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.5.tgz", + "integrity": "sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/parse": "^0.4.1", + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0", + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/should-skip-package": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", + "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", + "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/write": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", + "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "human-id": "^4.1.1", + "prettier": "^2.7.1" + } + }, + "node_modules/@emnapi/core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", + "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", + "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@manypkg/find-root/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/find-root/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz", + "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.66.0.tgz", + "integrity": "sha512-KF5Wlo2KzQ+jmuCtrGISZoUfdHom7qHavNfPLW2KkeYJfYMGwtiia8KjwtsvNJ49qRiXImOCkPeVPd4bMlbR7w==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxc-resolver/binding-darwin-arm64": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-9.0.2.tgz", + "integrity": "sha512-MVyRgP2gzJJtAowjG/cHN3VQXwNLWnY+FpOEsyvDepJki1SdAX/8XDijM1yN6ESD1kr9uhBKjGelC6h3qtT+rA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-x64": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-9.0.2.tgz", + "integrity": "sha512-7kV0EOFEZ3sk5Hjy4+bfA6XOQpCwbDiDkkHN4BHHyrBHsXxUR05EcEJPPL1WjItefg+9+8hrBmoK0xRoDs41+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-freebsd-x64": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-9.0.2.tgz", + "integrity": "sha512-6OvkEtRXrt8sJ4aVfxHRikjain9nV1clIsWtJ1J3J8NG1ZhjyJFgT00SCvqxbK+pzeWJq6XzHyTCN78ML+lY2w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-9.0.2.tgz", + "integrity": "sha512-aYpNL6o5IRAUIdoweW21TyLt54Hy/ZS9tvzNzF6ya1ckOQ8DLaGVPjGpmzxdNja9j/bbV6aIzBH7lNcBtiOTkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-9.0.2.tgz", + "integrity": "sha512-RGFW4vCfKMFEIzb9VCY0oWyyY9tR1/o+wDdNePhiUXZU4SVniRPQaZ1SJ0sUFI1k25pXZmzQmIP6cBmazi/Dew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-musl": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-9.0.2.tgz", + "integrity": "sha512-lxx/PibBfzqYvut2Y8N2D0Ritg9H8pKO+7NUSJb9YjR/bfk2KRmP8iaUz3zB0JhPtf/W3REs65oKpWxgflGToA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-9.0.2.tgz", + "integrity": "sha512-yD28ptS/OuNhwkpXRPNf+/FvrO7lwURLsEbRVcL1kIE0GxNJNMtKgIE4xQvtKDzkhk6ZRpLho5VSrkkF+3ARTQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-9.0.2.tgz", + "integrity": "sha512-WBwEJdspoga2w+aly6JVZeHnxuPVuztw3fPfWrei2P6rNM5hcKxBGWKKT6zO1fPMCB4sdDkFohGKkMHVV1eryQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-gnu": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-9.0.2.tgz", + "integrity": "sha512-a2z3/cbOOTUq0UTBG8f3EO/usFcdwwXnCejfXv42HmV/G8GjrT4fp5+5mVDoMByH3Ce3iVPxj1LmS6OvItKMYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-musl": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-9.0.2.tgz", + "integrity": "sha512-bHZF+WShYQWpuswB9fyxcgMIWVk4sZQT0wnwpnZgQuvGTZLkYJ1JTCXJMtaX5mIFHf69ngvawnwPIUA4Feil0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-9.0.2.tgz", + "integrity": "sha512-I5cSgCCh5nFozGSHz+PjIOfrqW99eUszlxKLgoNNzQ1xQ2ou9ZJGzcZ94BHsM9SpyYHLtgHljmOZxCT9bgxYNA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.9" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-9.0.2.tgz", + "integrity": "sha512-5IhoOpPr38YWDWRCA5kP30xlUxbIJyLAEsAK7EMyUgqygBHEYLkElaKGgS0X5jRXUQ6l5yNxuW73caogb2FYaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxc-resolver/binding-win32-x64-msvc": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-9.0.2.tgz", + "integrity": "sha512-Qc40GDkaad9rZksSQr2l/V9UubigIHsW69g94Gswc2sKYB3XfJXfIfyV8WTJ67u6ZMXsZ7BH1msSC6Aen75mCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxc-transform/binding-darwin-arm64": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.67.0.tgz", + "integrity": "sha512-P3zBMhpOQceNSys3/ZqvrjuRvcIbVzfGFN/tH34HlVkOjOmfGK1mOWjORsGAZtbgh1muXrF6mQETLzFjfYndXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-darwin-x64": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.67.0.tgz", + "integrity": "sha512-B52aeo/C3spYHcwFQ4nAbDkwbMKf0K6ncWM8GrVUgGu8PPECLBhjPCW11kPW/lt9FxwrdgVYVzPYlZ6wmJmpEA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm-gnueabihf": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.67.0.tgz", + "integrity": "sha512-5Ir1eQrC9lvj/rR1TJVGwOR4yLgXTLmfKHIfpVH7GGSQrzK7VMUfHWX+dAsX1VutaeE8puXIqtYvf9cHLw78dw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm64-gnu": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.67.0.tgz", + "integrity": "sha512-zTqfPET5+hZfJ3/dMqJboKxrpXMXk+j2HVdvX0wVhW2MI7n7hwELl+In6Yu20nXuEyJkNQlWHbNPCUfpM+cBWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm64-musl": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.67.0.tgz", + "integrity": "sha512-jzz/ATUhZ8wetb4gm5GwzheZns3Qj1CZ+DIMmD8nBxQXszmTS/fqnAPpgzruyLqkXBUuUfF3pHv5f/UmuHReuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-x64-gnu": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.67.0.tgz", + "integrity": "sha512-Qy2+tfglJ8yX6guC1EDAnuuzRZIXciXO9UwOewxyiahLxwuTpj/wvvZN3Cb1SA3c14zrwb2TNMZvaXS1/OS5Pg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-x64-musl": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.67.0.tgz", + "integrity": "sha512-tHoYgDIRhgvh+/wIrzAk3cUoj/LSSoJAdsZW9XRlaixFW/TF2puxRyaS1hRco0bcKTwotXl/eDYqZmhIfUyGRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-wasm32-wasi": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.67.0.tgz", + "integrity": "sha512-ZPT+1HECf7WUnotodIuS8tvSkwaiCdC2DDw8HVRmlerbS6iPYIPKyBCvkSM4RyUx0kljZtB9AciLCkEbwy5/zA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.9" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-win32-arm64-msvc": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.67.0.tgz", + "integrity": "sha512-+E3lOHCk4EuIk6IjshBAARknAUpgH+gHTtZxCPqK4AWYA+Tls2J6C0FVM48uZ4m3rZpAq8ZszM9JZVAkOaynBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-win32-x64-msvc": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.67.0.tgz", + "integrity": "sha512-3pIIFb9g5aFrAODTQVJYitq+ONHgDJ4IYk/7pk+jsG6JpKUkURd0auUlxvriO11fFit5hdwy+wIbU4kBvyRUkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@quansync/fs": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-0.1.3.tgz", + "integrity": "sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.10" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-2F4bhDtV6CHBx7JMiT9xvmxkcZLHFmonfbli36RyfvgThDOAu92bis28zDTdguDY85lN/jBRKX/eOvX+T5hMkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-8VMChhFLeD/oOAQUspFtxZaV7ctDob63w626kwvBBIHtlpY2Ohw4rsfjjtGckyrTCI/RROgZv/TVVEsG3GkgLw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-4W28EgaIidbWIpwB3hESMBfiOSs7LBFpJGa8JIV488qLEnTR/pqzxDEoOPobhRSJ1lJlv0vUgA8+DKBIldo2gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-1ECtyzIKlAHikR7BhS4hk7Hxw8xCH6W3S+Sb74EM0vy5AqPvWSbgLfAwagYC7gNDcMMby3I757X7qih5fIrGiw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-wU1kp8qPRUKC8N82dNs3F5+UyKRww9TUEO5dQ5mxCb0cG+y4l5rVaXpMgvL0VuQahPVvTMs577QPhJGb4iDONw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-odDjO2UtEEMAzwmLHEOKylJjQa+em1REAO9H19PA+O+lPu6evVbre5bqu8qCjEtHG1Q034LpZR86imCP2arb/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-Ty2T67t2Oj1lg417ATRENxdk8Jkkksc/YQdCJyvkGqteHe60pSU2GGP/tLWGB+I0Ox+u387bzU/SmfmrHZk9aw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-Fm1TxyeVE+gy74HM26CwbEOUndIoWAMgWkVDxYBD64tayvp5JvltpGHaqCg6x5i+X2F5XCDCItqwVlC7/mTxIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-AEZzTyGerfkffXmtv7kFJbHWkryNeolk0Br+yhH1wZyN6Tt6aebqICDL8KNRO2iExoEWzyYS6dPxh0QmvNTfUQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.4" + }, + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-0lskDFKQwf5PMjl17qHAroU6oVU0Zn8NbAH/PdM9QB1emOzyFDGa20d4kESGeo3Uq7xOKXcTORJV/JwKIBORqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-DfG1S0zGKnUfr95cNCmR4YPiZ/moS7Tob5eV+9r5JGeHZVWFHWwvJdR0jArj6Ty0LbBFDTVVB3iAvqRSji+l0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-5HZEtc8U2I1O903hXBynWtWaf+qzAFj66h5B7gOtVcvqIk+lKRVSupA85OdIvR7emrsYU25ikpfiU5Jhg9kTbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/node": { + "version": "22.15.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz", + "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@valibot/to-json-schema": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@valibot/to-json-schema/-/to-json-schema-1.0.0.tgz", + "integrity": "sha512-/9crJgPptVsGCL6X+JPDQyaJwkalSZ/52WuF8DiRUxJgcmpNdzYRfZ+gqMEP8W3CTVfuMWPqqvIgfwJ97f9Etw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "valibot": "^1.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ast-kit": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-1.4.3.tgz", + "integrity": "sha512-MdJqjpodkS5J149zN0Po+HPshkTdUyrvF7CKTafUgv69vBSPtncrj+3IiUgqdd7ElIEkbeXCsEouBUwLrw9Ilg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.0", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=16.14.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dts-resolver": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-1.2.0.tgz", + "integrity": "sha512-+xNF7raXYI1E3IFB+f3JqvoKYFI8R+1Mh9mpI75yNm3F5XuiC6ErEXe2Lqh9ach+4MQ1tOefzjxulhWGVclYbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "oxc-resolver": "^9.0.0", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/empathic": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-1.1.0.tgz", + "integrity": "sha512-rsPft6CK3eHtrlp9Y5ALBb+hfK+DWnA4WFebbazxjWyx8vSm3rZeoM3z9irsjcqO3PYRzlfv27XIB4tz2DV7RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/esbuild": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-id": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.1.tgz", + "integrity": "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/oxc-resolver": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-9.0.2.tgz", + "integrity": "sha512-w838ygc1p7rF+7+h5vR9A+Y9Fc4imy6C3xPthCMkdFUgFvUWkmABeNB8RBDQ6+afk44Q60/UMMQ+gfDUW99fBA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-resolver/binding-darwin-arm64": "9.0.2", + "@oxc-resolver/binding-darwin-x64": "9.0.2", + "@oxc-resolver/binding-freebsd-x64": "9.0.2", + "@oxc-resolver/binding-linux-arm-gnueabihf": "9.0.2", + "@oxc-resolver/binding-linux-arm64-gnu": "9.0.2", + "@oxc-resolver/binding-linux-arm64-musl": "9.0.2", + "@oxc-resolver/binding-linux-riscv64-gnu": "9.0.2", + "@oxc-resolver/binding-linux-s390x-gnu": "9.0.2", + "@oxc-resolver/binding-linux-x64-gnu": "9.0.2", + "@oxc-resolver/binding-linux-x64-musl": "9.0.2", + "@oxc-resolver/binding-wasm32-wasi": "9.0.2", + "@oxc-resolver/binding-win32-arm64-msvc": "9.0.2", + "@oxc-resolver/binding-win32-x64-msvc": "9.0.2" + } + }, + "node_modules/oxc-transform": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.67.0.tgz", + "integrity": "sha512-QXwmpLfNrXZoHgIjEtDEf6lhwmvHouNtstNgg/UveczVIjo8VSzd5h25Ea96PoX9KzReJUY/qYa4QSNkJpZGfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-transform/binding-darwin-arm64": "0.67.0", + "@oxc-transform/binding-darwin-x64": "0.67.0", + "@oxc-transform/binding-linux-arm-gnueabihf": "0.67.0", + "@oxc-transform/binding-linux-arm64-gnu": "0.67.0", + "@oxc-transform/binding-linux-arm64-musl": "0.67.0", + "@oxc-transform/binding-linux-x64-gnu": "0.67.0", + "@oxc-transform/binding-linux-x64-musl": "0.67.0", + "@oxc-transform/binding-wasm32-wasi": "0.67.0", + "@oxc-transform/binding-win32-arm64-msvc": "0.67.0", + "@oxc-transform/binding-win32-x64-msvc": "0.67.0" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/quansync": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", + "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.8-commit.151352b", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.8-commit.151352b.tgz", + "integrity": "sha512-TCb6GVaFBk4wB0LERofFDxTO5X1/Sgahr7Yn5UA9XjuFtCwL1CyEhUHX5lUIstcMxjbkLjn2z4TAGwisr6Blvw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "0.66.0", + "@valibot/to-json-schema": "1.0.0", + "ansis": "^3.17.0", + "valibot": "1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "optionalDependencies": { + "@rolldown/binding-darwin-arm64": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-darwin-x64": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.8-commit.151352b", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.8-commit.151352b" + }, + "peerDependencies": { + "@oxc-project/runtime": "0.66.0" + }, + "peerDependenciesMeta": { + "@oxc-project/runtime": { + "optional": true + } + } + }, + "node_modules/rolldown-plugin-dts": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/rolldown-plugin-dts/-/rolldown-plugin-dts-0.9.11.tgz", + "integrity": "sha512-iCIRKmvPLwRV4UKSxhaBo+5wDkvc3+MFiqYYvu7sGLSohzxoDn9WEsjN3y7A6xg3aCuxHh6rlRp8xbX98r1rSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "ast-kit": "^1.4.3", + "debug": "^4.4.0", + "dts-resolver": "^1.0.1", + "get-tsconfig": "^4.10.0", + "oxc-transform": "^0.67.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "rolldown": "^1.0.0-beta.7", + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/spawndamnit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz", + "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "cross-spawn": "^7.0.5", + "signal-exit": "^4.0.1" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tsdown": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.9.9.tgz", + "integrity": "sha512-IIGX55rkhaPomNSVrIbA58DRBwTO4ehlDTsw20XSooGqoEZbwpunDc1dRE73wKb1rHdwwBO6NMLOcgV2n1qhpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^3.17.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.2", + "debug": "^4.4.0", + "diff": "^7.0.0", + "empathic": "^1.0.0", + "hookable": "^5.5.3", + "lightningcss": "^1.29.3", + "rolldown": "1.0.0-beta.8-commit.151352b", + "rolldown-plugin-dts": "^0.9.4", + "tinyexec": "^1.0.1", + "tinyglobby": "^0.2.13", + "unconfig": "^7.3.2", + "unplugin-lightningcss": "^0.3.3" + }, + "bin": { + "tsdown": "dist/run.js" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "publint": "^0.3.0", + "unplugin-unused": "^0.4.0" + }, + "peerDependenciesMeta": { + "publint": { + "optional": true + }, + "unplugin-unused": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/tsx": { + "version": "4.19.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.4.tgz", + "integrity": "sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/unconfig": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-7.3.2.tgz", + "integrity": "sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^0.1.1", + "defu": "^6.1.4", + "jiti": "^2.4.2", + "quansync": "^0.2.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unplugin": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.4.tgz", + "integrity": "sha512-m4PjxTurwpWfpMomp8AptjD5yj8qEZN5uQjjGM3TAs9MWWD2tXSSNNj6jGR2FoVGod4293ytyV6SwBbertfyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.1", + "picomatch": "^4.0.2", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-lightningcss": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/unplugin-lightningcss/-/unplugin-lightningcss-0.3.3.tgz", + "integrity": "sha512-mMNRCNIcxc/3410w7sJdXcPxn0IGZdEpq42OBDyckdGkhOeWYZCG9RkHs72TFyBsS82a4agFDOFU8VrFKF2ZvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.29.3", + "magic-string": "^0.30.17", + "unplugin": "^2.3.2" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/valibot": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0.tgz", + "integrity": "sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + } + } +} diff --git a/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx b/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx index 404cbab..ce37c33 100644 --- a/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx +++ b/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx @@ -91,8 +91,8 @@ export const DevtoolsButton = component$(({ state }: DevtoolsButtonProps) => {
{ return (
+
+ +
); diff --git a/packages/ui/src/components/Tab/Tab.tsx b/packages/ui/src/components/Tab/Tab.tsx index d7896d4..41835cd 100644 --- a/packages/ui/src/components/Tab/Tab.tsx +++ b/packages/ui/src/components/Tab/Tab.tsx @@ -15,9 +15,9 @@ export const Tab = component$(({ state, id, title }) => { class={{ "flex h-10 w-10 items-center justify-center rounded-lg p-2.5 transition-all duration-200": true, - "bg-white/5 text-zinc-400 hover:bg-white/10 hover:text-white": + "bg-foreground/5 text-muted-foreground hover:bg-foreground/10 hover:text-foreground": state.activeTab !== id, - "bg-emerald-500 text-white shadow-lg shadow-emerald-500/35": + "bg-accent text-accent-foreground shadow-lg shadow-accent/35": state.activeTab === id, }} > diff --git a/packages/ui/src/components/TabContent/TabContent.tsx b/packages/ui/src/components/TabContent/TabContent.tsx index b97f41a..0a67374 100644 --- a/packages/ui/src/components/TabContent/TabContent.tsx +++ b/packages/ui/src/components/TabContent/TabContent.tsx @@ -3,7 +3,7 @@ import { component$, Slot } from "@qwik.dev/core"; export const TabContent = component$(() => { return (
-
+
diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx new file mode 100644 index 0000000..f4a3227 --- /dev/null +++ b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx @@ -0,0 +1,56 @@ +import { component$, useSignal, useVisibleTask$, $ } from "@qwik.dev/core"; +import { HiMoonMini, HiSunMini } from "@qwikest/icons/heroicons"; + +export const ThemeToggle = component$(() => { + const isDarkMode = useSignal(false); + + // Initialize theme based on system preference or stored preference + useVisibleTask$(() => { + // Check for stored preference + const storedTheme = localStorage.getItem('theme'); + + if (storedTheme === 'dark') { + isDarkMode.value = true; + document.documentElement.classList.add('dark'); + } else if (storedTheme === 'light') { + isDarkMode.value = false; + document.documentElement.classList.remove('dark'); + } else { + // Check system preference + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + isDarkMode.value = prefersDark; + + if (prefersDark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + } + }); + + const toggleTheme = $(() => { + isDarkMode.value = !isDarkMode.value; + + if (isDarkMode.value) { + document.documentElement.classList.add('dark'); + localStorage.setItem('theme', 'dark'); + } else { + document.documentElement.classList.remove('dark'); + localStorage.setItem('theme', 'light'); + } + }); + + return ( + + ); +}); \ No newline at end of file diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index 43492b1..e82651b 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -113,7 +113,7 @@ export const QwikDevtools = component$(() => { {state.isOpen.value && ( -
+
@@ -153,7 +153,7 @@ export const QwikDevtools = component$(() => { {state.activeTab === "assets" && ( -
+
Total Size:{" "} {( diff --git a/packages/ui/src/features/Assets/Assets.tsx b/packages/ui/src/features/Assets/Assets.tsx index a64efd2..d074535 100644 --- a/packages/ui/src/features/Assets/Assets.tsx +++ b/packages/ui/src/features/Assets/Assets.tsx @@ -15,7 +15,7 @@ export const Assets = component$(({ state }: AssetsProps) => { return (
{isImage ? (
@@ -29,16 +29,16 @@ export const Assets = component$(({ state }: AssetsProps) => {
) : (
- {fileExt} + {fileExt}
)}
{asset.path.split("/").pop()}
-
+
{(asset.size / 1024).toFixed(2)} KB - {fileExt} + {fileExt}
diff --git a/packages/ui/src/features/Components/Components.tsx b/packages/ui/src/features/Components/Components.tsx index 8b4e821..ca2a8f3 100644 --- a/packages/ui/src/features/Components/Components.tsx +++ b/packages/ui/src/features/Components/Components.tsx @@ -49,7 +49,7 @@ const ComponentsStore = component$(() => { return (
@@ -96,7 +96,7 @@ const ComponentStoreUpdate = component$<{

Key: {storeKey}

{ return ( <>
-
-
- +
+
+
{state.routes?.length}
-
pages
+
pages
-
-
- +
+
+
{state.components.length}
-
components
+
components
-
-
- +
+
+
{state.assets.length || 0}
-
assets
+
assets
-
+

Installed Packages

{state.npmPackages.map(([name, version]) => (
{name}
-
+
{version}
@@ -59,19 +59,19 @@ export const Overview = component$(({ state }: OverviewProps) => {
-
+

Performance

-
- SSR to full load +
+ SSR to full load -
-
- Page load +
+ Page load -
- Navigation + Navigation -
diff --git a/packages/ui/src/features/Packages/Packages.tsx b/packages/ui/src/features/Packages/Packages.tsx index a796618..e7766c6 100644 --- a/packages/ui/src/features/Packages/Packages.tsx +++ b/packages/ui/src/features/Packages/Packages.tsx @@ -48,7 +48,7 @@ export const Packages = component$(() => { debounceSearch(target.value); }} placeholder="Search npm packages..." - class="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-2 text-sm text-white placeholder-zinc-500 outline-none focus:border-white/20" + class="w-full rounded-lg border border-border bg-foreground/5 px-4 py-2 text-sm text-foreground placeholder-muted-foreground outline-none focus:border-border" />
@@ -56,7 +56,7 @@ export const Packages = component$(() => { value={searchResults} onPending={() => (
-
+
)} onRejected={(error) => ( @@ -71,12 +71,12 @@ export const Packages = component$(() => { return (
{pkg.name}
-
+
{pkg.version}
{ />
-
+
{pkg.description}
diff --git a/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx b/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx index 03c23e2..7c8853a 100644 --- a/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx +++ b/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx @@ -24,8 +24,8 @@ export const InstallButton = component$( class={[ "rounded-full px-2 py-1 text-xs", installingPackage.value === pkg.name - ? "cursor-not-allowed bg-blue-500/5 text-blue-400/50" - : "bg-blue-500/10 text-blue-400 hover:bg-blue-500/20", + ? "cursor-not-allowed bg-primary/5 text-primary/50" + : "bg-primary/10 text-primary hover:bg-primary/20", ].join(" ")} > {installingPackage.value === pkg.name ? ( diff --git a/packages/ui/src/features/Routes/Routes.tsx b/packages/ui/src/features/Routes/Routes.tsx index d9322dd..38cbcb7 100644 --- a/packages/ui/src/features/Routes/Routes.tsx +++ b/packages/ui/src/features/Routes/Routes.tsx @@ -8,8 +8,8 @@ interface RoutesProps { export const Routes = component$(({ state }: RoutesProps) => { return ( -
-
+
+
Route Path
Name
Middleware
@@ -25,12 +25,12 @@ export const Routes = component$(({ state }: RoutesProps) => { return (
{ {route.relativePath === "" ? "/" : `/${route.relativePath}/`}
-
{route.name}
-
-
+
{route.name}
+
-
0, - "text-zinc-400": !layout || i === 0, + "text-accent": layout && i > 0, + "text-muted-foreground": !layout || i === 0, }} > {layout && i > 0 ? `${route.relativePath}/layout` : "default"} diff --git a/packages/ui/src/features/inspect/Inspect.tsx b/packages/ui/src/features/inspect/Inspect.tsx index 2b13602..de80f29 100644 --- a/packages/ui/src/features/inspect/Inspect.tsx +++ b/packages/ui/src/features/inspect/Inspect.tsx @@ -8,7 +8,7 @@ import {inspectorLink} from './constant' //@ts-ignore export const Inspect = component$(() => { return ( -
+
); diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index 21c00f3..b256a80 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -115,7 +115,7 @@ html.dark { @layer utilities { .custom-scrollbar { scrollbar-width: thin; - scrollbar-color: rgb(63 63 70) transparent; + scrollbar-color: var(--color-scrollbar-thumb) transparent; } .custom-scrollbar::-webkit-scrollbar { @@ -127,11 +127,11 @@ html.dark { } .custom-scrollbar::-webkit-scrollbar-thumb { - background-color: rgb(63 63 70); + background-color: var(--color-scrollbar-thumb); border-radius: 20px; } .custom-scrollbar::-webkit-scrollbar-thumb:hover { - background-color: rgb(82 82 91); + background-color: var(--color-scrollbar-thumb-hover); } } diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index 0d9831e..c0c4bb3 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -20,6 +20,18 @@ export default { ring: 'var(--color-ring)', // for focus rings card: 'var(--color-card)', // card backgrounds 'card-foreground': 'var(--color-card-foreground)', // text on cards + 'card-item-bg': 'var(--color-card-item-bg)', + 'card-item-hover-bg': 'var(--color-card-item-hover-bg)', + 'background-darker': 'var(--color-background-darker)', + 'text-muted': 'var(--color-text-muted)', + 'text-subtle': 'var(--color-text-subtle)', + 'border-translucent': 'var(--color-border-translucent)', + 'border-strong-translucent': 'var(--color-border-strong-translucent)', + 'border-darker': 'var(--color-border-darker)', + 'asset-type-bg': 'var(--color-asset-type-bg)', + 'file-ext-text': 'var(--color-file-ext-text)', + 'active-route-bg': 'var(--color-active-route-bg)', + 'active-route-text': 'var(--color-active-route-text)' }, }, }, From bc6f85fc172f7b4a3e00310f9d1ddbcb3addc6a8 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 23 May 2025 01:59:27 +0000 Subject: [PATCH 03/30] Fix ThemeToggle component and update vite.config.mts for server configuration --- packages/playgrounds/vite.config.mts | 3 +++ .../ui/src/components/ThemeToggle/ThemeToggle.tsx | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/playgrounds/vite.config.mts b/packages/playgrounds/vite.config.mts index a8cd0a5..4ea8ee6 100644 --- a/packages/playgrounds/vite.config.mts +++ b/packages/playgrounds/vite.config.mts @@ -55,6 +55,9 @@ export default defineConfig(({ command, mode }): UserConfig => { // Don't cache the server response in dev mode 'Cache-Control': 'public, max-age=0', }, + host: '0.0.0.0', + port: 12000, + allowedHosts: 'all', }, preview: { headers: { diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx index f4a3227..6cdcb42 100644 --- a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx +++ b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx @@ -1,11 +1,21 @@ -import { component$, useSignal, useVisibleTask$, $ } from "@qwik.dev/core"; +import { component$, useSignal, useTask$, $, useOnWindow } from "@qwik.dev/core"; import { HiMoonMini, HiSunMini } from "@qwikest/icons/heroicons"; export const ThemeToggle = component$(() => { const isDarkMode = useSignal(false); + const isBrowser = useSignal(false); + + // Set isBrowser to true when component is mounted + useOnWindow('load', $(() => { + isBrowser.value = true; + })); // Initialize theme based on system preference or stored preference - useVisibleTask$(() => { + useTask$(({ track }) => { + // Track the isBrowser signal to ensure this runs only in the browser + const browser = track(() => isBrowser.value); + if (!browser) return; + // Check for stored preference const storedTheme = localStorage.getItem('theme'); From b343c146b98862a0d0873fe94e9318c6537b103e Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Sat, 24 May 2025 14:06:39 +0800 Subject: [PATCH 04/30] refactor(ui): remove unused CSS variables and streamline theme configuration Simplify the global CSS and Tailwind configuration by removing unused variables and consolidating theme-related settings. This improves maintainability and reduces redundancy in the codebase. --- .../DevtoolsPanel/DevtoolsPanel.tsx | 5 +- packages/ui/src/devtools.tsx | 5 ++ .../ui/src/features/Packages/Packages.tsx | 2 +- packages/ui/src/features/inspect/Inspect.tsx | 2 +- packages/ui/src/global.css | 55 +------------------ packages/ui/tailwind.config.js | 27 +++------ 6 files changed, 18 insertions(+), 78 deletions(-) diff --git a/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx b/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx index 4de83b7..d7a01fb 100644 --- a/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx +++ b/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx @@ -1,6 +1,6 @@ import { component$, Slot, useSignal, useTask$, isBrowser } from "@qwik.dev/core"; import { State } from "../../types/state"; -import { ThemeToggle } from "../ThemeToggle/ThemeToggle"; + interface DevtoolsPanelProps { state: State; @@ -45,9 +45,6 @@ export const DevtoolsPanel = component$(({ state }: DevtoolsPanelProps) => { ref={panelRef} class="fixed bottom-6 right-6 flex h-[calc(100vh-3rem)] w-[calc(100vw-3rem)] translate-y-0 transform overflow-hidden rounded-lg border-2 border-border bg-background text-foreground backdrop-blur-lg transition-transform duration-300 ease-in-out" > -
- -
); diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index e82651b..22e6eec 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -38,6 +38,7 @@ import { DevtoolsPanel } from "./components/DevtoolsPanel/DevtoolsPanel"; import { Packages } from "./features/Packages/Packages"; import { Components } from "./features/Components/Components"; import { Inspect } from "./features/inspect/Inspect"; +import { ThemeToggle } from "./components/ThemeToggle/ThemeToggle"; function getClientRpcFunctions() { return { @@ -132,6 +133,10 @@ export const QwikDevtools = component$(() => { + +
+ +
diff --git a/packages/ui/src/features/Packages/Packages.tsx b/packages/ui/src/features/Packages/Packages.tsx index e7766c6..11c24ab 100644 --- a/packages/ui/src/features/Packages/Packages.tsx +++ b/packages/ui/src/features/Packages/Packages.tsx @@ -48,7 +48,7 @@ export const Packages = component$(() => { debounceSearch(target.value); }} placeholder="Search npm packages..." - class="w-full rounded-lg border border-border bg-foreground/5 px-4 py-2 text-sm text-foreground placeholder-muted-foreground outline-none focus:border-border" + class="w-full rounded-lg border border-border bg-input px-4 py-2 text-sm text-foreground placeholder-muted-foreground outline-none focus:border-ring" />
diff --git a/packages/ui/src/features/inspect/Inspect.tsx b/packages/ui/src/features/inspect/Inspect.tsx index de80f29..a37501a 100644 --- a/packages/ui/src/features/inspect/Inspect.tsx +++ b/packages/ui/src/features/inspect/Inspect.tsx @@ -9,7 +9,7 @@ import {inspectorLink} from './constant' export const Inspect = component$(() => { return (
- +
); }); diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index b256a80..045f257 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -14,33 +14,11 @@ --color-card: #F3F4F6; /* Specific variables based on existing CSS (light theme equivalents) */ - --color-background-darker: #E5E7EB; /* Equivalent for #1c1c1f */ --color-text-muted: #4B5563; /* Equivalent for #a1a1aa */ - --color-text-subtle: #9CA3AF; /* Equivalent for #94a3b8 */ - --color-border-translucent: rgba(0, 0, 0, 0.05); /* For rgba(255, 255, 255, 0.1) */ - --color-border-strong-translucent: rgba(0, 0, 0, 0.1); /* For rgba(255,255,255,0.15) and 0.08 */ - --color-border-darker: #D1D5DB; /* For #3f3f46 */ - --color-shadow-soft: rgba(0, 0, 0, 0.1); /* For general soft shadows like rgba(0,0,0,0.1), rgba(0,0,0,0.15) */ - --color-shadow-medium: rgba(0, 0, 0, 0.15); /* For rgba(0,0,0,0.2) */ - --color-shadow-strong: rgba(0, 0, 0, 0.2); /* For rgba(0,0,0,0.3) */ - - --color-glow-base: rgba(59, 130, 246, 0.2); /* Primary blue for glow */ - --color-glow-border: rgba(59, 130, 246, 0.3); - --color-glow-shadow: rgba(59, 130, 246, 0.15); - --color-glow-hover-base: rgba(59, 130, 246, 0.3); - --color-glow-hover-border: rgba(59, 130, 246, 0.4); - --color-glow-hover-shadow: rgba(59, 130, 246, 0.2); - - --color-icon-accent: #2563EB; /* For #10b981, using primary dark as a placeholder */ - --color-active-route-bg: rgba(59, 130, 246, 0.1); /* Primary with alpha */ - --color-active-route-text: #2563EB; /* Primary dark */ - - --color-card-item-bg: rgba(0, 0, 0, 0.02); /* For rgba(255,255,255,0.03) */ - --color-card-item-hover-bg: rgba(0, 0, 0, 0.03); /* For rgba(255,255,255,0.05) */ - --color-asset-type-bg: rgba(0, 0, 0, 0.05); /* For rgba(255,255,255,0.1) */ - --color-file-ext-text: rgba(0, 0, 0, 0.5); /* For rgba(255,255,255,0.7) */ + --color-card-item-bg: rgba(0, 0, 0, 0.02); /* For rgba(255,255,255,0.03) 1 */ + --color-card-item-hover-bg: rgba(0, 0, 0, 0.03); /* For rgba(255,255,255,0.05) 1*/ /* Scrollbar variables */ --color-scrollbar-thumb: #D1D5DB; @@ -48,14 +26,12 @@ /* Tailwind semantic variables */ --color-primary-foreground: #FFFFFF; - --color-secondary-foreground: #FFFFFF; /* Assuming secondary (#6B7280) is dark enough for white text */ --color-muted: #9CA3AF; /* Similar to existing --color-text-subtle */ --color-muted-foreground: #4B5563; /* Similar to existing --color-text-muted */ --color-accent: #10B981; /* Green accent */ --color-accent-foreground: #FFFFFF; --color-input: var(--color-border); /* Alias to border */ --color-ring: var(--color-primary); /* Alias to primary */ - --color-card-foreground: var(--color-foreground); /* Alias to foreground */ } html.dark { @@ -67,34 +43,9 @@ html.dark { --color-card: #27272A; /* Specific variables based on existing CSS (dark theme) */ - --color-background-darker: #1c1c1f; --color-text-muted: #a1a1aa; - --color-text-subtle: #94a3b8; - - --color-border-translucent: rgba(255, 255, 255, 0.1); - --color-border-strong-translucent: rgba(255, 255, 255, 0.15); /* For 0.15 and 0.08 on dark */ - --color-border-darker: #3f3f46; - - --color-shadow-soft: rgba(0, 0, 0, 0.15); /* Existing value */ - --color-shadow-medium: rgba(0, 0, 0, 0.2); /* Existing value */ - --color-shadow-strong: rgba(0, 0, 0, 0.3); /* Existing value */ - - /* Glow colors are specific and don't directly map to the main palette */ - --color-glow-base: rgba(0, 220, 130, 0.35); - --color-glow-border: rgba(0, 220, 130, 0.5); - --color-glow-shadow: rgba(0, 220, 130, 0.25); - --color-glow-hover-base: rgba(0, 220, 130, 0.4); - --color-glow-hover-border: rgba(0, 220, 130, 0.6); - --color-glow-hover-shadow: rgba(0, 220, 130, 0.3); - - --color-icon-accent: #10b981; /* Original green */ - --color-active-route-bg: #22c55e20; /* Original green with alpha */ - --color-active-route-text: #22c55e; /* Original green */ - --color-card-item-bg: rgba(255, 255, 255, 0.03); --color-card-item-hover-bg: rgba(255, 255, 255, 0.05); - --color-asset-type-bg: rgba(255, 255, 255, 0.1); - --color-file-ext-text: rgba(255, 255, 255, 0.7); /* Scrollbar variables */ --color-scrollbar-thumb: #3f3f46; @@ -102,14 +53,12 @@ html.dark { /* Tailwind semantic variables */ --color-primary-foreground: #FFFFFF; - --color-secondary-foreground: #FFFFFF; /* Assuming secondary (#9CA3AF) is dark enough for white text */ --color-muted: #374151; /* Similar to existing html.dark --color-border */ --color-muted-foreground: #9CA3AF; /* Similar to existing html.dark --color-secondary */ --color-accent: #10B981; /* Matches existing html.dark --color-icon-accent */ --color-accent-foreground: #FFFFFF; --color-input: var(--color-border); /* Alias to border */ --color-ring: var(--color-primary); /* Alias to primary */ - --color-card-foreground: var(--color-foreground); /* Alias to foreground */ } @layer utilities { diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index c0c4bb3..00e39f3 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -8,30 +8,19 @@ export default { background: 'var(--color-background)', foreground: 'var(--color-foreground)', primary: 'var(--color-primary)', - 'primary-foreground': 'var(--color-primary-foreground)', // e.g., text on primary button - secondary: 'var(--color-secondary)', // e.g., muted button background or text - 'secondary-foreground': 'var(--color-secondary-foreground)', - muted: 'var(--color-muted)', // e.g., placeholder text or very subtle borders + 'primary-foreground': 'var(--color-primary-foreground)', // e.g., text on primary button 2 + secondary: 'var(--color-secondary)', // e.g., muted button background or text 2 + 'secondary-foreground': 'var(--color-secondary-foreground)', // 2 + muted: 'var(--color-muted)', // e.g., placeholder text or very subtle borders 2 'muted-foreground': 'var(--color-muted-foreground)', accent: 'var(--color-accent)', // e.g., for highlights, icons, or active states 'accent-foreground': 'var(--color-accent-foreground)', border: 'var(--color-border)', // default border color - input: 'var(--color-input)', // specific for input borders if different from general border - ring: 'var(--color-ring)', // for focus rings - card: 'var(--color-card)', // card backgrounds - 'card-foreground': 'var(--color-card-foreground)', // text on cards - 'card-item-bg': 'var(--color-card-item-bg)', - 'card-item-hover-bg': 'var(--color-card-item-hover-bg)', - 'background-darker': 'var(--color-background-darker)', + input: 'var(--color-input)', // specific for input borders if different from general border 2 + ring: 'var(--color-ring)', // for focus rings 2 + 'card-item-bg': 'var(--color-card-item-bg)', // 1 + 'card-item-hover-bg': 'var(--color-card-item-hover-bg)', // 1 'text-muted': 'var(--color-text-muted)', - 'text-subtle': 'var(--color-text-subtle)', - 'border-translucent': 'var(--color-border-translucent)', - 'border-strong-translucent': 'var(--color-border-strong-translucent)', - 'border-darker': 'var(--color-border-darker)', - 'asset-type-bg': 'var(--color-asset-type-bg)', - 'file-ext-text': 'var(--color-file-ext-text)', - 'active-route-bg': 'var(--color-active-route-bg)', - 'active-route-text': 'var(--color-active-route-text)' }, }, }, From 89c630297e84f6dc5a09bf30b1e60a2a895f678b Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Sat, 24 May 2025 14:07:45 +0800 Subject: [PATCH 05/30] refactor(vite): remove dev server host and port config --- packages/playgrounds/vite.config.mts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/playgrounds/vite.config.mts b/packages/playgrounds/vite.config.mts index 4ea8ee6..a8cd0a5 100644 --- a/packages/playgrounds/vite.config.mts +++ b/packages/playgrounds/vite.config.mts @@ -55,9 +55,6 @@ export default defineConfig(({ command, mode }): UserConfig => { // Don't cache the server response in dev mode 'Cache-Control': 'public, max-age=0', }, - host: '0.0.0.0', - port: 12000, - allowedHosts: 'all', }, preview: { headers: { From 2022ec4fcbeca45221e29f43e5e794e37119d32f Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Sat, 24 May 2025 16:07:39 +0800 Subject: [PATCH 06/30] refactor(vite): remove dev server host and port config The host, port, and allowedHosts configurations were removed from the dev server settings to simplify the configuration and rely on Vite's default behavior. This change reduces unnecessary customization and aligns with standard Vite practices. --- .../components/ThemeToggle/ThemeToggle.tsx | 57 +------ packages/ui/src/features/inspect/Inspect.tsx | 1 + packages/ui/src/hooks/useDark.ts | 151 ++++++++++++++++++ packages/ui/src/hooks/useDebouncer.ts | 2 + 4 files changed, 160 insertions(+), 51 deletions(-) create mode 100644 packages/ui/src/hooks/useDark.ts diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx index 6cdcb42..5b417fb 100644 --- a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx +++ b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx @@ -1,62 +1,17 @@ -import { component$, useSignal, useTask$, $, useOnWindow } from "@qwik.dev/core"; +import { component$ } from "@qwik.dev/core"; import { HiMoonMini, HiSunMini } from "@qwikest/icons/heroicons"; +import { useDark } from "../../hooks/useDark"; export const ThemeToggle = component$(() => { - const isDarkMode = useSignal(false); - const isBrowser = useSignal(false); - - // Set isBrowser to true when component is mounted - useOnWindow('load', $(() => { - isBrowser.value = true; - })); - - // Initialize theme based on system preference or stored preference - useTask$(({ track }) => { - // Track the isBrowser signal to ensure this runs only in the browser - const browser = track(() => isBrowser.value); - if (!browser) return; - - // Check for stored preference - const storedTheme = localStorage.getItem('theme'); - - if (storedTheme === 'dark') { - isDarkMode.value = true; - document.documentElement.classList.add('dark'); - } else if (storedTheme === 'light') { - isDarkMode.value = false; - document.documentElement.classList.remove('dark'); - } else { - // Check system preference - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - isDarkMode.value = prefersDark; - - if (prefersDark) { - document.documentElement.classList.add('dark'); - } else { - document.documentElement.classList.remove('dark'); - } - } - }); - - const toggleTheme = $(() => { - isDarkMode.value = !isDarkMode.value; - - if (isDarkMode.value) { - document.documentElement.classList.add('dark'); - localStorage.setItem('theme', 'dark'); - } else { - document.documentElement.classList.remove('dark'); - localStorage.setItem('theme', 'light'); - } - }); + const dark = useDark(); return ( ); -}); \ No newline at end of file +}); diff --git a/packages/ui/src/components/router-head/theme-script.tsx b/packages/ui/src/components/router-head/theme-script.tsx index 0f6211f..54e510a 100644 --- a/packages/ui/src/components/router-head/theme-script.tsx +++ b/packages/ui/src/components/router-head/theme-script.tsx @@ -1,12 +1,11 @@ -export const themeStorageKey = 'theme-preference'; +export const themeStorageKey = "theme-preference"; export const ThemeScript = () => { const themeScript = ` try { - document.firstElementChild - .setAttribute('data-theme', - localStorage.getItem('${themeStorageKey}') ?? - (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') - ); - } catch (e) { }`.replace(/\s+/g, ''); - return themeScript -}; \ No newline at end of file + const p = localStorage.getItem('${themeStorageKey}'); + if (p) { + document.documentElement.setAttribute('data-theme', p); + } + } catch (e) { }`.replace(/\s+/g, ""); + return themeScript; +}; diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index 66aaa40..280d167 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -7,7 +7,7 @@ import { useTask$, isBrowser, useOnDocument, - $ + sync$, } from "@qwik.dev/core"; import { tryCreateHotContext } from "vite-hot-client"; import { @@ -15,7 +15,7 @@ import { HiCubeOutline, HiPhotoOutline, HiCodeBracketMini, - HiMegaphoneMini + HiMegaphoneMini, } from "@qwikest/icons/heroicons"; import { LuFolderTree } from "@qwikest/icons/lucide"; import { @@ -61,63 +61,61 @@ export const QwikDevtools = component$(() => { }); useOnDocument( - 'qinit', - $(() => { - const scriptElement = document.createElement('script'); + "DOMContentLoaded", + sync$(() => { + const scriptElement = document.createElement("script"); scriptElement.innerHTML = ThemeScript(); - document.body.appendChild( - scriptElement - ); - }) + document.head.prepend(scriptElement); + }), ); // eslint-disable-next-line qwik/no-use-visible-task useTask$(async ({ track }) => { if (isBrowser) { - const hot = await tryCreateHotContext(undefined, ["/"]); + const hot = await tryCreateHotContext(undefined, ["/"]); - if (!hot) { - throw new Error("Vite Hot Context not connected"); - } + if (!hot) { + throw new Error("Vite Hot Context not connected"); + } - setViteClientContext(hot); - createClientRpc(getClientRpcFunctions()); + setViteClientContext(hot); + createClientRpc(getClientRpcFunctions()); - track(() => { - if (state.isOpen.value) { - const rpc = getViteClientRpc(); - rpc.getAssetsFromPublicDir().then((data) => { - state.assets = data; - }); - rpc.getComponents().then((data) => { - state.components = data; - }); - rpc.getRoutes().then((data: RoutesInfo) => { - const children: RoutesInfo[] = data.children || []; - const directories: RoutesInfo[] = children.filter( - (child) => child.type === "directory", - ); + track(() => { + if (state.isOpen.value) { + const rpc = getViteClientRpc(); + rpc.getAssetsFromPublicDir().then((data) => { + state.assets = data; + }); + rpc.getComponents().then((data) => { + state.components = data; + }); + rpc.getRoutes().then((data: RoutesInfo) => { + const children: RoutesInfo[] = data.children || []; + const directories: RoutesInfo[] = children.filter( + (child) => child.type === "directory", + ); - const values: RoutesInfo[] = [ - { - relativePath: "", - name: "index", - type: RouteType.DIRECTORY, - path: "", - isSymbolicLink: false, - children: undefined, - }, - ...directories, - ]; + const values: RoutesInfo[] = [ + { + relativePath: "", + name: "index", + type: RouteType.DIRECTORY, + path: "", + isSymbolicLink: false, + children: undefined, + }, + ...directories, + ]; - state.routes = noSerialize(values); - }); + state.routes = noSerialize(values); + }); - rpc.getQwikPackages().then((data: NpmInfo) => { - state.npmPackages = data; - }); - } - }); - } + rpc.getQwikPackages().then((data: NpmInfo) => { + state.npmPackages = data; + }); + } + }); + } }); return ( @@ -126,7 +124,7 @@ export const QwikDevtools = component$(() => { {true && ( -
+
@@ -147,7 +145,7 @@ export const QwikDevtools = component$(() => {
- +
@@ -207,7 +205,7 @@ export const QwikDevtools = component$(() => { )} {state.activeTab === "inspect" && ( - + )}
@@ -216,4 +214,3 @@ export const QwikDevtools = component$(() => { ); }); - diff --git a/packages/ui/src/features/Assets/Assets.tsx b/packages/ui/src/features/Assets/Assets.tsx index d074535..b8d0710 100644 --- a/packages/ui/src/features/Assets/Assets.tsx +++ b/packages/ui/src/features/Assets/Assets.tsx @@ -29,7 +29,9 @@ export const Assets = component$(({ state }: AssetsProps) => {
) : (
- {fileExt} + + {fileExt} +
)}
@@ -38,7 +40,9 @@ export const Assets = component$(({ state }: AssetsProps) => {
{(asset.size / 1024).toFixed(2)} KB - {fileExt} + + {fileExt} +
diff --git a/packages/ui/src/features/Components/styles.css b/packages/ui/src/features/Components/styles.css index a106fd7..188bf7b 100644 --- a/packages/ui/src/features/Components/styles.css +++ b/packages/ui/src/features/Components/styles.css @@ -1,38 +1,38 @@ :root { - --rct-color-tree-bg: transparent; - --rct-item-height: 32px; - --rct-color-search-highlight-bg: rgba(59, 130, 246, 0.2); - - --rct-color-tree-focus-outline: transparent; - --rct-item-margin: 1px; - --rct-item-padding: 8px; - --rct-radius: 6px; - --rct-bar-offset: 6px; - --rct-bar-width: 2px; - --rct-bar-color: rgb(16, 185, 129); - --rct-focus-outline: #000000; - - --rct-color-focustree-item-selected-bg: #fff; - --rct-color-focustree-item-hover-bg: rgba(255, 255, 255, 0.03); - --rct-color-focustree-item-hover-text: #fff; - --rct-color-focustree-item-active-bg: rgba(255, 255, 255, 0.08); - --rct-color-focustree-item-active-text: #fff; - - --rct-arrow-size: 10px; - --rct-arrow-container-size: 16px; - --rct-arrow-padding: 6px; - --rct-color-arrow: rgb(16 185 129 / var(--tw-bg-opacity, 1)); - --rct-cursor: pointer; - - --rct-search-width: 100%; - --rct-search-height: 32px; - --rct-search-padding: 8px; - --rct-search-border: rgba(255, 255, 255, 0.1); - --rct-search-border-bottom: rgb(16, 185, 129); - --rct-search-bg: rgba(255, 255, 255, 0.03); - --rct-search-text: #fff; - --rct-search-text-offset: calc(var(--rct-search-padding) * 2 + 16px); - } + --rct-color-tree-bg: transparent; + --rct-item-height: 32px; + --rct-color-search-highlight-bg: rgba(59, 130, 246, 0.2); + + --rct-color-tree-focus-outline: transparent; + --rct-item-margin: 1px; + --rct-item-padding: 8px; + --rct-radius: 6px; + --rct-bar-offset: 6px; + --rct-bar-width: 2px; + --rct-bar-color: rgb(16, 185, 129); + --rct-focus-outline: #000000; + + --rct-color-focustree-item-selected-bg: #fff; + --rct-color-focustree-item-hover-bg: rgba(255, 255, 255, 0.03); + --rct-color-focustree-item-hover-text: #fff; + --rct-color-focustree-item-active-bg: rgba(255, 255, 255, 0.08); + --rct-color-focustree-item-active-text: #fff; + + --rct-arrow-size: 10px; + --rct-arrow-container-size: 16px; + --rct-arrow-padding: 6px; + --rct-color-arrow: rgb(16 185 129 / var(--tw-bg-opacity, 1)); + --rct-cursor: pointer; + + --rct-search-width: 100%; + --rct-search-height: 32px; + --rct-search-padding: 8px; + --rct-search-border: rgba(255, 255, 255, 0.1); + --rct-search-border-bottom: rgb(16, 185, 129); + --rct-search-bg: rgba(255, 255, 255, 0.03); + --rct-search-text: #fff; + --rct-search-text-offset: calc(var(--rct-search-padding) * 2 + 16px); +} /* Add these additional styles to match devtools theme */ .rct-tree-item-button { @@ -64,4 +64,4 @@ border-color: rgb(16, 185, 129) !important; outline: none !important; box-shadow: 0 0 0 1px rgb(16, 185, 129) !important; -} \ No newline at end of file +} diff --git a/packages/ui/src/features/Overview/Overview.tsx b/packages/ui/src/features/Overview/Overview.tsx index 626abdb..a5a01a4 100644 --- a/packages/ui/src/features/Overview/Overview.tsx +++ b/packages/ui/src/features/Overview/Overview.tsx @@ -12,7 +12,7 @@ export const Overview = component$(({ state }: OverviewProps) => { <>
-
+
@@ -22,7 +22,7 @@ export const Overview = component$(({ state }: OverviewProps) => {
-
+
@@ -32,7 +32,7 @@ export const Overview = component$(({ state }: OverviewProps) => {
-
+
@@ -48,10 +48,10 @@ export const Overview = component$(({ state }: OverviewProps) => { {state.npmPackages.map(([name, version]) => (
{name}
-
+
{version}
diff --git a/packages/ui/src/features/Packages/Packages.tsx b/packages/ui/src/features/Packages/Packages.tsx index 11c24ab..d374e4c 100644 --- a/packages/ui/src/features/Packages/Packages.tsx +++ b/packages/ui/src/features/Packages/Packages.tsx @@ -56,7 +56,7 @@ export const Packages = component$(() => { value={searchResults} onPending={() => (
-
+
)} onRejected={(error) => ( @@ -71,12 +71,12 @@ export const Packages = component$(() => { return (
{pkg.name}
-
+
{pkg.version}
{installingPackage.value === pkg.name ? ( diff --git a/packages/ui/src/features/Routes/Routes.tsx b/packages/ui/src/features/Routes/Routes.tsx index 38cbcb7..34ca030 100644 --- a/packages/ui/src/features/Routes/Routes.tsx +++ b/packages/ui/src/features/Routes/Routes.tsx @@ -6,9 +6,8 @@ interface RoutesProps { } export const Routes = component$(({ state }: RoutesProps) => { - return ( -
+
Route Path
Name
@@ -31,8 +30,7 @@ export const Routes = component$(({ state }: RoutesProps) => { diff --git a/packages/ui/src/features/inspect/Inspect.tsx b/packages/ui/src/features/inspect/Inspect.tsx index 0dd238f..b9f3412 100644 --- a/packages/ui/src/features/inspect/Inspect.tsx +++ b/packages/ui/src/features/inspect/Inspect.tsx @@ -1,16 +1,20 @@ import { component$ } from "@qwik.dev/core"; // import { State } from "../../types/state"; -import {inspectorLink} from './constant' +import { inspectorLink } from "./constant"; // interface RoutesProps { // state: State; // } //@ts-ignore export const Inspect = component$(() => { - return ( -
- +
+
); }); diff --git a/packages/ui/src/features/inspect/constant.ts b/packages/ui/src/features/inspect/constant.ts index a02c774..f7157c5 100644 --- a/packages/ui/src/features/inspect/constant.ts +++ b/packages/ui/src/features/inspect/constant.ts @@ -1 +1 @@ -export const inspectorLink = "__inspect/" \ No newline at end of file +export const inspectorLink = "__inspect/"; diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index a65edb2..c05b860 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -6,43 +6,47 @@ @tailwind components; @tailwind utilities; :root { - --theme-name: 'light'; - --color-background: #FFFFFF; + --theme-name: "light"; + --color-background: #ffffff; --color-foreground: #000000; - --color-primary: #3B82F6; - --color-secondary: #6B7280; /* Tailwind's secondary.light */ - --color-border: #E5E7EB; - --color-card: #F3F4F6; + --color-primary: #3b82f6; + --color-secondary: #6b7280; /* Tailwind's secondary.light */ + --color-border: #e5e7eb; + --color-card: #f3f4f6; /* Specific variables based on existing CSS (light theme equivalents) */ - --color-text-muted: #4B5563; /* Equivalent for #a1a1aa */ - + --color-text-muted: #4b5563; /* Equivalent for #a1a1aa */ --color-card-item-bg: rgba(0, 0, 0, 0.02); /* For rgba(255,255,255,0.03) 1 */ - --color-card-item-hover-bg: rgba(0, 0, 0, 0.03); /* For rgba(255,255,255,0.05) 1*/ + --color-card-item-hover-bg: rgba( + 0, + 0, + 0, + 0.03 + ); /* For rgba(255,255,255,0.05) 1*/ /* Scrollbar variables */ - --color-scrollbar-thumb: #D1D5DB; - --color-scrollbar-thumb-hover: #A1A1AA; + --color-scrollbar-thumb: #d1d5db; + --color-scrollbar-thumb-hover: #a1a1aa; /* Tailwind semantic variables */ - --color-primary-foreground: #FFFFFF; - --color-muted: #9CA3AF; /* Similar to existing --color-text-subtle */ - --color-muted-foreground: #4B5563; /* Similar to existing --color-text-muted */ - --color-accent: #10B981; /* Green accent */ - --color-accent-foreground: #FFFFFF; + --color-primary-foreground: #ffffff; + --color-muted: #9ca3af; /* Similar to existing --color-text-subtle */ + --color-muted-foreground: #4b5563; /* Similar to existing --color-text-muted */ + --color-accent: #10b981; /* Green accent */ + --color-accent-foreground: #ffffff; --color-input: var(--color-border); /* Alias to border */ --color-ring: var(--color-primary); /* Alias to primary */ } -:root[data-theme='dark'] { - --theme-name: 'dark'; - --color-background: #18181B; - --color-foreground: #FFFFFF; - --color-primary: #2563EB; /* Tailwind's primary.dark */ - --color-secondary: #9CA3AF; /* Tailwind's secondary.dark */ +:root[data-theme="dark"] { + --theme-name: "dark"; + --color-background: #18181b; + --color-foreground: #ffffff; + --color-primary: #2563eb; /* Tailwind's primary.dark */ + --color-secondary: #9ca3af; /* Tailwind's secondary.dark */ --color-border: #374151; - --color-card: #27272A; + --color-card: #27272a; /* Specific variables based on existing CSS (dark theme) */ --color-text-muted: #a1a1aa; @@ -54,15 +58,44 @@ --color-scrollbar-thumb-hover: #52525b; /* Tailwind semantic variables */ - --color-primary-foreground: #FFFFFF; + --color-primary-foreground: #ffffff; --color-muted: #374151; /* Similar to existing html.dark --color-border */ - --color-muted-foreground: #9CA3AF; /* Similar to existing html.dark --color-secondary */ - --color-accent: #10B981; /* Matches existing html.dark --color-icon-accent */ - --color-accent-foreground: #FFFFFF; + --color-muted-foreground: #9ca3af; /* Similar to existing html.dark --color-secondary */ + --color-accent: #10b981; /* Matches existing html.dark --color-icon-accent */ + --color-accent-foreground: #ffffff; --color-input: var(--color-border); /* Alias to border */ --color-ring: var(--color-primary); /* Alias to primary */ } +@media (prefers-color-scheme: dark) { + :root:not([data-theme]) { + --theme-name: "dark"; + --color-background: #18181b; + --color-foreground: #ffffff; + --color-primary: #2563eb; /* Tailwind's primary.dark */ + --color-secondary: #9ca3af; /* Tailwind's secondary.dark */ + --color-border: #374151; + --color-card: #27272a; + + /* Specific variables based on existing CSS (dark theme) */ + --color-text-muted: #a1a1aa; + --color-card-item-bg: rgba(255, 255, 255, 0.03); + --color-card-item-hover-bg: rgba(255, 255, 255, 0.05); + + /* Scrollbar variables */ + --color-scrollbar-thumb: #3f3f46; + --color-scrollbar-thumb-hover: #52525b; + + /* Tailwind semantic variables */ + --color-primary-foreground: #ffffff; + --color-muted: #374151; /* Similar to existing html.dark --color-border */ + --color-muted-foreground: #9ca3af; /* Similar to existing html.dark --color-secondary */ + --color-accent: #10b981; /* Matches existing html.dark --color-icon-accent */ + --color-accent-foreground: #ffffff; + --color-input: var(--color-border); /* Alias to border */ + --color-ring: var(--color-primary); /* Alias to primary */ + } +} @layer utilities { .custom-scrollbar { scrollbar-width: thin; diff --git a/packages/ui/src/hooks/useDark.ts b/packages/ui/src/hooks/useDark.ts deleted file mode 100644 index bdadd30..0000000 --- a/packages/ui/src/hooks/useDark.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { $, isServer, QRL, Signal, useTask$, type ReadonlySignal, } from "@qwik.dev/core"; - -import { useSignal } from "@qwik.dev/core"; - - - -export type DarkModeSetting = 'light' | 'dark' | 'auto'; - -export interface UseDarkOptions { - selector?: string; - darkClassName?: string; - lightClassName?: string; - storageKey?: string; - initialValue?: DarkModeSetting; - onChanged?: QRL<(isDark: boolean, mode: DarkModeSetting, newMode?: DarkModeSetting) => void>; -} - -export interface UseDarkReturn { - isDark: Readonly>; - mode: Signal; - setMode: QRL<(newMode: DarkModeSetting) => void>; - toggleDark: QRL<() => void>; -} - -const DEFAULT_OPTIONS = { - selector: 'html', - darkClassName: 'dark', - lightClassName: 'light', - storageKey: 'qwik-theme-appearance', - initialValue: 'auto' as DarkModeSetting, -}; - -export function useDark(options?: UseDarkOptions): UseDarkReturn { - const resolvedOptions = { ...DEFAULT_OPTIONS, ...options }; - const { - selector, - darkClassName, - lightClassName, - storageKey, - initialValue, - onChanged, - } = resolvedOptions; - - const mode = useSignal(initialValue); - const isDark = useSignal(false); - - const updateDOMAndSignal = $((currentSetting: DarkModeSetting, systemPrefersDark: boolean) => { - let newIsDarkValue = false; - if (currentSetting === 'auto') { - newIsDarkValue = systemPrefersDark; - } else { - newIsDarkValue = currentSetting === 'dark'; - } - - const D = document; - const targetElement = D.querySelector(selector) || D.documentElement; - - if (isDark.value !== newIsDarkValue) { - isDark.value = newIsDarkValue; - } - - if (newIsDarkValue) { - targetElement.classList.add(darkClassName); - if (lightClassName) targetElement.classList.remove(lightClassName); - (targetElement as HTMLElement).style.setProperty('color-scheme', 'dark'); - } else { - targetElement.classList.remove(darkClassName); - if (lightClassName) targetElement.classList.add(lightClassName); - (targetElement as HTMLElement).style.setProperty('color-scheme', 'light'); - } - - if (onChanged) { - onChanged(isDark.value, currentSetting); - } - }); - - - const setMode = $((newMode: DarkModeSetting) => { - if (mode.value !== newMode) { - mode.value = newMode; - // The task below will handle localStorage and DOM update - } - }); - - const toggleDark = $(() => { - if (mode.value === 'auto') { - // If auto, switch to the opposite of current visual state - setMode(isDark.value ? 'light' : 'dark'); - } else { - // Toggle between light and dark - setMode(mode.value === 'light' ? 'dark' : 'light'); - } - }); - - useTask$(() => { - if (isServer) { - return; - } - - // 1. Initialize mode from localStorage if available - const storedMode = localStorage.getItem(storageKey) as DarkModeSetting | null; - if (storedMode && storedMode !== mode.value) { - mode.value = storedMode; // This will trigger the next task if value changes - } else if (!storedMode) { - // If nothing in storage, and initialValue is different from current mode, save it. - // This ensures the initialValue (e.g. 'auto') is stored if nothing was there. - localStorage.setItem(storageKey, mode.value); - } - }) - - // Ensures DOM is ready for querySelector - useTask$(({ cleanup, track }) => { - if (isServer) { - return; - } - - // 2. Media query for system preference - const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - - // Initial update based on current mode and system preference - updateDOMAndSignal(mode.value, mediaQuery.matches); - - - // 3. Watch for changes in mode signal (user-triggered or from localStorage init) - // This task is separate to ensure localStorage is updated *after* mode signal changes. - track(() => mode.value); // Track the mode signal - localStorage.setItem(storageKey, mode.value); - updateDOMAndSignal(mode.value, mediaQuery.matches); // Re-evaluate and update DOM - - - // 4. Listen to system preference changes - const onMediaChange = $(() => { - if (mode.value === 'auto') { // Only update if mode is 'auto' - updateDOMAndSignal('auto', window.matchMedia('(prefers-color-scheme: dark)').matches); - } - }); - - mediaQuery.addEventListener('change', onMediaChange); - - cleanup(() => { - mediaQuery.removeEventListener('change', onMediaChange); - }); - }); // Ensures DOM is ready for querySelector - - return { - isDark: isDark as ReadonlySignal, - mode, - setMode, - toggleDark, - }; -} \ No newline at end of file diff --git a/packages/ui/src/hooks/useDebouncer.ts b/packages/ui/src/hooks/useDebouncer.ts index 78aef60..9f28ad3 100644 --- a/packages/ui/src/hooks/useDebouncer.ts +++ b/packages/ui/src/hooks/useDebouncer.ts @@ -15,5 +15,3 @@ export const useDebouncer = ( }, delay); }); }; - - diff --git a/packages/ui/src/root.tsx b/packages/ui/src/root.tsx index dabfe17..09f86ff 100644 --- a/packages/ui/src/root.tsx +++ b/packages/ui/src/root.tsx @@ -1,4 +1,4 @@ -import { QwikDevtools } from './devtools'; +import { QwikDevtools } from "./devtools"; export default () => { return ( diff --git a/packages/ui/src/utils/location.ts b/packages/ui/src/utils/location.ts index b538036..5a1f466 100644 --- a/packages/ui/src/utils/location.ts +++ b/packages/ui/src/utils/location.ts @@ -1,9 +1,9 @@ -import { isBrowser } from '@qwik.dev/core'; +import { isBrowser } from "@qwik.dev/core"; export function getCurrentLocation() { - if (!isBrowser) return ''; + if (!isBrowser) return ""; - if (window.location.pathname === '/') return '/'; + if (window.location.pathname === "/") return "/"; return window.location.pathname.slice(0, -1); } diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index 00e39f3..6fd1a0f 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -1,26 +1,25 @@ /** @type {import('tailwindcss').Config} */ export default { - darkMode: 'class', - content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], + content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], theme: { extend: { colors: { - background: 'var(--color-background)', - foreground: 'var(--color-foreground)', - primary: 'var(--color-primary)', - 'primary-foreground': 'var(--color-primary-foreground)', // e.g., text on primary button 2 - secondary: 'var(--color-secondary)', // e.g., muted button background or text 2 - 'secondary-foreground': 'var(--color-secondary-foreground)', // 2 - muted: 'var(--color-muted)', // e.g., placeholder text or very subtle borders 2 - 'muted-foreground': 'var(--color-muted-foreground)', - accent: 'var(--color-accent)', // e.g., for highlights, icons, or active states - 'accent-foreground': 'var(--color-accent-foreground)', - border: 'var(--color-border)', // default border color - input: 'var(--color-input)', // specific for input borders if different from general border 2 - ring: 'var(--color-ring)', // for focus rings 2 - 'card-item-bg': 'var(--color-card-item-bg)', // 1 - 'card-item-hover-bg': 'var(--color-card-item-hover-bg)', // 1 - 'text-muted': 'var(--color-text-muted)', + background: "var(--color-background)", + foreground: "var(--color-foreground)", + primary: "var(--color-primary)", + "primary-foreground": "var(--color-primary-foreground)", // e.g., text on primary button 2 + secondary: "var(--color-secondary)", // e.g., muted button background or text 2 + "secondary-foreground": "var(--color-secondary-foreground)", // 2 + muted: "var(--color-muted)", // e.g., placeholder text or very subtle borders 2 + "muted-foreground": "var(--color-muted-foreground)", + accent: "var(--color-accent)", // e.g., for highlights, icons, or active states + "accent-foreground": "var(--color-accent-foreground)", + border: "var(--color-border)", // default border color + input: "var(--color-input)", // specific for input borders if different from general border 2 + ring: "var(--color-ring)", // for focus rings 2 + "card-item-bg": "var(--color-card-item-bg)", // 1 + "card-item-hover-bg": "var(--color-card-item-hover-bg)", // 1 + "text-muted": "var(--color-text-muted)", }, }, }, diff --git a/packages/ui/vite.config.mts b/packages/ui/vite.config.mts index 46b00c4..d041ce4 100644 --- a/packages/ui/vite.config.mts +++ b/packages/ui/vite.config.mts @@ -3,21 +3,23 @@ import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; import pkg from "./package.json"; import { qwikReact } from "@qwik.dev/react/vite"; -import { qwikDevtools } from '@devtools/plugin'; +import { qwikDevtools } from "@devtools/plugin"; import { createRequire } from "module"; const { dependencies = {}, peerDependencies = {} } = pkg as any; const makeRegex = (dep) => new RegExp(`^${dep}(/.*)?$`); const excludeAll = (obj) => Object.keys(obj).map(makeRegex); const require = createRequire(import.meta.url); -const isBuild = process.argv.includes('lib') +const isBuild = process.argv.includes("lib"); export default defineConfig(() => { return { resolve: { - alias: isBuild ? undefined : { - '@devtools/ui': require.resolve('.'), - '@qwik.dev/devtools/ui': require.resolve('.') - } + alias: isBuild + ? undefined + : { + "@devtools/ui": require.resolve("."), + "@qwik.dev/devtools/ui": require.resolve("."), + }, }, build: { target: "es2020", From f11cc88184331172272effbde319025eefe90ad3 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Thu, 29 May 2025 13:30:24 +0800 Subject: [PATCH 09/30] refactor(theme): simplify theme handling and remove unused code - Remove ThemeScript component and inline theme script logic in devtools - Remove unused useDark hook from ThemeToggle - Simplify theme toggle logic by removing dark state check --- packages/ui/src/components/ThemeToggle/ThemeToggle.tsx | 5 ++--- .../ui/src/components/router-head/theme-script.tsx | 10 ---------- packages/ui/src/devtools.tsx | 5 +++-- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx index c6e5b80..cbe689a 100644 --- a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx +++ b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx @@ -6,7 +6,6 @@ import { event$, } from "@qwik.dev/core"; import { HiMoonMini, HiSunMini } from "@qwikest/icons/heroicons"; -import { useDark } from "../../hooks/useDark"; import { themeStorageKey } from "../router-head/theme-script"; type ThemeName = "dark" | "light" | undefined; @@ -57,9 +56,9 @@ export const setTheme = (theme: ThemeName) => { }; export const ThemeToggle = component$(() => { - const dark = useDark(); const onClick$ = event$(() => { const currentTheme = getTheme(); + setTheme(currentTheme === "dark" ? "light" : "dark"); }); return ( @@ -67,7 +66,7 @@ export const ThemeToggle = component$(() => { onClick$={onClick$} class="hover:bg-accent/10 flex h-8 w-8 items-center justify-center rounded-md bg-background text-foreground" > - {dark.isDark.value ? ( + {true ? ( ) : ( diff --git a/packages/ui/src/components/router-head/theme-script.tsx b/packages/ui/src/components/router-head/theme-script.tsx index 54e510a..815d401 100644 --- a/packages/ui/src/components/router-head/theme-script.tsx +++ b/packages/ui/src/components/router-head/theme-script.tsx @@ -1,11 +1 @@ export const themeStorageKey = "theme-preference"; -export const ThemeScript = () => { - const themeScript = ` - try { - const p = localStorage.getItem('${themeStorageKey}'); - if (p) { - document.documentElement.setAttribute('data-theme', p); - } - } catch (e) { }`.replace(/\s+/g, ""); - return themeScript; -}; diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index 280d167..8db95c0 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -64,8 +64,9 @@ export const QwikDevtools = component$(() => { "DOMContentLoaded", sync$(() => { const scriptElement = document.createElement("script"); - scriptElement.innerHTML = ThemeScript(); - document.head.prepend(scriptElement); + scriptElement.innerHTML = `try {const p = localStorage.getItem('theme-preference');if (p) { document.documentElement.setAttribute('data-theme', p); }} catch (e) { }`.replace(/\s+/g, ""); + + document.head.appendChild(scriptElement); }), ); // eslint-disable-next-line qwik/no-use-visible-task From 6943d10b3400e503c924295d3f7ecd0376d29326 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Tue, 3 Jun 2025 13:21:26 +0800 Subject: [PATCH 10/30] fix(devtools): remove unused ThemeScript import and fix panel visibility condition - Remove unused ThemeScript import to clean up dependencies - Fix devtools panel visibility to only show when state.isOpen.value is true --- packages/ui/src/devtools.tsx | 3 +-- packages/ui/src/hooks/useDebouncer.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index 8db95c0..d3d05c9 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -41,7 +41,6 @@ import { Packages } from "./features/Packages/Packages"; import { Components } from "./features/Components/Components"; import { Inspect } from "./features/inspect/Inspect"; import { ThemeToggle } from "./components/ThemeToggle/ThemeToggle"; -import { ThemeScript } from "./components/router-head/theme-script"; function getClientRpcFunctions() { return { healthCheck: () => true, @@ -123,7 +122,7 @@ export const QwikDevtools = component$(() => { - {true && ( + {state.isOpen.value && (
diff --git a/packages/ui/src/hooks/useDebouncer.ts b/packages/ui/src/hooks/useDebouncer.ts index 9f28ad3..e99eaa7 100644 --- a/packages/ui/src/hooks/useDebouncer.ts +++ b/packages/ui/src/hooks/useDebouncer.ts @@ -14,4 +14,4 @@ export const useDebouncer = ( fn(...args); }, delay); }); -}; +}; \ No newline at end of file From 177a8bea87fc06eb86b70517fcf24176d6598754 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Tue, 3 Jun 2025 14:05:28 +0800 Subject: [PATCH 11/30] style: enforce single quotes in codebase and update prettier config Update all double quotes to single quotes across the codebase for consistency. Added 'singleQuote: true' to prettier configuration to enforce this style. This change improves code style consistency and aligns with the project's linting rules. --- packages/ui/.eslintrc.cjs | 44 +++++----- packages/ui/.prettierrc.js | 3 +- .../DevtoolsButton/DevtoolsButton.tsx | 28 +++---- .../DevtoolsContainer/DevtoolsContainer.tsx | 2 +- .../DevtoolsPanel/DevtoolsPanel.tsx | 16 ++-- packages/ui/src/components/Tab/Tab.tsx | 10 +-- .../src/components/TabContent/TabContent.tsx | 2 +- .../ui/src/components/TabTitle/TabTitle.tsx | 2 +- .../components/ThemeToggle/ThemeToggle.tsx | 32 ++++---- .../components/router-head/theme-script.tsx | 2 +- packages/ui/src/devtools.tsx | 82 ++++++++++--------- packages/ui/src/entry.dev.tsx | 4 +- packages/ui/src/entry.ssr.tsx | 6 +- packages/ui/src/features/Assets/Assets.tsx | 8 +- .../ui/src/features/Components/Components.tsx | 24 +++--- .../features/Components/components/Tree.tsx | 14 ++-- .../ui/src/features/Components/styles.css | 2 +- .../ui/src/features/Overview/Overview.tsx | 8 +- .../ui/src/features/Packages/Packages.tsx | 14 ++-- .../InstallButton/InstallButton.tsx | 18 ++-- packages/ui/src/features/Routes/Routes.tsx | 22 ++--- packages/ui/src/features/inspect/Inspect.tsx | 8 +- packages/ui/src/features/inspect/constant.ts | 2 +- packages/ui/src/global.css | 8 +- packages/ui/src/hooks/useDebouncer.ts | 6 +- packages/ui/src/index.ts | 2 +- packages/ui/src/root.tsx | 2 +- packages/ui/src/types/state.ts | 18 ++-- packages/ui/src/utils/location.ts | 6 +- packages/ui/tailwind.config.js | 34 ++++---- packages/ui/vite.config.mts | 34 ++++---- 31 files changed, 232 insertions(+), 231 deletions(-) diff --git a/packages/ui/.eslintrc.cjs b/packages/ui/.eslintrc.cjs index 8fde82a..22f1041 100644 --- a/packages/ui/.eslintrc.cjs +++ b/packages/ui/.eslintrc.cjs @@ -6,36 +6,36 @@ module.exports = { node: true, }, extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:qwik/recommended", + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:qwik/recommended', ], - parser: "@typescript-eslint/parser", + parser: '@typescript-eslint/parser', parserOptions: { tsconfigRootDir: __dirname, - project: ["./tsconfig.json"], + project: ['./tsconfig.json'], ecmaVersion: 2021, - sourceType: "module", + sourceType: 'module', ecmaFeatures: { jsx: true, }, }, - plugins: ["@typescript-eslint"], + plugins: ['@typescript-eslint'], rules: { - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-empty-interface": "off", - "@typescript-eslint/no-namespace": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-this-alias": "off", - "@typescript-eslint/ban-types": "off", - "@typescript-eslint/ban-ts-comment": "off", - "prefer-spread": "off", - "no-case-declarations": "off", - "no-console": "off", - "@typescript-eslint/no-unused-vars": ["error"], - "no-var": "off", + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-empty-interface': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-this-alias': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + 'prefer-spread': 'off', + 'no-case-declarations': 'off', + 'no-console': 'off', + '@typescript-eslint/no-unused-vars': ['error'], + 'no-var': 'off', }, }; diff --git a/packages/ui/.prettierrc.js b/packages/ui/.prettierrc.js index 7b5b93e..c4d914f 100644 --- a/packages/ui/.prettierrc.js +++ b/packages/ui/.prettierrc.js @@ -1,3 +1,4 @@ export default { - plugins: ["prettier-plugin-tailwindcss"], + plugins: ['prettier-plugin-tailwindcss'], + singleQuote: true, }; diff --git a/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx b/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx index 4b231f2..47aafbb 100644 --- a/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx +++ b/packages/ui/src/components/DevtoolsButton/DevtoolsButton.tsx @@ -1,5 +1,5 @@ -import { component$, useSignal, $, useTask$ } from "@qwik.dev/core"; -import type { State } from "../../types/state"; // Assuming State type is defined elsewhere +import { component$, useSignal, $, useTask$ } from '@qwik.dev/core'; +import type { State } from '../../types/state'; // Assuming State type is defined elsewhere interface DevtoolsButtonProps { state: State; @@ -74,12 +74,12 @@ export const DevtoolsButton = component$(({ state }: DevtoolsButtonProps) => { // Effect to add/remove window event listeners based on dragging state useTask$(({ track, cleanup }) => { track(() => isDragging.value); - if (isDragging.value && typeof window !== "undefined") { - window.addEventListener("mousemove", handleMouseMove); - window.addEventListener("mouseup", handleMouseUp); + if (isDragging.value && typeof window !== 'undefined') { + window.addEventListener('mousemove', handleMouseMove); + window.addEventListener('mouseup', handleMouseUp); cleanup(() => { - window.removeEventListener("mousemove", handleMouseMove); - window.removeEventListener("mouseup", handleMouseUp); + window.removeEventListener('mousemove', handleMouseMove); + window.removeEventListener('mouseup', handleMouseUp); }); } }); @@ -88,19 +88,19 @@ export const DevtoolsButton = component$(({ state }: DevtoolsButtonProps) => {
diff --git a/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx b/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx index 3d2f093..4f930a2 100644 --- a/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx +++ b/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx @@ -1,4 +1,4 @@ -import { component$, Slot } from "@qwik.dev/core"; +import { component$, Slot } from '@qwik.dev/core'; export const DevtoolsContainer = component$(() => { return ( diff --git a/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx b/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx index dc559dc..4f86cc3 100644 --- a/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx +++ b/packages/ui/src/components/DevtoolsPanel/DevtoolsPanel.tsx @@ -4,8 +4,8 @@ import { useSignal, useTask$, isBrowser, -} from "@qwik.dev/core"; -import { State } from "../../types/state"; +} from '@qwik.dev/core'; +import { State } from '../../types/state'; interface DevtoolsPanelProps { state: State; @@ -16,11 +16,11 @@ export const DevtoolsPanel = component$(({ state }: DevtoolsPanelProps) => { useTask$(({ cleanup }) => { const handleKeyPress = (e: KeyboardEvent) => { - if (e.key === "`" && e.metaKey) { + if (e.key === '`' && e.metaKey) { state.isOpen.value = !state.isOpen.value; } // Add Escape key to close - if (e.key === "Escape" && state.isOpen.value) { + if (e.key === 'Escape' && state.isOpen.value) { state.isOpen.value = false; } }; @@ -36,12 +36,12 @@ export const DevtoolsPanel = component$(({ state }: DevtoolsPanelProps) => { } }; if (!isBrowser) return; - window.addEventListener("keydown", handleKeyPress); - window.addEventListener("mousedown", handleClickOutside); + window.addEventListener('keydown', handleKeyPress); + window.addEventListener('mousedown', handleClickOutside); cleanup(() => { - window.removeEventListener("keydown", handleKeyPress); - window.removeEventListener("mousedown", handleClickOutside); + window.removeEventListener('keydown', handleKeyPress); + window.removeEventListener('mousedown', handleClickOutside); }); }); diff --git a/packages/ui/src/components/Tab/Tab.tsx b/packages/ui/src/components/Tab/Tab.tsx index a0c993a..d5c55ee 100644 --- a/packages/ui/src/components/Tab/Tab.tsx +++ b/packages/ui/src/components/Tab/Tab.tsx @@ -1,5 +1,5 @@ -import { component$, Slot } from "@qwik.dev/core"; -import { State, TabName } from "../../types/state"; +import { component$, Slot } from '@qwik.dev/core'; +import { State, TabName } from '../../types/state'; interface TabProps { state: State; @@ -13,11 +13,11 @@ export const Tab = component$(({ state, id, title }) => { onClick$={() => (state.activeTab = id)} title={title} class={{ - "flex h-10 w-10 items-center justify-center rounded-lg p-2.5 transition-all duration-200": + 'flex h-10 w-10 items-center justify-center rounded-lg p-2.5 transition-all duration-200': true, - "bg-foreground/5 hover:bg-foreground/10 text-muted-foreground hover:text-foreground": + 'bg-foreground/5 hover:bg-foreground/10 text-muted-foreground hover:text-foreground': state.activeTab !== id, - "shadow-accent/35 bg-accent text-accent-foreground shadow-lg": + 'shadow-accent/35 bg-accent text-accent-foreground shadow-lg': state.activeTab === id, }} > diff --git a/packages/ui/src/components/TabContent/TabContent.tsx b/packages/ui/src/components/TabContent/TabContent.tsx index 6c234f8..32fe82d 100644 --- a/packages/ui/src/components/TabContent/TabContent.tsx +++ b/packages/ui/src/components/TabContent/TabContent.tsx @@ -1,4 +1,4 @@ -import { component$, Slot } from "@qwik.dev/core"; +import { component$, Slot } from '@qwik.dev/core'; export const TabContent = component$(() => { return ( diff --git a/packages/ui/src/components/TabTitle/TabTitle.tsx b/packages/ui/src/components/TabTitle/TabTitle.tsx index 86432b9..5bef3b5 100644 --- a/packages/ui/src/components/TabTitle/TabTitle.tsx +++ b/packages/ui/src/components/TabTitle/TabTitle.tsx @@ -1,4 +1,4 @@ -import { component$ } from "@qwik.dev/core"; +import { component$ } from '@qwik.dev/core'; interface TabTitleProps { title: string; diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx index cbe689a..5f1f010 100644 --- a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx +++ b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx @@ -4,11 +4,11 @@ import { isBrowser, Signal, event$, -} from "@qwik.dev/core"; -import { HiMoonMini, HiSunMini } from "@qwikest/icons/heroicons"; -import { themeStorageKey } from "../router-head/theme-script"; +} from '@qwik.dev/core'; +import { HiMoonMini, HiSunMini } from '@qwikest/icons/heroicons'; +import { themeStorageKey } from '../router-head/theme-script'; -type ThemeName = "dark" | "light" | undefined; +type ThemeName = 'dark' | 'light' | undefined; export const getTheme = (): ThemeName => { let theme; @@ -20,22 +20,22 @@ export const getTheme = (): ThemeName => { if (theme) { return theme as ThemeName; } else { - return window.matchMedia("(prefers-color-scheme: dark)").matches - ? "dark" - : "light"; + return window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light'; } }; let currentThemeSignal: Signal; export const getThemeSignal = () => { if (!isBrowser) { - throw new Error("getThemeSignal is only available in the browser"); + throw new Error('getThemeSignal is only available in the browser'); } if (!currentThemeSignal) { currentThemeSignal = createSignal(getTheme()); window - .matchMedia("(prefers-color-scheme: dark)") - .addEventListener("change", () => { + .matchMedia('(prefers-color-scheme: dark)') + .addEventListener('change', () => { currentThemeSignal.value = getTheme(); }); } @@ -49,7 +49,7 @@ export const setTheme = (theme: ThemeName) => { } else { localStorage.setItem(themeStorageKey, theme); } - document.firstElementChild?.setAttribute("data-theme", theme!); + document.firstElementChild?.setAttribute('data-theme', theme!); if (currentThemeSignal) { currentThemeSignal.value = theme; } @@ -58,19 +58,15 @@ export const setTheme = (theme: ThemeName) => { export const ThemeToggle = component$(() => { const onClick$ = event$(() => { const currentTheme = getTheme(); - - setTheme(currentTheme === "dark" ? "light" : "dark"); + + setTheme(currentTheme === 'dark' ? 'light' : 'dark'); }); return ( ); }); diff --git a/packages/ui/src/components/router-head/theme-script.tsx b/packages/ui/src/components/router-head/theme-script.tsx index 815d401..2e3e518 100644 --- a/packages/ui/src/components/router-head/theme-script.tsx +++ b/packages/ui/src/components/router-head/theme-script.tsx @@ -1 +1 @@ -export const themeStorageKey = "theme-preference"; +export const themeStorageKey = 'theme-preference'; diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index d3d05c9..cff728c 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -8,16 +8,16 @@ import { isBrowser, useOnDocument, sync$, -} from "@qwik.dev/core"; -import { tryCreateHotContext } from "vite-hot-client"; +} from '@qwik.dev/core'; +import { tryCreateHotContext } from 'vite-hot-client'; import { HiBoltOutline, HiCubeOutline, HiPhotoOutline, HiCodeBracketMini, HiMegaphoneMini, -} from "@qwikest/icons/heroicons"; -import { LuFolderTree } from "@qwikest/icons/lucide"; +} from '@qwikest/icons/heroicons'; +import { LuFolderTree } from '@qwikest/icons/lucide'; import { createClientRpc, getViteClientRpc, @@ -25,22 +25,22 @@ import { type NpmInfo, type RoutesInfo, RouteType, -} from "@devtools/kit"; -import globalCss from "./global.css?inline"; -import { Tab } from "./components/Tab/Tab"; -import { TabContent } from "./components/TabContent/TabContent"; -import { Overview } from "./features/Overview/Overview"; -import { State } from "./types/state"; -import { Assets } from "./features/Assets/Assets"; -import { Routes } from "./features/Routes/Routes"; -import { TabTitle } from "./components/TabTitle/TabTitle"; -import { DevtoolsButton } from "./components/DevtoolsButton/DevtoolsButton"; -import { DevtoolsContainer } from "./components/DevtoolsContainer/DevtoolsContainer"; -import { DevtoolsPanel } from "./components/DevtoolsPanel/DevtoolsPanel"; -import { Packages } from "./features/Packages/Packages"; -import { Components } from "./features/Components/Components"; -import { Inspect } from "./features/inspect/Inspect"; -import { ThemeToggle } from "./components/ThemeToggle/ThemeToggle"; +} from '@devtools/kit'; +import globalCss from './global.css?inline'; +import { Tab } from './components/Tab/Tab'; +import { TabContent } from './components/TabContent/TabContent'; +import { Overview } from './features/Overview/Overview'; +import { State } from './types/state'; +import { Assets } from './features/Assets/Assets'; +import { Routes } from './features/Routes/Routes'; +import { TabTitle } from './components/TabTitle/TabTitle'; +import { DevtoolsButton } from './components/DevtoolsButton/DevtoolsButton'; +import { DevtoolsContainer } from './components/DevtoolsContainer/DevtoolsContainer'; +import { DevtoolsPanel } from './components/DevtoolsPanel/DevtoolsPanel'; +import { Packages } from './features/Packages/Packages'; +import { Components } from './features/Components/Components'; +import { Inspect } from './features/inspect/Inspect'; +import { ThemeToggle } from './components/ThemeToggle/ThemeToggle'; function getClientRpcFunctions() { return { healthCheck: () => true, @@ -52,7 +52,7 @@ export const QwikDevtools = component$(() => { const state = useStore({ isOpen: useSignal(false), - activeTab: "overview", + activeTab: 'overview', npmPackages: [], assets: [], components: [], @@ -60,21 +60,25 @@ export const QwikDevtools = component$(() => { }); useOnDocument( - "DOMContentLoaded", + 'DOMContentLoaded', sync$(() => { - const scriptElement = document.createElement("script"); - scriptElement.innerHTML = `try {const p = localStorage.getItem('theme-preference');if (p) { document.documentElement.setAttribute('data-theme', p); }} catch (e) { }`.replace(/\s+/g, ""); - + const scriptElement = document.createElement('script'); + scriptElement.innerHTML = + `try {const p = localStorage.getItem('theme-preference');if (p) { document.documentElement.setAttribute('data-theme', p); }} catch (e) { }`.replace( + /\s+/g, + '', + ); + document.head.appendChild(scriptElement); }), ); // eslint-disable-next-line qwik/no-use-visible-task useTask$(async ({ track }) => { if (isBrowser) { - const hot = await tryCreateHotContext(undefined, ["/"]); + const hot = await tryCreateHotContext(undefined, ['/']); if (!hot) { - throw new Error("Vite Hot Context not connected"); + throw new Error('Vite Hot Context not connected'); } setViteClientContext(hot); @@ -92,15 +96,15 @@ export const QwikDevtools = component$(() => { rpc.getRoutes().then((data: RoutesInfo) => { const children: RoutesInfo[] = data.children || []; const directories: RoutesInfo[] = children.filter( - (child) => child.type === "directory", + (child) => child.type === 'directory', ); const values: RoutesInfo[] = [ { - relativePath: "", - name: "index", + relativePath: '', + name: 'index', type: RouteType.DIRECTORY, - path: "", + path: '', isSymbolicLink: false, children: undefined, }, @@ -150,7 +154,7 @@ export const QwikDevtools = component$(() => {
- {state.activeTab === "overview" && ( + {state.activeTab === 'overview' && (
{ )} - {state.activeTab === "assets" && ( + {state.activeTab === 'assets' && (
- Total Size:{" "} + Total Size:{' '} {( state.assets?.reduce( (acc, asset) => acc + asset.size, 0, ) / 1024 - ).toFixed(2)}{" "} + ).toFixed(2)}{' '} KB Count: {state.assets?.length || 0} @@ -185,25 +189,25 @@ export const QwikDevtools = component$(() => { )} - {state.activeTab === "packages" && ( + {state.activeTab === 'packages' && ( )} - {state.activeTab === "routes" && ( + {state.activeTab === 'routes' && ( )} - {state.activeTab === "components" && ( + {state.activeTab === 'components' && ( )} - {state.activeTab === "inspect" && ( + {state.activeTab === 'inspect' && ( diff --git a/packages/ui/src/entry.dev.tsx b/packages/ui/src/entry.dev.tsx index dba2a86..6efcd87 100644 --- a/packages/ui/src/entry.dev.tsx +++ b/packages/ui/src/entry.dev.tsx @@ -9,8 +9,8 @@ * - More code is transferred to the browser than in SSR mode. * - Optimizer/Serialization/Deserialization code is not exercised! */ -import { render, type RenderOptions } from "@qwik.dev/core"; -import Root from "./root"; +import { render, type RenderOptions } from '@qwik.dev/core'; +import Root from './root'; export default function (opts: RenderOptions) { return render(document, , opts); diff --git a/packages/ui/src/entry.ssr.tsx b/packages/ui/src/entry.ssr.tsx index 577ed8b..539ba32 100644 --- a/packages/ui/src/entry.ssr.tsx +++ b/packages/ui/src/entry.ssr.tsx @@ -10,12 +10,12 @@ * - npm run build * */ -import { manifest } from "@qwik-client-manifest"; +import { manifest } from '@qwik-client-manifest'; import { renderToStream, type RenderToStreamOptions, -} from "@qwik.dev/core/server"; -import Root from "./root"; +} from '@qwik.dev/core/server'; +import Root from './root'; export default function (opts: RenderToStreamOptions) { return renderToStream(, { diff --git a/packages/ui/src/features/Assets/Assets.tsx b/packages/ui/src/features/Assets/Assets.tsx index b8d0710..b33c8ea 100644 --- a/packages/ui/src/features/Assets/Assets.tsx +++ b/packages/ui/src/features/Assets/Assets.tsx @@ -1,5 +1,5 @@ -import { component$ } from "@qwik.dev/core"; -import { State } from "../../types/state"; +import { component$ } from '@qwik.dev/core'; +import { State } from '../../types/state'; interface AssetsProps { state: State; @@ -10,7 +10,7 @@ export const Assets = component$(({ state }: AssetsProps) => {
{state.assets?.map((asset) => { const isImage = asset.path.match(/\.(jpg|jpeg|png|gif|svg|webp)$/i); - const fileExt = asset.path.split(".").pop()?.toUpperCase(); + const fileExt = asset.path.split('.').pop()?.toUpperCase(); return (
{ )}
- {asset.path.split("/").pop()} + {asset.path.split('/').pop()}
{(asset.size / 1024).toFixed(2)} KB diff --git a/packages/ui/src/features/Components/Components.tsx b/packages/ui/src/features/Components/Components.tsx index ca2a8f3..b091f57 100644 --- a/packages/ui/src/features/Components/Components.tsx +++ b/packages/ui/src/features/Components/Components.tsx @@ -1,11 +1,11 @@ -import { $, component$, useSignal, useStyles$ } from "@qwik.dev/core"; -import { QGreetings } from "./components/Tree"; -import reactTreeCss from "react-complex-tree/lib/style-modern.css?inline"; -import styles from "./styles.css?inline"; +import { $, component$, useSignal, useStyles$ } from '@qwik.dev/core'; +import { QGreetings } from './components/Tree'; +import reactTreeCss from 'react-complex-tree/lib/style-modern.css?inline'; +import styles from './styles.css?inline'; export interface ComponentStateStore { [key: string]: { - type: "signal" | "store"; + type: 'signal' | 'store'; value: any; }; } @@ -75,20 +75,20 @@ const ComponentStoreUpdate = component$<{ return (
{Object.keys(value).map((key) => { - if (value[key].type === "signal") { + if (value[key].type === 'signal') { return (

Signal: {key}

); } - if (value[key].type === "store") { + if (value[key].type === 'store') { return (

Store: {key}

@@ -98,14 +98,14 @@ const ComponentStoreUpdate = component$<{ { value[key].value[storeKey] = - typeof value[key].value[storeKey] === "string" + typeof value[key].value[storeKey] === 'string' ? e.value : Number(e.value); }} diff --git a/packages/ui/src/features/Components/components/Tree.tsx b/packages/ui/src/features/Components/components/Tree.tsx index 7a96ffe..c99d7e8 100644 --- a/packages/ui/src/features/Components/components/Tree.tsx +++ b/packages/ui/src/features/Components/components/Tree.tsx @@ -1,11 +1,11 @@ /** @jsxImportSource react */ //@ts-nocheck -import { qwikify$ } from "@qwik.dev/react"; +import { qwikify$ } from '@qwik.dev/react'; import { UncontrolledTreeEnvironment, Tree, StaticTreeDataProvider, -} from "react-complex-tree"; +} from 'react-complex-tree'; const readTemplate = (template: any, data: any = { items: {} }) => { for (const [key, value] of Object.entries(template)) { @@ -27,9 +27,9 @@ const readTemplate = (template: any, data: any = { items: {} }) => { const longTree = { root: { - "": { - "": null, - "": null, + '': { + '': null, + '': null, }, }, }; @@ -53,7 +53,7 @@ function Greetings() { canDropOnFolder={false} canDropOnNonFolder={false} viewState={{ - "tree-1": { + 'tree-1': { expandedItems: [], }, }} @@ -64,4 +64,4 @@ function Greetings() { } // Convert React component to Qwik component -export const QGreetings = qwikify$(Greetings, { eagerness: "load" }); +export const QGreetings = qwikify$(Greetings, { eagerness: 'load' }); diff --git a/packages/ui/src/features/Components/styles.css b/packages/ui/src/features/Components/styles.css index 188bf7b..d1d6e4c 100644 --- a/packages/ui/src/features/Components/styles.css +++ b/packages/ui/src/features/Components/styles.css @@ -45,7 +45,7 @@ color: rgb(16 185 129 / var(--tw-bg-opacity, 1)) !important; } -.rct-tree-item-button[aria-expanded="true"] { +.rct-tree-item-button[aria-expanded='true'] { color: #fff !important; } diff --git a/packages/ui/src/features/Overview/Overview.tsx b/packages/ui/src/features/Overview/Overview.tsx index a5a01a4..ee42d7b 100644 --- a/packages/ui/src/features/Overview/Overview.tsx +++ b/packages/ui/src/features/Overview/Overview.tsx @@ -1,7 +1,7 @@ -import { component$ } from "@qwik.dev/core"; -import { HiCubeOutline, HiPhotoOutline } from "@qwikest/icons/heroicons"; -import { LuFolderTree } from "@qwikest/icons/lucide"; -import { State } from "../../types/state"; +import { component$ } from '@qwik.dev/core'; +import { HiCubeOutline, HiPhotoOutline } from '@qwikest/icons/heroicons'; +import { LuFolderTree } from '@qwikest/icons/lucide'; +import { State } from '../../types/state'; interface OverviewProps { state: State; diff --git a/packages/ui/src/features/Packages/Packages.tsx b/packages/ui/src/features/Packages/Packages.tsx index d374e4c..31af62b 100644 --- a/packages/ui/src/features/Packages/Packages.tsx +++ b/packages/ui/src/features/Packages/Packages.tsx @@ -4,13 +4,13 @@ import { Resource, useResource$, useSignal, -} from "@qwik.dev/core"; -import { useDebouncer } from "../../hooks/useDebouncer"; -import { Package } from "./types"; -import { InstallButton } from "./components/InstallButton/InstallButton"; +} from '@qwik.dev/core'; +import { useDebouncer } from '../../hooks/useDebouncer'; +import { Package } from './types'; +import { InstallButton } from './components/InstallButton/InstallButton'; export const Packages = component$(() => { - const debouncedQuery = useSignal(""); + const debouncedQuery = useSignal(''); const installingPackage = useSignal(null); const debounceSearch = useDebouncer( @@ -34,7 +34,7 @@ export const Packages = component$(() => { const packages: Package[] = data.objects.map((obj: any) => ({ name: obj.package.name, version: obj.package.version, - description: obj.package.description || "No description available", + description: obj.package.description || 'No description available', })); return packages; }); @@ -61,7 +61,7 @@ export const Packages = component$(() => { )} onRejected={(error) => (
- {error.message || "Failed to fetch packages"} + {error.message || 'Failed to fetch packages'}
)} onResolved={(packages) => { diff --git a/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx b/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx index 7c93d5d..bf972e1 100644 --- a/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx +++ b/packages/ui/src/features/Packages/components/InstallButton/InstallButton.tsx @@ -1,6 +1,6 @@ -import { getViteClientRpc } from "@devtools/kit"; -import { component$, Signal } from "@qwik.dev/core"; -import { Package } from "../../types"; +import { getViteClientRpc } from '@devtools/kit'; +import { component$, Signal } from '@qwik.dev/core'; +import { Package } from '../../types'; export const InstallButton = component$( ({ @@ -17,16 +17,16 @@ export const InstallButton = component$( const rpc = getViteClientRpc(); const result = await rpc.installPackage(pkg.name); if (!result.success) { - return Promise.reject(result.error || "Installation failed"); + return Promise.reject(result.error || 'Installation failed'); } }} disabled={installingPackage.value === pkg.name} class={[ - "rounded-full px-2 py-1 text-xs", + 'rounded-full px-2 py-1 text-xs', installingPackage.value === pkg.name - ? "bg-primary/5 text-primary/50 cursor-not-allowed" - : "bg-primary/10 hover:bg-primary/20 text-primary", - ].join(" ")} + ? 'bg-primary/5 text-primary/50 cursor-not-allowed' + : 'bg-primary/10 hover:bg-primary/20 text-primary', + ].join(' ')} > {installingPackage.value === pkg.name ? (
@@ -34,7 +34,7 @@ export const InstallButton = component$( Installing...
) : ( - "Install" + 'Install' )} ); diff --git a/packages/ui/src/features/Routes/Routes.tsx b/packages/ui/src/features/Routes/Routes.tsx index 34ca030..c33b5b6 100644 --- a/packages/ui/src/features/Routes/Routes.tsx +++ b/packages/ui/src/features/Routes/Routes.tsx @@ -1,5 +1,5 @@ -import { component$ } from "@qwik.dev/core"; -import { State } from "../../types/state"; +import { component$ } from '@qwik.dev/core'; +import { State } from '../../types/state'; interface RoutesProps { state: State; @@ -17,9 +17,9 @@ export const Routes = component$(({ state }: RoutesProps) => { {state.routes?.map((route, i) => { const children = route.children || []; const layout = - route.relativePath !== "" && - route.type === "directory" && - children.find((child) => child.name.startsWith("layout")); + route.relativePath !== '' && + route.type === 'directory' && + children.find((child) => child.name.startsWith('layout')); return (
{
- {route.relativePath === "" ? "/" : `/${route.relativePath}/`} + {route.relativePath === '' ? '/' : `/${route.relativePath}/`}
{route.name}
@@ -42,11 +42,11 @@ export const Routes = component$(({ state }: RoutesProps) => {
0, - "text-muted-foreground": !layout || i === 0, + 'text-accent': layout && i > 0, + 'text-muted-foreground': !layout || i === 0, }} > - {layout && i > 0 ? `${route.relativePath}/layout` : "default"} + {layout && i > 0 ? `${route.relativePath}/layout` : 'default'}
diff --git a/packages/ui/src/features/inspect/Inspect.tsx b/packages/ui/src/features/inspect/Inspect.tsx index b9f3412..5ba4d2a 100644 --- a/packages/ui/src/features/inspect/Inspect.tsx +++ b/packages/ui/src/features/inspect/Inspect.tsx @@ -1,6 +1,6 @@ -import { component$ } from "@qwik.dev/core"; +import { component$ } from '@qwik.dev/core'; // import { State } from "../../types/state"; -import { inspectorLink } from "./constant"; +import { inspectorLink } from './constant'; // interface RoutesProps { // state: State; // } @@ -11,8 +11,8 @@ export const Inspect = component$(() => {
diff --git a/packages/ui/src/features/inspect/constant.ts b/packages/ui/src/features/inspect/constant.ts index f7157c5..cfda629 100644 --- a/packages/ui/src/features/inspect/constant.ts +++ b/packages/ui/src/features/inspect/constant.ts @@ -1 +1 @@ -export const inspectorLink = "__inspect/"; +export const inspectorLink = '__inspect/'; diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index c05b860..cdafb6e 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -6,7 +6,7 @@ @tailwind components; @tailwind utilities; :root { - --theme-name: "light"; + --theme-name: 'light'; --color-background: #ffffff; --color-foreground: #000000; --color-primary: #3b82f6; @@ -39,8 +39,8 @@ --color-ring: var(--color-primary); /* Alias to primary */ } -:root[data-theme="dark"] { - --theme-name: "dark"; +:root[data-theme='dark'] { + --theme-name: 'dark'; --color-background: #18181b; --color-foreground: #ffffff; --color-primary: #2563eb; /* Tailwind's primary.dark */ @@ -69,7 +69,7 @@ @media (prefers-color-scheme: dark) { :root:not([data-theme]) { - --theme-name: "dark"; + --theme-name: 'dark'; --color-background: #18181b; --color-foreground: #ffffff; --color-primary: #2563eb; /* Tailwind's primary.dark */ diff --git a/packages/ui/src/hooks/useDebouncer.ts b/packages/ui/src/hooks/useDebouncer.ts index e99eaa7..e4adaa7 100644 --- a/packages/ui/src/hooks/useDebouncer.ts +++ b/packages/ui/src/hooks/useDebouncer.ts @@ -1,6 +1,6 @@ -import { $, QRL } from "@qwik.dev/core"; +import { $, QRL } from '@qwik.dev/core'; -import { useSignal } from "@qwik.dev/core"; +import { useSignal } from '@qwik.dev/core'; export const useDebouncer = ( fn: QRL<(...args: [...A]) => R>, @@ -14,4 +14,4 @@ export const useDebouncer = ( fn(...args); }, delay); }); -}; \ No newline at end of file +}; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index c39c6bd..e700c2e 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -1 +1 @@ -export { QwikDevtools } from "./devtools"; +export { QwikDevtools } from './devtools'; diff --git a/packages/ui/src/root.tsx b/packages/ui/src/root.tsx index 09f86ff..dabfe17 100644 --- a/packages/ui/src/root.tsx +++ b/packages/ui/src/root.tsx @@ -1,4 +1,4 @@ -import { QwikDevtools } from "./devtools"; +import { QwikDevtools } from './devtools'; export default () => { return ( diff --git a/packages/ui/src/types/state.ts b/packages/ui/src/types/state.ts index fbd519b..a2faf7e 100644 --- a/packages/ui/src/types/state.ts +++ b/packages/ui/src/types/state.ts @@ -1,14 +1,14 @@ -import { AssetInfo, NpmInfo, RoutesInfo, Component } from "@devtools/kit"; -import { NoSerialize, Signal } from "@qwik.dev/core"; +import { AssetInfo, NpmInfo, RoutesInfo, Component } from '@devtools/kit'; +import { NoSerialize, Signal } from '@qwik.dev/core'; export type TabName = - | "overview" - | "packages" - | "routes" - | "state" - | "assets" - | "components" - | "inspect"; + | 'overview' + | 'packages' + | 'routes' + | 'state' + | 'assets' + | 'components' + | 'inspect'; export interface State { isOpen: Signal; diff --git a/packages/ui/src/utils/location.ts b/packages/ui/src/utils/location.ts index 5a1f466..b538036 100644 --- a/packages/ui/src/utils/location.ts +++ b/packages/ui/src/utils/location.ts @@ -1,9 +1,9 @@ -import { isBrowser } from "@qwik.dev/core"; +import { isBrowser } from '@qwik.dev/core'; export function getCurrentLocation() { - if (!isBrowser) return ""; + if (!isBrowser) return ''; - if (window.location.pathname === "/") return "/"; + if (window.location.pathname === '/') return '/'; return window.location.pathname.slice(0, -1); } diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index 6fd1a0f..3d2006a 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -1,25 +1,25 @@ /** @type {import('tailwindcss').Config} */ export default { - content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], + content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], theme: { extend: { colors: { - background: "var(--color-background)", - foreground: "var(--color-foreground)", - primary: "var(--color-primary)", - "primary-foreground": "var(--color-primary-foreground)", // e.g., text on primary button 2 - secondary: "var(--color-secondary)", // e.g., muted button background or text 2 - "secondary-foreground": "var(--color-secondary-foreground)", // 2 - muted: "var(--color-muted)", // e.g., placeholder text or very subtle borders 2 - "muted-foreground": "var(--color-muted-foreground)", - accent: "var(--color-accent)", // e.g., for highlights, icons, or active states - "accent-foreground": "var(--color-accent-foreground)", - border: "var(--color-border)", // default border color - input: "var(--color-input)", // specific for input borders if different from general border 2 - ring: "var(--color-ring)", // for focus rings 2 - "card-item-bg": "var(--color-card-item-bg)", // 1 - "card-item-hover-bg": "var(--color-card-item-hover-bg)", // 1 - "text-muted": "var(--color-text-muted)", + background: 'var(--color-background)', + foreground: 'var(--color-foreground)', + primary: 'var(--color-primary)', + 'primary-foreground': 'var(--color-primary-foreground)', // e.g., text on primary button 2 + secondary: 'var(--color-secondary)', // e.g., muted button background or text 2 + 'secondary-foreground': 'var(--color-secondary-foreground)', // 2 + muted: 'var(--color-muted)', // e.g., placeholder text or very subtle borders 2 + 'muted-foreground': 'var(--color-muted-foreground)', + accent: 'var(--color-accent)', // e.g., for highlights, icons, or active states + 'accent-foreground': 'var(--color-accent-foreground)', + border: 'var(--color-border)', // default border color + input: 'var(--color-input)', // specific for input borders if different from general border 2 + ring: 'var(--color-ring)', // for focus rings 2 + 'card-item-bg': 'var(--color-card-item-bg)', // 1 + 'card-item-hover-bg': 'var(--color-card-item-hover-bg)', // 1 + 'text-muted': 'var(--color-text-muted)', }, }, }, diff --git a/packages/ui/vite.config.mts b/packages/ui/vite.config.mts index d041ce4..f1660c2 100644 --- a/packages/ui/vite.config.mts +++ b/packages/ui/vite.config.mts @@ -1,15 +1,15 @@ -import { qwikVite } from "@qwik.dev/core/optimizer"; -import { defineConfig } from "vite"; -import tsconfigPaths from "vite-tsconfig-paths"; -import pkg from "./package.json"; -import { qwikReact } from "@qwik.dev/react/vite"; -import { qwikDevtools } from "@devtools/plugin"; -import { createRequire } from "module"; +import { qwikVite } from '@qwik.dev/core/optimizer'; +import { defineConfig } from 'vite'; +import tsconfigPaths from 'vite-tsconfig-paths'; +import pkg from './package.json'; +import { qwikReact } from '@qwik.dev/react/vite'; +import { qwikDevtools } from '@devtools/plugin'; +import { createRequire } from 'module'; const { dependencies = {}, peerDependencies = {} } = pkg as any; const makeRegex = (dep) => new RegExp(`^${dep}(/.*)?$`); const excludeAll = (obj) => Object.keys(obj).map(makeRegex); const require = createRequire(import.meta.url); -const isBuild = process.argv.includes("lib"); +const isBuild = process.argv.includes('lib'); export default defineConfig(() => { return { @@ -17,27 +17,27 @@ export default defineConfig(() => { alias: isBuild ? undefined : { - "@devtools/ui": require.resolve("."), - "@qwik.dev/devtools/ui": require.resolve("."), + '@devtools/ui': require.resolve('.'), + '@qwik.dev/devtools/ui': require.resolve('.'), }, }, build: { - target: "es2020", + target: 'es2020', lib: { - entry: "./src/index.ts", - formats: ["es", "cjs"], + entry: './src/index.ts', + formats: ['es', 'cjs'], fileName: (format, entryName) => - `${entryName}.qwik.${format === "es" ? "mjs" : "cjs"}`, + `${entryName}.qwik.${format === 'es' ? 'mjs' : 'cjs'}`, }, rollupOptions: { output: { preserveModules: true, - preserveModulesRoot: "src", + preserveModulesRoot: 'src', }, // externalize deps that shouldn't be bundled into the library external: [ - "stream", - "util", + 'stream', + 'util', /^node:.*/, ...excludeAll(peerDependencies), ...excludeAll(dependencies), From 52356f6ed339ab3b1c6112138f913305b28fcd5e Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Tue, 3 Jun 2025 17:40:33 +0800 Subject: [PATCH 12/30] refactor(theme): consolidate theme handling and cleanup - Rename theme storage key for compatibility with vite-plugin-inspect - Extract theme script logic into separate component - Remove unused imports and simplify ThemeToggle component - Replace inline script with ThemeScript component in devtools --- .../components/ThemeToggle/ThemeToggle.tsx | 6 +++--- .../components/ThemeToggle/theme-script.tsx | 13 ++++++++++++ .../components/router-head/theme-script.tsx | 3 ++- packages/ui/src/devtools.tsx | 20 +++++-------------- 4 files changed, 23 insertions(+), 19 deletions(-) create mode 100644 packages/ui/src/components/ThemeToggle/theme-script.tsx diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx index 5f1f010..3c3c845 100644 --- a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx +++ b/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx @@ -5,7 +5,7 @@ import { Signal, event$, } from '@qwik.dev/core'; -import { HiMoonMini, HiSunMini } from '@qwikest/icons/heroicons'; +import { HiSunMini } from '@qwikest/icons/heroicons'; import { themeStorageKey } from '../router-head/theme-script'; type ThemeName = 'dark' | 'light' | undefined; @@ -58,7 +58,6 @@ export const setTheme = (theme: ThemeName) => { export const ThemeToggle = component$(() => { const onClick$ = event$(() => { const currentTheme = getTheme(); - setTheme(currentTheme === 'dark' ? 'light' : 'dark'); }); return ( @@ -66,7 +65,8 @@ export const ThemeToggle = component$(() => { onClick$={onClick$} class="hover:bg-accent/10 flex h-8 w-8 items-center justify-center rounded-md bg-background text-foreground" > - {true ? : } + {/* {true ? : } */} + ); }); diff --git a/packages/ui/src/components/ThemeToggle/theme-script.tsx b/packages/ui/src/components/ThemeToggle/theme-script.tsx new file mode 100644 index 0000000..22d1dfb --- /dev/null +++ b/packages/ui/src/components/ThemeToggle/theme-script.tsx @@ -0,0 +1,13 @@ +import { themeStorageKey } from "../router-head/theme-script"; + +export const ThemeScript = () => { + const themeScript = ` + try { + document.firstElementChild + .setAttribute('data-theme', + localStorage.getItem('${themeStorageKey}') ?? + (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') + ); + } catch (err) { }`; + return `; +} + +type MiddlewareNext = (err?: unknown) => void; +type MinimalMiddlewareReq = { headers: Record; url?: string }; +type MinimalMiddlewareRes = { + write: (...args: any[]) => any; + end: (...args: any[]) => any; + setHeader: (name: string, value: any) => void; +}; + +function attachSsrPerfInjectorMiddleware(server: any) { + // In dev SSR, Qwik streams HTML; `transformIndexHtml` often runs before SSR rendering finishes, + // causing `__QWIK_SSR_PERF__` to still be empty at injection time. + // Instead, intercept the final HTML response and inject after SSR completes. + server.middlewares.use((req: MinimalMiddlewareReq, res: MinimalMiddlewareRes, next: MiddlewareNext) => { + const accept = req.headers.accept || ''; + if (!accept.includes('text/html')) return next(); + + // The SSR collector uses "global accumulation + de-dupe". + // Do NOT clear it per-request, otherwise we may inject empty data if sampling hasn't occurred yet. + const store = getStoreForSSR() as unknown as Record; + + const originalWrite = res.write.bind(res); + const originalEnd = res.end.bind(res); + + let body = ''; + + res.write = function ( + chunk: unknown, + encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void), + callback?: (error?: Error | null) => void + ): boolean { + if (chunk) { + body += typeof chunk === 'string' ? chunk : Buffer.from(chunk as any).toString(); + } + // Don't flush immediately; inject on `end` (in dev it's OK to sacrifice streaming) + if (typeof encodingOrCallback === 'function') encodingOrCallback(); + if (typeof callback === 'function') callback(); + return true; + } as typeof res.write; + + res.end = function ( + chunk?: unknown, + encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void), + callback?: (error?: Error | null) => void + ): typeof res { + if (chunk) { + body += typeof chunk === 'string' ? chunk : Buffer.from(chunk as any).toString(); + } + + if (body.includes('')) { + const rawArr = store.__QWIK_SSR_PERF__; + const entries = Array.isArray(rawArr) ? rawArr : []; + log('inject ssr perf %O', { url: req.url, total: entries.length }); + const script = createSsrPerfInjectionScript(entries); + + // Place at the start of `` so it runs earlier than other head scripts + body = body.replace(/]*)?>/i, (m) => `${m}${script}`); + } + + try { + res.setHeader('Content-Length', Buffer.byteLength(body)); + } catch { + // ignore + } + + originalWrite(body); + + if (typeof encodingOrCallback === 'function') encodingOrCallback(); + if (typeof callback === 'function') callback(); + + return originalEnd(); + } as typeof res.end; + + next(); + }); +} + +// ============================================================================ +// Plugin factory (similar entry-point style to devtools.ts) +// ============================================================================ + +export function statisticsPlugin(): Plugin { + return { + name: 'vite:qwik-component-proxy-transform', + enforce: 'post', + + transform(code, id) { + // Avoid rewriting imports inside the perf virtual module itself (otherwise `originalComponentQrl` + // could become self-referential/undefined) + if (isPerfVirtualModuleId(id)) return null; + + // By default, skip dependencies and build outputs (otherwise we'd transform node_modules / ui's `.qwik.mjs` as well) + if (!shouldTransformSource(id)) return null; + + let modifiedCode = code; + let hasChanges = false; + + // 1) Replace `componentQrl` import from `@qwik.dev/core` -> virtual module + const rewritten = rewriteComponentQrlImport(modifiedCode, id); + modifiedCode = rewritten.code; + hasChanges = hasChanges || rewritten.changed; + + // 2) Handle Qwik-generated lazy render function modules (`_component_`) + const cleanId = normalizeId(id); + if (cleanId.includes('_component_')) { + const exports = findQwikLazyComponentExports(code); + const wrapped = wrapQwikLazyComponentExports({ code: modifiedCode, id, exports }); + modifiedCode = wrapped.code; + hasChanges = hasChanges || wrapped.changed; + } + + if (!hasChanges) return null; + return { code: modifiedCode, map: null }; + }, + + configureServer(server) { + attachSsrPerfInjectorMiddleware(server); + }, + }; +} + +// Backwards compatible default export (existing callers spread a Plugin[]) +export default function qwikComponentProxy(): Plugin[] { + return [statisticsPlugin()]; +} diff --git a/packages/plugin/src/utils/useCollectHooks.ts b/packages/plugin/src/utils/useCollectHooks.ts deleted file mode 100644 index 5dd1061..0000000 --- a/packages/plugin/src/utils/useCollectHooks.ts +++ /dev/null @@ -1,22 +0,0 @@ -const useCollectHooks = `import { $, useSignal, useVisibleTask$ } from "@qwik.dev/core" -export const useCollectHooks = (src) => { - const hooksList = useSignal(new Set()) - useVisibleTask$(({ track }) => { - const newdata = track(() => hooksList.value); - if(!window.QWIK_DEVTOOLS_GLOBAL_STATE) { - window.QWIK_DEVTOOLS_GLOBAL_STATE = {} - window.QWIK_DEVTOOLS_GLOBAL_STATE[src] = [...newdata] - }else { - window.QWIK_DEVTOOLS_GLOBAL_STATE[src] = [...newdata] - } - }, { strategy: 'document-ready'}) - return $((args) => { - if(hooksList.value.has(args)) { - return - } - hooksList.value.add(args) - }) -} -` - -export default useCollectHooks \ No newline at end of file diff --git a/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts b/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts new file mode 100644 index 0000000..4134ee0 --- /dev/null +++ b/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts @@ -0,0 +1,51 @@ +import perfRuntime from './perfRuntime'; + +/** + * Preamble injected into Qwik-generated lazy render function modules (`_component_...`). + * + * It defines `__qwik_wrap__` that wraps each exported render function and records perf entries. + */ +const perfLazyWrapperPreamble = `${perfRuntime} + +// [qwik-component-proxy] Render function wrapper +const __qwik_wrap__ = (fn, name, viteId) => { + let renderCount = 0; + return function (...args) { + renderCount += 1; + const phase = __qwik_perf_is_server__() ? 'ssr' : 'csr'; + const start = performance.now(); + + try { + const result = fn.apply(this, args); + const duration = performance.now() - start; + __qwik_perf_commit__({ + component: name, + phase, + duration, + start, + end: start + duration, + viteId, + renderCount, + }); + return result; + } catch (err) { + const duration = performance.now() - start; + __qwik_perf_commit__({ + component: name, + phase, + duration, + start, + end: start + duration, + error: __qwik_perf_to_error__(err), + viteId, + renderCount, + }); + throw err; + } + }; +}; +`; + +export default perfLazyWrapperPreamble; + + diff --git a/packages/plugin/src/virtualmodules/perfRuntime.ts b/packages/plugin/src/virtualmodules/perfRuntime.ts new file mode 100644 index 0000000..1d33067 --- /dev/null +++ b/packages/plugin/src/virtualmodules/perfRuntime.ts @@ -0,0 +1,140 @@ +/** + * Shared runtime snippet used by perf instrumentation code. + * + * This file exports a **string** (not executable TS) that gets concatenated into: + * - the virtual module `virtual:qwik-component-proxy` + * - injected wrappers for Qwik-generated `_component_` render-function modules + * + * It is intentionally framework-agnostic and relies only on `window`/`process`. + */ +const perfRuntime = ` +// [qwik-perf-runtime] shared helpers (injected) +const __qwik_perf_is_server__ = () => typeof window === 'undefined'; + +const __qwik_perf_init_csr__ = () => { + if (typeof window === 'undefined') return; + window.__QWIK_PERF__ = window.__QWIK_PERF__ || { ssr: [], csr: [] }; + // Map: viteId -> index in perf.csr (used for upsert) + window.__QWIK_PERF__._csrByViteId = window.__QWIK_PERF__._csrByViteId || {}; + // Map: component -> index in perf.ssr (used for componentQrl upsert on CSR) + window.__QWIK_PERF__._ssrByComponent = window.__QWIK_PERF__._ssrByComponent || {}; +}; + +const __qwik_perf_get_ssr_store__ = () => + typeof process !== 'undefined' && process ? process : globalThis; + +const __qwik_perf_to_error__ = (err) => ({ + name: (err && err.name) || 'Error', + message: err && err.message ? String(err.message) : String(err), +}); + +const __qwik_perf_next_id__ = (perf) => { + perf._id = (perf._id || 0) + 1; + return perf._id; +}; + +const __qwik_perf_next_ssr_id__ = (store) => { + store.__QWIK_SSR_PERF_ID__ = (store.__QWIK_SSR_PERF_ID__ || 0) + 1; + return store.__QWIK_SSR_PERF_ID__; +}; + +const __qwik_perf_ssr_push__ = (store, entry) => { + const id = __qwik_perf_next_ssr_id__(store); + store.__QWIK_SSR_PERF__.push({ id, ...entry }); + return store.__QWIK_SSR_PERF__.length - 1; +}; + +const __qwik_perf_commit_ssr__ = (store, entry) => { + store.__QWIK_SSR_PERF__ = store.__QWIK_SSR_PERF__ || []; + + // Upsert by key (viteId preferred, otherwise component). Keep only the latest entry per key, + // but also attach an ever-increasing ssrCount so we can see how many times it rendered. + store.__QWIK_SSR_PERF_INDEX__ = store.__QWIK_SSR_PERF_INDEX__ || {}; + store.__QWIK_SSR_PERF_COUNT__ = store.__QWIK_SSR_PERF_COUNT__ || {}; + + const key = (entry && (entry.viteId || entry.component)) || 'unknown'; + const nextCount = (store.__QWIK_SSR_PERF_COUNT__[key] || 0) + 1; + store.__QWIK_SSR_PERF_COUNT__[key] = nextCount; + + const next = { ...entry, ssrCount: nextCount }; + const existingIdx = store.__QWIK_SSR_PERF_INDEX__[key]; + + if (typeof existingIdx === 'number') { + const prev = store.__QWIK_SSR_PERF__[existingIdx]; + store.__QWIK_SSR_PERF__[existingIdx] = { id: prev?.id, ...next }; + } else { + store.__QWIK_SSR_PERF_INDEX__[key] = __qwik_perf_ssr_push__(store, next); + } +}; + +const __qwik_perf_commit_csr__ = (entry) => { + __qwik_perf_init_csr__(); + const perf = window.__QWIK_PERF__; + const next = { id: __qwik_perf_next_id__(perf), ...entry }; + + // If viteId exists we treat it as an "upsert" record (render-function modules). + if (entry && entry.viteId) { + const idx = perf._csrByViteId[entry.viteId]; + if (typeof idx === 'number') perf.csr[idx] = next; + else { + perf._csrByViteId[entry.viteId] = perf.csr.length; + perf.csr.push(next); + } + return; + } + + perf.csr.push(next); +}; + +// Force componentQrl entries to be treated as SSR records. +// - On SSR: store into process/globalThis __QWIK_SSR_PERF__ (same as other SSR entries) +// - On CSR: store into window.__QWIK_PERF__.ssr (so csr only contains render-function modules) +const __qwik_perf_commit_componentqrl__ = (entry) => { + const next = { ...entry, phase: 'ssr'}; + if (__qwik_perf_is_server__()) { + const store = __qwik_perf_get_ssr_store__(); + __qwik_perf_commit_ssr__(store, next); + return; + } + + __qwik_perf_init_csr__(); + const perf = window.__QWIK_PERF__; + perf.ssr = perf.ssr || []; + // Build index lazily from any SSR-injected snapshot + if (!perf._ssrIndexBuilt) { + for (let i = 0; i < perf.ssr.length; i++) { + const e = perf.ssr[i]; + if (e && e.component && typeof perf._ssrByComponent[e.component] !== 'number') { + perf._ssrByComponent[e.component] = i; + } + } + perf._ssrIndexBuilt = true; + } + + const key = next && next.component; + const idx = key ? perf._ssrByComponent[key] : undefined; + if (typeof idx === 'number') { + const prev = perf.ssr[idx]; + const prevCount = prev && typeof prev.ssrCount === 'number' ? prev.ssrCount : 0; + const ssrCount = prevCount + 1; + perf.ssr[idx] = { id: prev && prev.id, ...next, ssrCount }; + } else { + const id = __qwik_perf_next_id__(perf); + if (key) perf._ssrByComponent[key] = perf.ssr.length; + perf.ssr.push({ id, ...next, ssrCount: 1 }); + } +}; + +const __qwik_perf_commit__ = (entry) => { + if (__qwik_perf_is_server__()) { + const store = __qwik_perf_get_ssr_store__(); + __qwik_perf_commit_ssr__(store, entry); + } else { + __qwik_perf_commit_csr__(entry); + } +}; +`; + +export default perfRuntime; + + diff --git a/packages/plugin/src/virtualmodules/qwikComponentProxy.ts b/packages/plugin/src/virtualmodules/qwikComponentProxy.ts new file mode 100644 index 0000000..ed19b82 --- /dev/null +++ b/packages/plugin/src/virtualmodules/qwikComponentProxy.ts @@ -0,0 +1,53 @@ +/** + * Virtual module source for perf tracking of Qwik's `componentQrl`. + * + * This module is loaded via the devtools plugin virtual-module registry + * (`virtualmodules/virtualModules.ts`) and is imported from: + * - `virtual:qwik-component-proxy` + */ +import perfRuntime from './perfRuntime'; + +const qwikComponentProxy = `${perfRuntime} +import { componentQrl as originalComponentQrl } from '@qwik.dev/core'; + +function componentQrl(qrl, options) { + const phase = __qwik_perf_is_server__() ? 'ssr' : 'csr'; + const start = performance.now(); + let viteId = null; + const component = qrl?.getSymbol?.() || qrl?.$symbol$ || 'unknown'; + if(qrl.dev){ + viteId = qrl.dev.file.replace(/[^/]*$/, qrl.dev.displayName); + } + try { + const result = originalComponentQrl(qrl, options); + const duration = performance.now() - start; + __qwik_perf_commit_componentqrl__({ + component, + phase, + duration, + start, + viteId, + end: start + duration, + }); + return result; + } catch (err) { + const duration = performance.now() - start; + __qwik_perf_commit_componentqrl__({ + component, + phase, + duration, + start, + viteId, + end: start + duration, + error: __qwik_perf_to_error__(err), + }); + throw err; + } +} + +export { componentQrl }; +`; + +export default qwikComponentProxy; + + diff --git a/packages/plugin/src/virtualmodules/useCollectHooks.ts b/packages/plugin/src/virtualmodules/useCollectHooks.ts new file mode 100644 index 0000000..a6ead6a --- /dev/null +++ b/packages/plugin/src/virtualmodules/useCollectHooks.ts @@ -0,0 +1,44 @@ +/** + * Virtual module source for devtools tracking. + * Collects hooks and tracks render statistics. + */ +const useCollectHooks = `import { $, useSignal, useVisibleTask$ } from "@qwik.dev/core" + +function initComponentState() { + return { + hooks: [], + stats: {} + } +} + +function getOrCreateState(src) { + if (!window.QWIK_DEVTOOLS_GLOBAL_STATE) { + window.QWIK_DEVTOOLS_GLOBAL_STATE = {} + } + if (!window.QWIK_DEVTOOLS_GLOBAL_STATE[src]) { + window.QWIK_DEVTOOLS_GLOBAL_STATE[src] = initComponentState() + } + return window.QWIK_DEVTOOLS_GLOBAL_STATE[src] +} + +/** + * Hook to collect component hooks + */ +export const useCollectHooks = (src) => { + const hooksList = useSignal(new Set()) + useVisibleTask$(({ track }) => { + const newHooks = track(() => hooksList.value) + const state = getOrCreateState(src) + state.hooks = [...newHooks] + }, { strategy: 'document-ready' }) + + return $((args) => { + if (hooksList.value.has(args)) { + return + } + hooksList.value.add(args) + }) +} +` + +export default useCollectHooks diff --git a/packages/plugin/src/virtualmodules/virtualModules.ts b/packages/plugin/src/virtualmodules/virtualModules.ts new file mode 100644 index 0000000..25587a2 --- /dev/null +++ b/packages/plugin/src/virtualmodules/virtualModules.ts @@ -0,0 +1,91 @@ +import { VIRTUAL_QWIK_DEVTOOLS_KEY, INNER_USE_HOOK } from '@devtools/kit'; +import useCollectHooksSource from './useCollectHooks'; +import qwikComponentProxySource from './qwikComponentProxy'; +import { parseQwikCode } from '../parse/parse'; +import { debug } from 'debug'; + +const log = debug('qwik:devtools:plugin'); + +// ============================================================================ +// Types & Configuration +// ============================================================================ + +export interface VirtualModuleConfig { + key: string; + source: string; + hookName: string; +} + +export const VIRTUAL_MODULES: VirtualModuleConfig[] = [ + { + key: VIRTUAL_QWIK_DEVTOOLS_KEY, + source: useCollectHooksSource, + hookName: INNER_USE_HOOK, + }, + { + // Perf tracking: used by `plugin/statistics.ts` to rewrite `componentQrl` imports + key: 'virtual:qwik-component-proxy', + source: qwikComponentProxySource, + hookName: '', + } +]; + +// ============================================================================ +// Virtual Module Helpers +// ============================================================================ + +export function normalizeId(id: string): string { + return id.split('?')[0].split('#')[0]; +} + +export function getIdVariations(key: string): string[] { + return [key, `/${key}`, `\u0000${key}`, `/@id/${key}`]; +} + +export function isVirtualId(id: string, key: string): boolean { + return getIdVariations(key).includes(normalizeId(id)); +} + +export function findVirtualModule(id: string): VirtualModuleConfig | undefined { + return VIRTUAL_MODULES.find((module) => isVirtualId(id, module.key)); +} + +// ============================================================================ +// Code Transform Helpers +// ============================================================================ + +function injectImportIfMissing(code: string, key: string, hookName: string): string { + if (!code.includes(key)) { + return `import { ${hookName} } from '${key}';\n${code}`; + } + log('importing virtual qwik devtools', key, code); + return code; +} + +export function transformComponentFile(code: string, id: string): string { + // Inject useCollectHooks import + code = injectImportIfMissing(code, VIRTUAL_QWIK_DEVTOOLS_KEY, INNER_USE_HOOK); + // Parse and transform the Qwik code + return parseQwikCode(code, { path: id }); +} + +export function transformRootFile(code: string): string { + const mode = process.env.MODE; + const importPath = mode === 'dev' ? '@devtools/ui' : '@qwik.dev/devtools/ui'; + + // Add QwikDevtools import if not present + if (!code.includes(importPath)) { + code = `import { QwikDevtools } from '${importPath}';\n${code}`; + } + + // Inject QwikDevtools component before closing body tag + const bodyMatch = code.match(/]*>([\s\S]*?)<\/body>/); + if (bodyMatch) { + const bodyContent = bodyMatch[1]; + const newBodyContent = `${bodyContent}\n `; + code = code.replace(bodyContent, newBodyContent); + } + + return code; +} + diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index 61be4a8..f887059 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -13,6 +13,7 @@ import { HiMegaphoneMini, HiCubeOutline, HiCodeBracketSolid, + HiClockOutline } from '@qwikest/icons/heroicons'; import { BsDiagram3 } from '@qwikest/icons/bootstrap'; import { LuFolderTree } from '@qwikest/icons/lucide'; @@ -40,6 +41,7 @@ import { Inspect } from './features/inspect/Inspect'; import { QwikThemeToggle } from './components/ThemeToggle/QwikThemeToggle'; import { ThemeScript as QwikThemeScript } from './components/ThemeToggle/theme-script'; import { CodeBreack } from './features/CodeBreack/CodeBreack'; +import { Performance } from './features/Performance/Performance'; import { debug } from 'debug'; const log = debug('qwik:devtools:devtools'); @@ -182,9 +184,12 @@ export const QwikDevtools = component$(() => { - + + + +
@@ -255,6 +260,12 @@ export const QwikDevtools = component$(() => { )} + {state.activeTab === 'performance' && ( + + + + + )}
)} diff --git a/packages/ui/src/features/Performance/Performance.tsx b/packages/ui/src/features/Performance/Performance.tsx new file mode 100644 index 0000000..5590671 --- /dev/null +++ b/packages/ui/src/features/Performance/Performance.tsx @@ -0,0 +1,192 @@ +import { component$, useComputed$, useSignal, useTask$, $, isBrowser } from '@qwik.dev/core'; +import type { QwikPerfStoreRemembered } from '@devtools/kit'; +import { computeEventRows, computePerfViewModel } from './computePerfViewModel'; + +function formatMs(ms: number): string { + if (!Number.isFinite(ms)) return '-'; + if (ms >= 1000) return `${(ms / 1000).toFixed(2)}s`; + if (ms >= 10) return `${ms.toFixed(0)}ms`; + return `${ms.toFixed(2)}ms`; +} + +export const Performance = component$(() => { + const perf = useSignal(null); + const selectedComponent = useSignal(null); + + useTask$(() => { + if (!isBrowser) return; + perf.value = window.__QWIK_PERF__ || { ssr: [], csr: [] }; + }); + + const vm = useComputed$(() => computePerfViewModel(perf.value)); + + const selectedVm = useComputed$(() => { + const name = selectedComponent.value; + if (!name) return null; + return vm.value.components.find((c) => c.componentName === name) || null; + }); + + const onSelect = $((name: string) => { + selectedComponent.value = name; + }); + + const clearSelect = $(() => { + selectedComponent.value = null; + }); + + return ( +
+ {!perf.value?.ssr?.length && !perf.value?.csr?.length ? ( +
+
+ No performance data found. +
+ Ensure instrumentation is enabled and interact with the app, then reopen this tab. +
+
+
+ ) : ( +
+ {/* Overview cards */} +
+
+
+
TOTAL RENDER TIME
+
{formatMs(vm.value.overview.totalRenderTime)}
+
+
+ +
+
+
SLOWEST COMPONENT
+
+ {vm.value.overview.slowestComponent?.componentName || '-'} +
+
+ {vm.value.overview.slowestComponent + ? `${formatMs(vm.value.overview.slowestComponent.avgTime)} avg` + : '-'} +
+
+
+ +
+
+
AVG TIME
+
{formatMs(vm.value.overview.avgTime)}
+
+
+ +
+
+
TOTAL CALLS
+
{vm.value.overview.totalCalls}
+
+
+
+ + {/* Main split */} +
+
+
+
+
Components
+
+ CSR only • {vm.value.components.length} total +
+
+
+ +
+ {vm.value.components.map((c) => { + const selected = selectedComponent.value === c.componentName; + return ( + + ); + })} +
+
+ +
+ +
+ {selectedVm.value ? ( + <> +
+
+
+ {selectedVm.value.componentName} Hook Details +
+
+ Total: {formatMs(selectedVm.value.totalTime)} • {selectedVm.value.calls} calls +
+
+ +
+ +
+
+
+
HOOK NAME
+
TIME
+
CALLS
+
+
+ {computeEventRows(selectedVm.value.csrItems).map((row) => ( +
+
{row.eventName}
+
{formatMs(row.time)}
+
{row.calls}
+
+ ))} + {!selectedVm.value.csrItems.length && ( +
+ No CSR records for this component. +
+ )} +
+
+
+ + ) : ( +
+
+ Select a component to view hook details. +
+
+ )} +
+
+
+ )} +
+ ); +}); diff --git a/packages/ui/src/features/Performance/computePerfViewModel.test.ts b/packages/ui/src/features/Performance/computePerfViewModel.test.ts new file mode 100644 index 0000000..57f0b4a --- /dev/null +++ b/packages/ui/src/features/Performance/computePerfViewModel.test.ts @@ -0,0 +1,121 @@ +import { describe, expect, it } from 'vitest'; +import { computeEventRows, computePerfViewModel } from './computePerfViewModel'; +import type { QwikPerfStoreRemembered } from '@devtools/kit'; + +describe('computePerfViewModel', () => { + it('prefers ssr list when present and groups csr via _component_ prefix', () => { + const ssrButton = { + id: 1, + component: 'Button_component_hash', + phase: 'ssr' as const, + duration: 0, + start: 0, + end: 0, + ssrCount: 1, + }; + + const data: QwikPerfStoreRemembered = { + ssr: [ssrButton], + csr: [ + { + id: 10, + component: 'Button_component_qwikContainer_useComputed_abc', + phase: 'csr', + duration: 4, + start: 0, + end: 4, + renderCount: 2, + }, + { + id: 11, + component: 'Button_component_hash', + phase: 'csr', + duration: 6, + start: 0, + end: 6, + renderCount: 1, + }, + ], + }; + + const vm = computePerfViewModel(data); + expect(vm.components.map((c) => c.componentName)).toEqual(['Button']); + expect(vm.components[0].calls).toBe(3); + expect(vm.components[0].totalTime).toBe(10); + }); + + it('falls back to csr-only grouping by componentName when ssr is empty', () => { + const data: QwikPerfStoreRemembered = { + ssr: [], + csr: [ + { + id: 1, + component: 'A_component_x_useEffect_1', + phase: 'csr', + duration: 1, + start: 0, + end: 1, + }, + { + id: 2, + component: 'A_component_x_onClick_2', + phase: 'csr', + duration: 2, + start: 0, + end: 2, + renderCount: 3, + }, + { + id: 3, + component: 'B_component_y', + phase: 'csr', + duration: 5, + start: 0, + end: 5, + }, + ], + }; + + const vm = computePerfViewModel(data); + expect(vm.components.map((c) => c.componentName).sort()).toEqual(['A', 'B']); + const a = vm.components.find((c) => c.componentName === 'A')!; + expect(a.totalTime).toBe(3); + expect(a.calls).toBe(4); + }); +}); + +describe('computeEventRows', () => { + it('uses render when eventName is missing and uses renderCount as calls fallback', () => { + const rows = computeEventRows([ + { + id: 1, + component: 'A_component_x', + componentName: 'A', + phase: 'csr', + duration: 2, + start: 0, + end: 2, + // no eventName -> render + } as any, + { + id: 2, + component: 'A_component_x_useEffect_1', + componentName: 'A', + eventName: 'useEffect', + phase: 'csr', + duration: 1, + start: 0, + end: 1, + renderCount: 3, + } as any, + ]); + + const byName = new Map(rows.map((r) => [r.eventName, r])); + expect(byName.get('render')?.calls).toBe(1); + expect(byName.get('render')?.time).toBe(2); + expect(byName.get('useEffect')?.calls).toBe(3); + expect(byName.get('useEffect')?.time).toBe(1); + }); +}); + + diff --git a/packages/ui/src/features/Performance/computePerfViewModel.ts b/packages/ui/src/features/Performance/computePerfViewModel.ts new file mode 100644 index 0000000..6e1ceff --- /dev/null +++ b/packages/ui/src/features/Performance/computePerfViewModel.ts @@ -0,0 +1,127 @@ +import type { QwikPerfStoreRemembered } from '@devtools/kit'; +import { groupCsrBySsr, parseComponentAndEventName, type PerfGroupedCsrItem, type PerfSsrItem } from './transformPerformanceData'; + +export type PerfPayload = QwikPerfStoreRemembered; + +export interface PerfOverviewVm { + totalRenderTime: number; + totalCalls: number; + avgTime: number; + slowestComponent?: { + componentName: string; + avgTime: number; + totalTime: number; + calls: number; + }; +} + +export interface PerfComponentVm { + componentName: string; + totalTime: number; + calls: number; + avgTime: number; + ssr?: PerfSsrItem; + csrItems: PerfGroupedCsrItem[]; +} + +export interface PerfEventVm { + eventName: string; + time: number; + calls: number; +} + +export interface PerfViewModel { + overview: PerfOverviewVm; + components: PerfComponentVm[]; +} + +function getCallsFromCsr(item: PerfGroupedCsrItem): number { + return typeof item.renderCount === 'number' ? item.renderCount : 1; +} + +export function computeEventRows(csrItems: PerfGroupedCsrItem[]): PerfEventVm[] { + const byEvent = new Map(); + for (const item of csrItems) { + const eventName = item.eventName || 'render'; + const prev = byEvent.get(eventName) || { time: 0, calls: 0 }; + prev.time += item.duration || 0; + prev.calls += getCallsFromCsr(item); + byEvent.set(eventName, prev); + } + return [...byEvent.entries()] + .map(([eventName, v]) => ({ eventName, time: v.time, calls: v.calls })) + .sort((a, b) => b.time - a.time); +} + +function computeComponentVmFromCsr(componentName: string, csrItems: PerfGroupedCsrItem[], ssr?: PerfSsrItem): PerfComponentVm { + let totalTime = 0; + let calls = 0; + for (const item of csrItems) { + totalTime += item.duration || 0; + calls += getCallsFromCsr(item); + } + const avgTime = calls > 0 ? totalTime / calls : 0; + return { componentName, totalTime, calls, avgTime, ssr, csrItems }; +} + +export function computePerfViewModel(perf: PerfPayload | undefined | null): PerfViewModel { + const safe: PerfPayload = perf || { ssr: [], csr: [] }; + + const components: PerfComponentVm[] = []; + + if (safe.ssr?.length) { + const grouped = groupCsrBySsr(safe); + for (const ssrItem of safe.ssr as PerfSsrItem[]) { + const componentName = parseComponentAndEventName(ssrItem.component).componentName; + const csrItems = grouped.get(ssrItem as PerfSsrItem) || []; + components.push(computeComponentVmFromCsr(componentName, csrItems, ssrItem as PerfSsrItem)); + } + } else if (safe.csr?.length) { + const byName = new Map(); + for (const csrItem of safe.csr as any[]) { + const parsed = parseComponentAndEventName(csrItem.component); + const list = byName.get(parsed.componentName) || []; + list.push({ ...csrItem, ...parsed }); + byName.set(parsed.componentName, list); + } + for (const [componentName, csrItems] of byName.entries()) { + components.push(computeComponentVmFromCsr(componentName, csrItems)); + } + } + + // Sort components by total time (desc) to make the list useful. + components.sort((a, b) => b.totalTime - a.totalTime); + + let totalRenderTime = 0; + let totalCalls = 0; + for (const c of components) { + totalRenderTime += c.totalTime; + totalCalls += c.calls; + } + const avgTime = totalCalls > 0 ? totalRenderTime / totalCalls : 0; + + const slowest = components + .filter((c) => c.calls > 0) + .reduce((acc, cur) => { + if (!acc) return cur; + return cur.avgTime > acc.avgTime ? cur : acc; + }, undefined); + + const overview: PerfOverviewVm = { + totalRenderTime, + totalCalls, + avgTime, + slowestComponent: slowest + ? { + componentName: slowest.componentName, + avgTime: slowest.avgTime, + totalTime: slowest.totalTime, + calls: slowest.calls, + } + : undefined, + }; + + return { overview, components }; +} + + diff --git a/packages/ui/src/features/Performance/transformPerformanceData.test.ts b/packages/ui/src/features/Performance/transformPerformanceData.test.ts new file mode 100644 index 0000000..9a3e4f3 --- /dev/null +++ b/packages/ui/src/features/Performance/transformPerformanceData.test.ts @@ -0,0 +1,110 @@ +import { describe, expect, it } from 'vitest'; +import { groupCsrBySsr } from './transformPerformanceData'; +import type { QwikPerfStoreRemembered } from '@devtools/kit'; + +describe('groupCsrBySsr', () => { + it('groups CSR by SSR via `_component_` prefix (hook/event style + component instance style)', () => { + const ssrButton = { + id: 4, + component: 'Button_component_4n7uUfcfzUA', + phase: 'ssr' as const, + duration: 0.1, + start: 1, + end: 1.1, + ssrCount: 2, + }; + + const ssrRoutes = { + id: 9, + component: 'routes_component_SvRQF1kT0DY', + phase: 'ssr' as const, + duration: 0.002, + start: 2, + end: 2.002, + ssrCount: 1, + }; + + const data: QwikPerfStoreRemembered = { + ssr: [ssrButton, ssrRoutes], + csr: [ + { + id: 15, + component: 'Button_component_qwikContainer_useComputed_U4doJ1SoX6Y', + phase: 'csr', + duration: 0.1, + start: 10, + end: 10.1, + renderCount: 1, + }, + { + id: 16, + component: 'Button_component_4n7uUfcfzUA', + phase: 'csr', + duration: 0.5, + start: 11, + end: 11.5, + renderCount: 2, + }, + { + id: 11, + component: 'routes_component_Fragment_Button_onClick_XvXtXTjQY2A', + phase: 'csr', + duration: 0, + start: 20, + end: 20, + renderCount: 1, + }, + ], + }; + + const result = groupCsrBySsr(data); + + const buttonList = result.get(ssrButton); + const routesList = result.get(ssrRoutes); + + expect(buttonList).toBeDefined(); + expect(routesList).toBeDefined(); + + expect(buttonList!.map((x) => x.id)).toEqual([15, 16]); + expect(buttonList![0].componentName).toBe('Button'); + expect(buttonList![0].eventName).toBe('useComputed'); + expect(buttonList![1].componentName).toBe('Button'); + expect(buttonList![1].eventName).toBeUndefined(); + + expect(routesList!.map((x) => x.id)).toEqual([11]); + expect(routesList![0].componentName).toBe('routes'); + expect(routesList![0].eventName).toBe('onClick'); + }); + + it('drops unmatched CSR but still initializes SSR keys with empty arrays', () => { + const ssrOnly = { + id: 1, + component: 'Only_component_hash', + phase: 'ssr' as const, + duration: 0.01, + start: 1, + end: 1.01, + ssrCount: 1, + }; + + const data: QwikPerfStoreRemembered = { + ssr: [ssrOnly], + csr: [ + { + id: 999, + component: 'NoMatch_component_xxx', + phase: 'csr', + duration: 0, + start: 0, + end: 0, + renderCount: 1, + }, + ], + }; + + const result = groupCsrBySsr(data); + expect(result.get(ssrOnly)).toEqual([]); + }); +}); + + diff --git a/packages/ui/src/features/Performance/transformPerformanceData.ts b/packages/ui/src/features/Performance/transformPerformanceData.ts new file mode 100644 index 0000000..b61b87f --- /dev/null +++ b/packages/ui/src/features/Performance/transformPerformanceData.ts @@ -0,0 +1,51 @@ +import type { QwikPerfEntryRemembered, QwikPerfStoreRemembered } from '@devtools/kit'; + +export type PerfPayload = QwikPerfStoreRemembered; +// Note: runtime instrumentation attaches `ssrCount` to SSR entries (see plugin perf runtime). +export type PerfSsrItem = QwikPerfEntryRemembered & { phase: 'ssr'; ssrCount?: number }; +export type PerfCsrItem = QwikPerfEntryRemembered & { phase: 'csr' }; + +export interface PerfParsedNames { + componentName: string; + eventName?: string; +} + +export function parseComponentAndEventName(component: string): PerfParsedNames { + const componentName = (component?.split('_component_')[0] ?? component) || ''; + const rest = component.includes('_component_') ? component.split('_component_')[1] ?? '' : ''; + const parts = rest.split('_').filter(Boolean); + const eventName = parts.find((p) => /^use[A-Z_]/.test(p) || /^on[A-Z_]/.test(p)); + return { componentName, eventName }; +} + +/** + * Groups CSR records by SSR component name (split by `_component_`). + * - key: the SSR item object reference (WeakMap key) + * - value: CSR list belonging to that SSR component + * - unmatched CSR items: dropped + */ +export type PerfGroupedCsrItem = PerfCsrItem & PerfParsedNames; + +export function groupCsrBySsr(data: PerfPayload): WeakMap { + const ssrByName = new Map(); + for (const ssrItem of data.ssr) { + // Trust runtime shape: SSR entries should have phase 'ssr' + ssrByName.set(parseComponentAndEventName(ssrItem.component).componentName, ssrItem as PerfSsrItem); + } + + const result = new WeakMap(); + for (const ssrItem of data.ssr) { + result.set(ssrItem as PerfSsrItem, []); + } + + for (const csrItem of data.csr) { + const parsed = parseComponentAndEventName(csrItem.component); + const ssrItem = ssrByName.get(parsed.componentName); + if (!ssrItem) continue; + result.get(ssrItem)!.push({ ...(csrItem as PerfCsrItem), ...parsed }); + } + + return result; +} + + diff --git a/packages/ui/src/features/RenderTree/HookDataStore.ts b/packages/ui/src/features/RenderTree/HookDataStore.ts deleted file mode 100644 index fc7ee12..0000000 --- a/packages/ui/src/features/RenderTree/HookDataStore.ts +++ /dev/null @@ -1,290 +0,0 @@ -import type { TreeNode } from '../../components/Tree/Tree'; -import { - CAPTURE_REF_KEY, - CHUNK_KEY, - COMPUTED_QRL_KEY, - QRL_KEY, -} from '@devtools/kit'; -import type { QRL } from '@qwik.dev/core'; -import { - HOOK_TYPES, - HIDDEN_HOOKS, - QRL_HOOKS, - type HookType, - type HookFilterItem, -} from './types'; -import { TreeBuilder } from './TreeBuilder'; - -/** - * Store for managing hook data collected from components. - * Replaces the previous module-level global state. - */ -export class HookDataStore { - private data: Map> = new Map(); - private visibilityConfig: Map = new Map(); - - constructor() { - this.initializeStore(); - } - - private initializeStore(): void { - for (const hookType of HOOK_TYPES) { - this.data.set(hookType, new Set()); - this.visibilityConfig.set(hookType, !HIDDEN_HOOKS.includes(hookType)); - } - } - - /** - * Add data for a specific hook type - */ - add(type: HookType, entry: unknown): void { - const set = this.data.get(type); - if (set) { - set.add(entry); - } - } - - /** - * Get all entries for a specific hook type - */ - get(type: HookType): unknown[] { - return [...(this.data.get(type) ?? [])]; - } - - /** - * Get all data as a plain object - */ - getAll(): Record { - const result = {} as Record; - for (const [type, set] of this.data) { - result[type] = [...set]; - } - return result; - } - - /** - * Check if a hook type has any data - */ - has(type: HookType): boolean { - return (this.data.get(type)?.size ?? 0) > 0; - } - - /** - * Clear all stored data - */ - clear(): void { - for (const set of this.data.values()) { - set.clear(); - } - } - - /** - * Set visibility for a hook type - */ - setVisibility(type: HookType, visible: boolean): void { - this.visibilityConfig.set(type, visible); - } - - /** - * Check if a hook type is visible - */ - isVisible(type: HookType): boolean { - return this.visibilityConfig.get(type) ?? true; - } - - /** - * Get filter list for UI - */ - getFilterList(): HookFilterItem[] { - return HOOK_TYPES.filter( - (type) => this.has(type) && this.isVisible(type), - ).map((key) => ({ - key, - display: this.isVisible(key), - })); - } - - /** - * Build tree nodes from stored data - */ - buildTree(): TreeNode[] { - const builder = new TreeBuilder(); - const result: TreeNode[] = []; - - for (const hookType of HOOK_TYPES) { - if (!this.has(hookType) || !this.isVisible(hookType)) { - continue; - } - - const entries = this.get(hookType); - const nodes = this.transformEntriesToNodes(hookType, entries, builder); - - if (nodes.length > 0) { - result.push(builder.createGroupNode(hookType, nodes)); - } - } - - return result; - } - - /** - * Transform entries to tree nodes based on hook type - */ - private transformEntriesToNodes( - hookType: HookType, - entries: unknown[], - builder: TreeBuilder, - ): TreeNode[] { - return entries - .map((entry) => this.transformSingleEntry(hookType, entry, builder)) - .flat() - .filter(Boolean) as TreeNode[]; - } - - private transformSingleEntry( - hookType: HookType, - entry: unknown, - builder: TreeBuilder, - ): TreeNode[] { - const typedEntry = entry as Record; - - switch (hookType) { - case 'props': - case 'listens': - case 'render': - return builder.objectToTree(typedEntry.data as Record); - - case 'useTask': - case 'useVisibleTask': { - const scopeVars = this.findScopeVariables(typedEntry); - return builder.objectToTree({ - [`let ${typedEntry.variableName ?? hookType} =`]: scopeVars, - }); - } - - case 'customhook': { - const captureRef = (typedEntry.data as Record)?.[ - CAPTURE_REF_KEY - ]; - return builder.objectToTree({ - [`let ${typedEntry.variableName ?? 'customhook'} = Scope `]: captureRef, - }); - } - - default: - return builder.objectToTree({ - [`let ${typedEntry.variableName ?? hookType} =`]: typedEntry.data, - }); - } - } - - /** - * Find scope variables for useTask/useVisibleTask - */ - private findScopeVariables(entry: Record): string { - const targets = (entry.data as Record)?.[ - CAPTURE_REF_KEY - ] as unknown[] | undefined; - - if (!targets) return 'Scope []'; - - const variableNames: string[] = []; - - for (const [, set] of this.data) { - for (const storedEntry of set) { - const entryData = storedEntry as Record; - const data = entryData?.data ?? entryData; - if (!data) continue; - - const match = targets.find((target) => target === data); - if (match && entryData.variableName) { - variableNames.push(entryData.variableName as string); - } - } - } - - return `Scope [${variableNames.join(', ')}]`; - } - - /** - * Find all QRL paths for code lookup - */ - findAllQrlPaths(): string[] { - const paths: string[] = []; - - for (const hookType of QRL_HOOKS) { - const entries = this.get(hookType); - - for (const entry of entries) { - const typedEntry = entry as Record; - const extracted = this.extractQrlPath(hookType, typedEntry); - if (extracted) { - if (Array.isArray(extracted)) { - paths.push(...extracted.filter(Boolean)); - } else { - paths.push(extracted); - } - } - } - } - - return paths.filter(Boolean); - } - - private extractQrlPath( - hookType: HookType, - entry: Record, - ): string | string[] | null { - if (hookType === 'listens') { - const data = (entry.data ?? entry) as Record; - return Object.values(data) - .map((v) => (v as Record)?.[CHUNK_KEY] as string) - .filter(Boolean); - } - - if (hookType === 'render') { - const renderFn = - (entry.data as Record)?.render ?? entry; - return this.getQrlPath(renderFn as QRL); - } - - const data = (entry.data ?? entry) as Record; - const qrlObj = data[QRL_KEY] ?? data[COMPUTED_QRL_KEY]; - return this.getQrlPath(qrlObj as QRL); - } - - private getQrlPath(qrl: QRL | null | undefined): string | null { - if (!qrl) return null; - - const qrlAny = qrl as unknown as Record; - if (qrlAny.dev) { - return (qrlAny.dev as Record).filename; - } - return qrlAny[CHUNK_KEY] as string | null; - } -} - -/** - * Get the chunk name from a QRL for component identification - */ -export function getQrlChunkName(qrl: QRL): string { - const splitPoint = '_component'; - const qrlAny = qrl as unknown as Record; - const chunk = qrlAny[CHUNK_KEY] as string | undefined; - return chunk?.split(splitPoint)?.[0] ?? ''; -} - -// Singleton instance for global access (can be replaced with context in the future) -let storeInstance: HookDataStore | null = null; - -export function getHookDataStore(): HookDataStore { - if (!storeInstance) { - storeInstance = new HookDataStore(); - } - return storeInstance; -} - -export function resetHookDataStore(): void { - storeInstance = new HookDataStore(); -} - diff --git a/packages/ui/src/features/RenderTree/RenderTree.tsx b/packages/ui/src/features/RenderTree/RenderTree.tsx index 54efd38..d441253 100644 --- a/packages/ui/src/features/RenderTree/RenderTree.tsx +++ b/packages/ui/src/features/RenderTree/RenderTree.tsx @@ -136,9 +136,12 @@ export const RenderTree = component$(() => { codes.value = []; - const res = await rpc?.getModulesByPathIds(hookStore.value.findAllQrlPaths()); + const res = + (await rpc?.getModulesByPathIds(hookStore.value.findAllQrlPaths())) ?? []; log('getModulesByPathIds return: %O', res); - codes.value = res.filter((item) => item.modules); + codes.value = res.filter( + (item: { pathId: string; modules: unknown; error?: string }) => item.modules + ); stateTree.value = hookStore.value.buildTree() as TreeNode[]; hookFilters.value = hookStore.value.getFilterList(); }); diff --git a/packages/ui/src/features/RenderTree/data.ts b/packages/ui/src/features/RenderTree/data.ts index 23d1785..5c6e705 100644 --- a/packages/ui/src/features/RenderTree/data.ts +++ b/packages/ui/src/features/RenderTree/data.ts @@ -3,16 +3,9 @@ import { INNER_USE_HOOK, QRL_KEY, } from '@devtools/kit'; -import type { ParsedStructure } from '@devtools/kit'; +import type { ParsedStructure, ComponentDevtoolsState, DevtoolsRenderStats } from '@devtools/kit'; import type { QRLInternal } from './types'; -// Extend Window interface to include QWIK_DEVTOOLS_GLOBAL_STATE -declare global { - interface Window { - QWIK_DEVTOOLS_GLOBAL_STATE?: Record; - } -} - /** * Sequence entry from Qwik's q:seq containing QRL references. * Can have either $qrl$ (for tasks) or $computeQrl$ (for computed). @@ -50,10 +43,36 @@ export function getQwikState(qrlChunkName: string): ParsedStructure[] { if (!matchingKey) return []; - const entries = globalState[matchingKey] ?? []; + const componentState = globalState[matchingKey]; + if (!componentState) return []; + + // 新结构:{ hooks: ParsedStructure[], stats: DevtoolsRenderStats } + const entries = componentState.hooks ?? []; return entries.filter((item) => item.data !== undefined); } +/** + * Get render stats from global devtools state by QRL chunk name + */ +export function getRenderStats(qrlChunkName: string): DevtoolsRenderStats | null { + const globalState = window.QWIK_DEVTOOLS_GLOBAL_STATE ?? {}; + const matchingKey = Object.keys(globalState).find((key) => + key.endsWith(qrlChunkName), + ); + + if (!matchingKey) return null; + + const componentState = globalState[matchingKey]; + return componentState?.stats ?? null; +} + +/** + * Get all component states from global devtools state + */ +export function getAllComponentStates(): Record { + return window.QWIK_DEVTOOLS_GLOBAL_STATE ?? {}; +} + /** * Determine hook type from QRL chunk path */ diff --git a/packages/ui/src/features/RenderTree/index.ts b/packages/ui/src/features/RenderTree/index.ts index eea114d..ef6b976 100644 --- a/packages/ui/src/features/RenderTree/index.ts +++ b/packages/ui/src/features/RenderTree/index.ts @@ -22,24 +22,11 @@ export { isQRLInternal, } from './types'; -// Data store -export { - HookDataStore, - getHookDataStore, - resetHookDataStore, - getQrlChunkName, -} from './HookDataStore'; - // Tree builder export { TreeBuilder } from './TreeBuilder'; // Data utilities -export { - getQwikState, - filterUserDefinedHooks, - transformQrlSequenceData, -} from './data'; +export { getQwikState, getRenderStats, getAllComponentStates, filterUserDefinedHooks, transformQrlSequenceData } from './data'; // Hook store (class-based API) export { HookStore, QrlUtils, getHookStore } from './formatTreeData'; - diff --git a/packages/ui/src/features/RenderTree/transfromqseq.ts b/packages/ui/src/features/RenderTree/transfromqseq.ts deleted file mode 100644 index 399aa1a..0000000 --- a/packages/ui/src/features/RenderTree/transfromqseq.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { TreeNode } from '../../components/Tree/Tree'; -import { TreeBuilder } from './TreeBuilder'; - -/** - * Shared TreeBuilder instance for backward compatibility - */ -const builder = new TreeBuilder(); - -/** - * Convert object to TreeNode array - * @deprecated Use TreeBuilder.objectToTree() directly instead - */ -export const objectToTree = (obj: unknown, parentPath = ''): TreeNode[] => { - return builder.objectToTree(obj, parentPath); -}; - -/** - * Create a group TreeNode with label and children - * @deprecated Use TreeBuilder.createGroupNode() directly instead - */ -export const createTreeNodeObj = ( - label: string, - children: TreeNode[] = [], -): TreeNode => { - return builder.createGroupNode(label, children); -}; - -/** - * Reset the internal ID counter - * Useful for testing to get deterministic IDs - */ -export const resetIdCounter = (): void => { - builder.resetIdCounter(); -}; diff --git a/packages/ui/src/types/state.ts b/packages/ui/src/types/state.ts index b472d61..81c8ce5 100644 --- a/packages/ui/src/types/state.ts +++ b/packages/ui/src/types/state.ts @@ -10,7 +10,8 @@ export type TabName = | 'components' | 'inspect' | 'renderTree' - | 'codeBreack'; + | 'codeBreack' + | 'performance'; export interface State { isOpen: Signal; From 830072d2e384faa680f3fca99f1787c7eb6a3c39 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Thu, 18 Dec 2025 17:07:43 +0800 Subject: [PATCH 25/30] add changelog --- .changeset/mighty-windows-begin.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/mighty-windows-begin.md diff --git a/.changeset/mighty-windows-begin.md b/.changeset/mighty-windows-begin.md new file mode 100644 index 0000000..8ee096c --- /dev/null +++ b/.changeset/mighty-windows-begin.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/devtools': patch +--- + +add performance tab From b4c980800a962dbf628908070bf959b6f0eaf66c Mon Sep 17 00:00:00 2001 From: Giorgio Boa <35845425+gioboa@users.noreply.github.com> Date: Thu, 18 Dec 2025 11:09:15 +0100 Subject: [PATCH 26/30] chore: fix up changeset --- .changeset/mighty-windows-begin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/mighty-windows-begin.md b/.changeset/mighty-windows-begin.md index 8ee096c..523bd12 100644 --- a/.changeset/mighty-windows-begin.md +++ b/.changeset/mighty-windows-begin.md @@ -2,4 +2,4 @@ '@qwik.dev/devtools': patch --- -add performance tab +feat: add performance tab From bad4d7c6cfc97e1a731582fedd4c1188a7f3e471 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Fri, 19 Dec 2025 13:10:45 +0800 Subject: [PATCH 27/30] feat: add dependency status tracking and refresh functionality - Introduced `getDependenciesStatus` and `refreshDependencies` methods to track and manage the state of dependencies. - Enhanced `ServerFunctions` interface with new methods for dependency management. - Updated the `QwikDevtools` component to improve data loading and error handling for assets, components, routes, and Qwik packages. - Refactored dependency preloading logic to support better concurrency and error handling. - Adjusted the `QwikRouterProvider` to disable view transitions for improved stability. --- packages/kit/src/types.ts | 9 + packages/playgrounds/src/root.tsx | 2 +- packages/plugin/src/npm/index.ts | 497 ++++++++++-------- .../virtualmodules/perfLazyWrapperPreamble.ts | 66 ++- .../plugin/src/virtualmodules/perfRuntime.ts | 5 - .../src/virtualmodules/qwikComponentProxy.ts | 36 +- packages/ui/src/devtools.tsx | 132 +++-- 7 files changed, 387 insertions(+), 360 deletions(-) diff --git a/packages/kit/src/types.ts b/packages/kit/src/types.ts index 2e2be80..bb27cd8 100644 --- a/packages/kit/src/types.ts +++ b/packages/kit/src/types.ts @@ -14,6 +14,15 @@ export interface ServerFunctions { getRoutes: () => any; getQwikPackages: () => Promise<[string, string][]>; getAllDependencies: () => Promise; + getDependenciesStatus: () => Promise<{ + phase: 'idle' | 'phase1' | 'phase2' | 'done' | 'error'; + loaded: number; + total: number; + startedAt: number | null; + finishedAt: number | null; + error?: string; + }>; + refreshDependencies: () => Promise; installPackage: ( packageName: string, isDev?: boolean, diff --git a/packages/playgrounds/src/root.tsx b/packages/playgrounds/src/root.tsx index 55dce1c..83c7f14 100644 --- a/packages/playgrounds/src/root.tsx +++ b/packages/playgrounds/src/root.tsx @@ -16,7 +16,7 @@ export default component$(() => { */ return ( - + {!isDev && ( diff --git a/packages/plugin/src/npm/index.ts b/packages/plugin/src/npm/index.ts index c348a01..27a9d6e 100644 --- a/packages/plugin/src/npm/index.ts +++ b/packages/plugin/src/npm/index.ts @@ -3,270 +3,294 @@ import fsp from 'node:fs/promises'; import { NpmInfo } from '@devtools/kit'; import { execSync } from 'child_process'; import path from 'path'; -import {debug} from 'debug' +import { debug } from 'debug'; const log = debug('qwik:devtools:npm'); -// In-memory cache for npm package information -interface CacheEntry { - data: any; - timestamp: number; + +/** + * This module intentionally favors readability and non-blocking behavior: + * - Phase1: fast local scan (node_modules//package.json) with limited concurrency. + * - Phase2: best-effort background enrich (optional small registry lookup). + * - RPC calls NEVER wait for heavy work (getAllDependencies returns immediately). + */ + +// ----------------------------- +// Types & state +// ----------------------------- + +type DependenciesPhase = 'idle' | 'phase1' | 'phase2' | 'done' | 'error'; + +export interface DependenciesStatus { + phase: DependenciesPhase; + loaded: number; + total: number; + startedAt: number | null; + finishedAt: number | null; + error?: string; } -const packageCache = new Map(); -const CACHE_TTL = 1000 * 60 * 30; // 30 minutes cache TTL +interface DependencyInfo { + name: string; + version: string; + description: string; + author?: any; + homepage?: string; + repository?: string; + npmUrl: string; + iconUrl: string | null; +} -// Preloaded dependencies cache - loaded at server startup -let preloadedDependencies: any[] | null = null; +let preloadedDependencies: DependencyInfo[] | null = null; let isPreloading = false; -let preloadPromise: Promise | null = null; +let preloadPromise: Promise | null = null; -function getCachedPackage(name: string): any | null { - const cached = packageCache.get(name); - if (cached && Date.now() - cached.timestamp < CACHE_TTL) { - return cached.data; - } - packageCache.delete(name); - return null; -} +let dependenciesStatus: DependenciesStatus = { + phase: 'idle', + loaded: 0, + total: 0, + startedAt: null, + finishedAt: null, +}; -function setCachedPackage(name: string, data: any): void { - packageCache.set(name, { - data, - timestamp: Date.now(), - }); +// ----------------------------- +// Small utilities (kept minimal) +// ----------------------------- + +async function fileExists(filePath: string): Promise { + try { + await fsp.access(filePath); + return true; + } catch { + return false; + } } -async function findNearestFileUp(startDir: string, fileName: string): Promise { +async function readJsonFile(filePath: string): Promise { try { - let currentDir = path.resolve(startDir); - // Guard against infinite loops by capping directory ascents - for (let i = 0; i < 100; i++) { - const candidate = path.join(currentDir, fileName); - const exists = await fsp - .access(candidate) - .then(() => true) - .catch(() => false); - if (exists) return candidate; - - const parent = path.dirname(currentDir); - if (parent === currentDir) break; - currentDir = parent; - } - return null; + const content = await fsp.readFile(filePath, 'utf-8'); + return JSON.parse(content); } catch { return null; } } +async function findNearestFileUp(startDir: string, fileName: string): Promise { + let currentDir = path.resolve(startDir); + for (let i = 0; i < 100; i++) { + const candidate = path.join(currentDir, fileName); + if (await fileExists(candidate)) return candidate; + const parent = path.dirname(currentDir); + if (parent === currentDir) break; + currentDir = parent; + } + return null; +} + function getProjectStartDirFromConfig(config: any): string { - // Prefer Vite's resolved root; fallback to the directory of the config file; finally cwd if (config?.root) return config.root; if (config?.configFile) return path.dirname(config.configFile); return process.cwd(); } +function nodeModulesPackageJsonPath(projectRoot: string, name: string): string { + return path.join(projectRoot, 'node_modules', ...name.split('/'), 'package.json'); +} + +function normalizeRepositoryUrl(repository: any): string | undefined { + const url = typeof repository === 'string' ? repository : repository?.url; + if (!url || typeof url !== 'string') return undefined; + return url + .replace(/^git\+/, '') + .replace(/^ssh:\/\/git@/, 'https://') + .replace(/\.git$/, ''); +} + +function guessIconUrl(name: string, repositoryUrl?: string): string | null { + if (name.startsWith('@')) { + const scope = name.split('/')[0].substring(1); + return `https://avatars.githubusercontent.com/${scope}?size=64`; + } + if (repositoryUrl?.includes('github.com')) { + const match = repositoryUrl.match(/github\.com\/([^\/]+)/); + if (match) return `https://avatars.githubusercontent.com/${match[1]}?size=64`; + } + return null; +} + +function deferToEventLoop(): Promise { + return new Promise((resolve) => setImmediate(resolve)); +} + +async function mapLimit( + items: T[], + concurrency: number, + fn: (item: T, index: number) => Promise, +): Promise { + if (items.length === 0) return []; + const results = new Array(items.length); + let cursor = 0; + const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => { + while (true) { + const i = cursor++; + if (i >= items.length) return; + results[i] = await fn(items[i], i); + } + }); + await Promise.all(workers); + return results; +} + export async function detectPackageManager( projectRoot: string, ): Promise<'npm' | 'pnpm' | 'yarn'> { - try { - if ( - await fsp - .access(path.join(projectRoot, 'pnpm-lock.yaml')) - .then(() => true) - .catch(() => false) - ) { - return 'pnpm'; - } - if ( - await fsp - .access(path.join(projectRoot, 'yarn.lock')) - .then(() => true) - .catch(() => false) - ) { - return 'yarn'; - } - if ( - await fsp - .access(path.join(projectRoot, 'package-lock.json')) - .then(() => true) - .catch(() => false) - ) { - return 'npm'; - } - return 'pnpm'; // default to pnpm if no lockfile found - } catch { - return 'pnpm'; - } + if (await fileExists(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm'; + if (await fileExists(path.join(projectRoot, 'yarn.lock'))) return 'yarn'; + if (await fileExists(path.join(projectRoot, 'package-lock.json'))) return 'npm'; + return 'pnpm'; } -// Preload dependencies function - moved to module scope -const preloadDependencies = async (config: any): Promise => { - if (preloadedDependencies) { - log('[Qwik DevTools] Dependencies already preloaded'); - return preloadedDependencies; - } +// ----------------------------- +// Dependencies preload (Phase1 + Phase2) +// ----------------------------- - if (isPreloading && preloadPromise) { - log('[Qwik DevTools] Preloading already in progress...'); - return preloadPromise; - } +async function phase1LocalIndex(projectRoot: string, deps: [string, string][]): Promise { + const localConcurrency = 16; + + return mapLimit(deps, localConcurrency, async ([name, requestedVersion]) => { + const pkgJsonPath = nodeModulesPackageJsonPath(projectRoot, name); + const installedPkg = await readJsonFile(pkgJsonPath); + + const version = installedPkg?.version || requestedVersion; + const repository = normalizeRepositoryUrl(installedPkg?.repository); + const iconUrl = guessIconUrl(name, repository); + + const info: DependencyInfo = { + name, + version, + description: installedPkg?.description || 'No description available', + author: installedPkg?.author, + homepage: installedPkg?.homepage, + repository, + npmUrl: `https://www.npmjs.com/package/${name}`, + iconUrl, + }; + + dependenciesStatus.loaded++; + if (dependenciesStatus.loaded % 50 === 0) await deferToEventLoop(); + + return info; + }); +} + +async function phase2BackgroundEnrich(deps: DependencyInfo[]): Promise { + const targets = deps.filter( + (p) => !p.repository || !p.iconUrl || p.description === 'No description available', + ); + + const enrichConcurrency = 6; + await mapLimit(targets, enrichConcurrency, async (p) => { + // local enrich first + const repo = normalizeRepositoryUrl(p.repository); + if (repo && repo !== p.repository) p.repository = repo; + if (!p.iconUrl) p.iconUrl = guessIconUrl(p.name, p.repository); + + // optional small registry lookup for missing description/repo + if (!p.repository || p.description === 'No description available') { + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 1500); + const res = await fetch( + `https://registry.npmjs.org/${encodeURIComponent(p.name)}/${encodeURIComponent(p.version)}`, + { headers: { Accept: 'application/json' }, signal: controller.signal }, + ); + clearTimeout(timeoutId); + + if (res.ok) { + const data = await res.json(); + if (!p.repository) p.repository = normalizeRepositoryUrl(data?.repository); + if (p.description === 'No description available' && data?.description) { + p.description = data.description; + } + if (!p.iconUrl) p.iconUrl = guessIconUrl(p.name, p.repository); + } + } catch { + // ignore + } + } + + await deferToEventLoop(); + return p; + }); +} + +async function preloadDependencies(config: any): Promise { + if (preloadedDependencies) return preloadedDependencies; + if (isPreloading && preloadPromise) return preloadPromise; isPreloading = true; - log('[Qwik DevTools] Starting to preload dependencies...'); - + dependenciesStatus = { + phase: 'phase1', + loaded: 0, + total: 0, + startedAt: Date.now(), + finishedAt: null, + }; + preloadPromise = (async () => { const startDir = getProjectStartDirFromConfig(config); - const pathToPackageJson = await findNearestFileUp(startDir, 'package.json'); - - if (!pathToPackageJson) { + const packageJsonPath = await findNearestFileUp(startDir, 'package.json'); + if (!packageJsonPath) { preloadedDependencies = []; + dependenciesStatus.phase = 'done'; + dependenciesStatus.finishedAt = Date.now(); isPreloading = false; - log('[Qwik DevTools] No package.json found'); return []; } + const projectRoot = path.dirname(packageJsonPath); + const pkg = await readJsonFile(packageJsonPath); + + const allDeps = { + ...(pkg?.dependencies || {}), + ...(pkg?.devDependencies || {}), + ...(pkg?.peerDependencies || {}), + }; + const entries = Object.entries(allDeps); + dependenciesStatus.total = entries.length; + try { - const pkgJson = await fsp.readFile(pathToPackageJson, 'utf-8'); - const pkg = JSON.parse(pkgJson); - - const allDeps = { - ...pkg.dependencies || {}, - ...pkg.devDependencies || {}, - ...pkg.peerDependencies || {}, - }; + const list = await phase1LocalIndex(projectRoot, entries); + preloadedDependencies = list; + dependenciesStatus.phase = 'phase2'; - const dependencies = Object.entries(allDeps); - - // Check cache first - const cachedPackages: any[] = []; - const uncachedDependencies: [string, string][] = []; - - for (const [name, version] of dependencies) { - const cached = getCachedPackage(name); - if (cached) { - cachedPackages.push({ ...cached, version }); - } else { - uncachedDependencies.push([name, version]); - } - } - - if (uncachedDependencies.length === 0) { - preloadedDependencies = cachedPackages; + // Phase2 runs truly in background; never blocks Phase1 result. + void (async () => { + try { + await phase2BackgroundEnrich(list); + dependenciesStatus.phase = 'done'; + } catch (e) { + dependenciesStatus.phase = 'error'; + dependenciesStatus.error = e instanceof Error ? e.message : String(e); + } finally { + dependenciesStatus.finishedAt = Date.now(); isPreloading = false; - return cachedPackages; - } - - // Load all dependencies - use larger batch for initial preload - const batchSize = 100; - const batches = []; - for (let i = 0; i < uncachedDependencies.length; i += batchSize) { - batches.push(uncachedDependencies.slice(i, i + batchSize)); } + })(); - const fetchedPackages: any[] = []; - - log(`[Qwik DevTools] Fetching ${uncachedDependencies.length} packages in parallel...`); - - const allBatchPromises = batches.map(async (batch) => { - const batchPromises = batch.map(async ([name, version]) => { - try { - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 5000); // Longer timeout for initial load - - const response = await fetch(`https://registry.npmjs.org/${name}`, { - headers: { - 'Accept': 'application/json', - }, - signal: controller.signal, - }); - - clearTimeout(timeoutId); - - if (!response.ok) { - throw new Error(`HTTP ${response.status}`); - } - - const packageData = await response.json(); - - const latestVersion = packageData['dist-tags']?.latest || version; - const versionData = packageData.versions?.[latestVersion] || packageData.versions?.[version]; - - let repositoryUrl = versionData?.repository?.url || packageData.repository?.url; - if (repositoryUrl) { - repositoryUrl = repositoryUrl - .replace(/^git\+/, '') - .replace(/^ssh:\/\/git@/, 'https://') - .replace(/\.git$/, ''); - } - - let iconUrl = null; - - if (packageData.logo) { - iconUrl = packageData.logo; - } else if (name.startsWith('@')) { - const scope = name.split('/')[0].substring(1); - iconUrl = `https://avatars.githubusercontent.com/${scope}?size=64`; - } else if (repositoryUrl?.includes('github.com')) { - const repoMatch = repositoryUrl.match(/github\.com\/([^\/]+)/); - if (repoMatch) { - iconUrl = `https://avatars.githubusercontent.com/${repoMatch[1]}?size=64`; - } - } - - const packageInfo = { - name, - version, - description: versionData?.description || packageData.description || 'No description available', - author: versionData?.author || packageData.author, - homepage: versionData?.homepage || packageData.homepage, - repository: repositoryUrl, - npmUrl: `https://www.npmjs.com/package/${name}`, - iconUrl, - }; - - setCachedPackage(name, packageInfo); - return packageInfo; - } catch (error) { - const basicInfo = { - name, - version, - description: 'No description available', - npmUrl: `https://www.npmjs.com/package/${name}`, - iconUrl: null, - }; - - setCachedPackage(name, basicInfo); - return basicInfo; - } - }); - - const batchResults = await Promise.allSettled(batchPromises); - return batchResults - .filter((result): result is PromiseFulfilledResult => result.status === 'fulfilled') - .map(result => result.value); - }); - - const allBatchResults = await Promise.all(allBatchPromises); - for (const batchResult of allBatchResults) { - fetchedPackages.push(...batchResult); - } - - const allPackages = [...cachedPackages, ...fetchedPackages]; - preloadedDependencies = allPackages; - isPreloading = false; - - log(`[Qwik DevTools] ✓ Successfully preloaded ${allPackages.length} dependencies`); - - return allPackages; - } catch (error) { - log('[Qwik DevTools] ✗ Failed to preload dependencies:', error); - preloadedDependencies = []; - isPreloading = false; - return []; - } - })(); + log(`[Qwik DevTools] ✓ Phase1 preloaded ${list.length} dependencies (local-first)`); + return list; + } catch (e) { + preloadedDependencies = []; + dependenciesStatus.phase = 'error'; + dependenciesStatus.error = e instanceof Error ? e.message : String(e); + dependenciesStatus.finishedAt = Date.now(); + isPreloading = false; + log('[Qwik DevTools] ✗ Failed to preload dependencies (local-first):', e); + return []; + } + })(); - return preloadPromise; + return preloadPromise; }; // Export function to start preloading from plugin initialization @@ -294,8 +318,7 @@ export function getNpmFunctions({ config }: ServerContext) { if (!pathToPackageJson) return []; try { - const pkgJson = await fsp.readFile(pathToPackageJson, 'utf-8'); - const pkg = JSON.parse(pkgJson); + const pkg = await readJsonFile(pathToPackageJson); return Object.entries(pkg.devDependencies).filter(([key]) => /@qwik/i.test(key), ); @@ -311,15 +334,31 @@ export function getNpmFunctions({ config }: ServerContext) { return preloadedDependencies; } - // If preloading is in progress, wait for it - if (isPreloading && preloadPromise) { - log('[Qwik DevTools] Waiting for preload to complete...'); - return preloadPromise; - } + // If preloading is in progress, NEVER wait (avoid blocking the whole dev server / UI). + if (isPreloading) return []; // If preloading hasn't started (shouldn't happen), start it now log('[Qwik DevTools] Warning: Preload not started, starting now...'); - return preloadDependencies(config); + void preloadDependencies(config); + return []; + }, + + async getDependenciesStatus() { + return dependenciesStatus; + }, + + async refreshDependencies(): Promise { + preloadedDependencies = null; + isPreloading = false; + preloadPromise = null; + dependenciesStatus = { + phase: 'idle', + loaded: 0, + total: 0, + startedAt: null, + finishedAt: null, + }; + void preloadDependencies(config); }, async installPackage( diff --git a/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts b/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts index 4134ee0..1698bc4 100644 --- a/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts +++ b/packages/plugin/src/virtualmodules/perfLazyWrapperPreamble.ts @@ -9,40 +9,50 @@ const perfLazyWrapperPreamble = `${perfRuntime} // [qwik-component-proxy] Render function wrapper const __qwik_wrap__ = (fn, name, viteId) => { + if (typeof fn !== 'function') return fn; let renderCount = 0; - return function (...args) { + + function wrapped(...args) { renderCount += 1; const phase = __qwik_perf_is_server__() ? 'ssr' : 'csr'; const start = performance.now(); - try { - const result = fn.apply(this, args); - const duration = performance.now() - start; - __qwik_perf_commit__({ - component: name, - phase, - duration, - start, - end: start + duration, - viteId, - renderCount, - }); - return result; - } catch (err) { - const duration = performance.now() - start; - __qwik_perf_commit__({ - component: name, - phase, - duration, - start, - end: start + duration, - error: __qwik_perf_to_error__(err), - viteId, - renderCount, - }); - throw err; - } + const result = fn.apply(this, args); + const duration = performance.now() - start; + __qwik_perf_commit__({ + component: name, + phase, + duration, + start, + end: start + duration, + viteId, + renderCount, + }); + return result; + } + + // Preserve Qwik-compiler metadata attached to the original function. + // (No try/catch per request; avoid touching special function props.) + const skip = { + length: true, + name: true, + arguments: true, + caller: true, + prototype: true, }; + + const descriptors = Object.getOwnPropertyDescriptors(fn); + for (const key of Object.keys(descriptors)) { + if (skip[key]) continue; + Object.defineProperty(wrapped, key, descriptors[key]); + } + + for (const sym of Object.getOwnPropertySymbols(fn)) { + const desc = Object.getOwnPropertyDescriptor(fn, sym); + if (desc) Object.defineProperty(wrapped, sym, desc); + } + + return wrapped; }; `; diff --git a/packages/plugin/src/virtualmodules/perfRuntime.ts b/packages/plugin/src/virtualmodules/perfRuntime.ts index 1d33067..fee189e 100644 --- a/packages/plugin/src/virtualmodules/perfRuntime.ts +++ b/packages/plugin/src/virtualmodules/perfRuntime.ts @@ -23,11 +23,6 @@ const __qwik_perf_init_csr__ = () => { const __qwik_perf_get_ssr_store__ = () => typeof process !== 'undefined' && process ? process : globalThis; -const __qwik_perf_to_error__ = (err) => ({ - name: (err && err.name) || 'Error', - message: err && err.message ? String(err.message) : String(err), -}); - const __qwik_perf_next_id__ = (perf) => { perf._id = (perf._id || 0) + 1; return perf._id; diff --git a/packages/plugin/src/virtualmodules/qwikComponentProxy.ts b/packages/plugin/src/virtualmodules/qwikComponentProxy.ts index ed19b82..eb43230 100644 --- a/packages/plugin/src/virtualmodules/qwikComponentProxy.ts +++ b/packages/plugin/src/virtualmodules/qwikComponentProxy.ts @@ -18,31 +18,17 @@ function componentQrl(qrl, options) { if(qrl.dev){ viteId = qrl.dev.file.replace(/[^/]*$/, qrl.dev.displayName); } - try { - const result = originalComponentQrl(qrl, options); - const duration = performance.now() - start; - __qwik_perf_commit_componentqrl__({ - component, - phase, - duration, - start, - viteId, - end: start + duration, - }); - return result; - } catch (err) { - const duration = performance.now() - start; - __qwik_perf_commit_componentqrl__({ - component, - phase, - duration, - start, - viteId, - end: start + duration, - error: __qwik_perf_to_error__(err), - }); - throw err; - } + const result = originalComponentQrl(qrl, options); + const duration = performance.now() - start; + __qwik_perf_commit_componentqrl__({ + component, + phase, + duration, + start, + viteId, + end: start + duration, + }); + return result; } export { componentQrl }; diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index f887059..2dd0a84 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -51,6 +51,25 @@ function getClientRpcFunctions() { }; } +function toDevtoolsRoutes(routes: any): RoutesInfo[] { + const children: RoutesInfo[] = routes?.children || []; + const directories: RoutesInfo[] = children.filter( + (child) => child.type === RouteType.DIRECTORY, + ); + + return [ + { + relativePath: '', + name: 'index', + type: RouteType.DIRECTORY, + path: '', + isSymbolicLink: false, + children: undefined, + }, + ...directories, + ]; +} + export const QwikDevtools = component$(() => { useStyles$(globalCss); const state = useStore({ @@ -64,8 +83,6 @@ export const QwikDevtools = component$(() => { isLoadingDependencies: false, }); - const clientReady = useSignal(false); - useVisibleTask$(async () => { const hot = await tryCreateHotContext(undefined, ['/']); if (!hot) { @@ -74,87 +91,58 @@ export const QwikDevtools = component$(() => { setViteClientContext(hot); createClientRpc(getClientRpcFunctions()); - clientReady.value = true; - }); - useVisibleTask$(async ({ track }) => { - track(() => clientReady.value); - if (!clientReady.value) return; const rpc = getViteClientRpc(); - try { - const assets = await rpc.getAssetsFromPublicDir(); - state.assets = assets; - } catch (error) { - log('Failed to load assets:', error); - } - }); - useVisibleTask$(async ({ track }) => { - track(() => clientReady.value); - if (!clientReady.value) return; - const rpc = getViteClientRpc(); - try { - const components = await rpc.getComponents(); - state.components = components; - } catch (error) { - log('Failed to load components:', error); - } - }); + // Group 1: load most data in parallel, each failure is isolated. + const group1 = Promise.allSettled([ + rpc.getAssetsFromPublicDir(), + rpc.getComponents(), + rpc.getRoutes(), + rpc.getQwikPackages(), + ]); - useVisibleTask$(async ({ track }) => { - track(() => clientReady.value); - if (!clientReady.value) return; - const rpc = getViteClientRpc(); - try { - const routes = await rpc.getRoutes(); - const children: RoutesInfo[] = routes?.children || []; - const directories: RoutesInfo[] = children.filter( - (child) => child.type === 'directory', - ); + // Group 2: load dependencies separately to keep a dedicated loading state. + state.isLoadingDependencies = true; + const depsPromise = rpc + .getAllDependencies() + .then((allDeps) => { + state.allDependencies = allDeps; + }) + .catch((error) => { + log('Failed to load all dependencies:', error); + }) + .finally(() => { + state.isLoadingDependencies = false; + }); - const values: RoutesInfo[] = [ - { - relativePath: '', - name: 'index', - type: RouteType.DIRECTORY, - path: '', - isSymbolicLink: false, - children: undefined, - }, - ...directories, - ]; + const [assetsRes, componentsRes, routesRes, packagesRes] = await group1; - state.routes = noSerialize(values); - } catch (error) { - log('Failed to load routes:', error); + if (assetsRes.status === 'fulfilled') { + state.assets = assetsRes.value; + } else { + log('Failed to load assets:', assetsRes.reason); } - }); - useVisibleTask$(async ({ track }) => { - track(() => clientReady.value); - if (!clientReady.value) return; - const rpc = getViteClientRpc(); - try { - const qwikPackages = await rpc.getQwikPackages(); - state.npmPackages = qwikPackages; - } catch (error) { - log('Failed to load Qwik packages:', error); + if (componentsRes.status === 'fulfilled') { + state.components = componentsRes.value; + } else { + log('Failed to load components:', componentsRes.reason); } - }); - useVisibleTask$(async ({ track }) => { - track(() => clientReady.value); - if (!clientReady.value) return; - const rpc = getViteClientRpc(); - state.isLoadingDependencies = true; - try { - const allDeps = await rpc.getAllDependencies(); - state.allDependencies = allDeps; - } catch (error) { - log('Failed to load all dependencies:', error); - } finally { - state.isLoadingDependencies = false; + if (routesRes.status === 'fulfilled') { + state.routes = noSerialize(toDevtoolsRoutes(routesRes.value)); + } else { + log('Failed to load routes:', routesRes.reason); } + + if (packagesRes.status === 'fulfilled') { + state.npmPackages = packagesRes.value; + } else { + log('Failed to load Qwik packages:', packagesRes.reason); + } + + await depsPromise; }); return ( From 489b224850bca38dc2ca00d1f124bc678558aafc Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Fri, 19 Dec 2025 13:12:18 +0800 Subject: [PATCH 28/30] fix(plugin): preserve Qwik lazy render metadata when wrapping components --- .changeset/selfish-houses-film.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/selfish-houses-film.md diff --git a/.changeset/selfish-houses-film.md b/.changeset/selfish-houses-film.md new file mode 100644 index 0000000..c61cc0c --- /dev/null +++ b/.changeset/selfish-houses-film.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/devtools': patch +--- + +fix(plugin): preserve Qwik lazy render metadata when wrapping components From 967021dfaecab07c6393477198f155e87eee5069 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Fri, 19 Dec 2025 13:24:06 +0800 Subject: [PATCH 29/30] solve conflict --- .../src/virtualmodules/qwikComponentProxy.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/plugin/src/virtualmodules/qwikComponentProxy.ts b/packages/plugin/src/virtualmodules/qwikComponentProxy.ts index e69de29..eb43230 100644 --- a/packages/plugin/src/virtualmodules/qwikComponentProxy.ts +++ b/packages/plugin/src/virtualmodules/qwikComponentProxy.ts @@ -0,0 +1,39 @@ +/** + * Virtual module source for perf tracking of Qwik's `componentQrl`. + * + * This module is loaded via the devtools plugin virtual-module registry + * (`virtualmodules/virtualModules.ts`) and is imported from: + * - `virtual:qwik-component-proxy` + */ +import perfRuntime from './perfRuntime'; + +const qwikComponentProxy = `${perfRuntime} +import { componentQrl as originalComponentQrl } from '@qwik.dev/core'; + +function componentQrl(qrl, options) { + const phase = __qwik_perf_is_server__() ? 'ssr' : 'csr'; + const start = performance.now(); + let viteId = null; + const component = qrl?.getSymbol?.() || qrl?.$symbol$ || 'unknown'; + if(qrl.dev){ + viteId = qrl.dev.file.replace(/[^/]*$/, qrl.dev.displayName); + } + const result = originalComponentQrl(qrl, options); + const duration = performance.now() - start; + __qwik_perf_commit_componentqrl__({ + component, + phase, + duration, + start, + viteId, + end: start + duration, + }); + return result; +} + +export { componentQrl }; +`; + +export default qwikComponentProxy; + + From 3d997071e78967244cc67b481b3444359d51643b Mon Sep 17 00:00:00 2001 From: gioboa Date: Fri, 19 Dec 2025 07:49:50 +0100 Subject: [PATCH 30/30] chore: remove extra changeset --- .changeset/mighty-windows-begin.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/mighty-windows-begin.md diff --git a/.changeset/mighty-windows-begin.md b/.changeset/mighty-windows-begin.md deleted file mode 100644 index 523bd12..0000000 --- a/.changeset/mighty-windows-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@qwik.dev/devtools': patch ---- - -feat: add performance tab