Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/app/composables/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ export function useEnabledHintsFeatures(): Record<FeaturesName, boolean> {
return Object.fromEntries<boolean>(
Object.entries(config.features).map(([feature, flags]) => [
feature,
typeof flags === 'object' ? flags.devtools : Boolean(flags),
typeof flags === 'object' ? flags.devtools !== false : Boolean(flags),
] as [FeaturesName, boolean]),
) as Record<FeaturesName, boolean>
}

export function useHintsFeature(feature: FeaturesName): boolean {
const config = useHintsConfig()
return typeof config.features[feature] === 'object' ? config.features[feature].devtools : Boolean(config.features[feature])
return typeof config.features[feature] === 'object' ? config.features[feature].devtools !== false : Boolean(config.features[feature])
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,16 @@
"@nuxt/devtools-kit": "^3.2.2",
"@nuxt/kit": "^4.3.1",
"consola": "^3.4.2",
"defu": "^6.1.4",
"devalue": "^5.6.3",
"h3": "^1.15.5",
"html-validate": "^10.8.0",
"knitwork": "^1.3.0",
"magic-string": "^0.30.21",
"nitropack": "^2.13.1",
"oxc-parser": "^0.116.0",
"sirv": "^3.0.2",
"prettier": "^3.8.1",
"sirv": "^3.0.2",
"unplugin": "^3.0.0",
"unstorage": "^1.17.4",
"valibot": "^1.2.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 18 additions & 1 deletion src/features.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import type { ModuleOptions } from './module'
import type { FeaturesName } from './runtime/core/types'
import type { FeatureOptionsMap } from './runtime/feature-options'

export function isFeatureDevtoolsEnabled(options: ModuleOptions, feature: FeaturesName): boolean {
return typeof options.features[feature] === 'object' ? options.features[feature].devtools : !!options.features[feature]
const val = options.features[feature]
return typeof val === 'object' ? val.devtools !== false : !!val
}

export function isFeatureEnabled(options: ModuleOptions, feature: FeaturesName): boolean {
return !!options.features[feature]
}

/**
* Extract the per-feature options from the module config.
* Returns an empty object if the feature is set to a simple boolean.
*/
export function getFeatureOptions<K extends keyof FeatureOptionsMap>(
options: ModuleOptions,
feature: K,
): FeatureOptionsMap[K] {
const val = options.features[feature]
if (typeof val === 'object' && val.options) {
return val.options as FeatureOptionsMap[K]
}
return {} as FeatureOptionsMap[K]
}
4 changes: 2 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { HINTS_SSE_ROUTE } from './runtime/core/server/types'
import { setupDevToolsUI } from './devtools'
import { InjectHydrationPlugin } from './plugins/hydration'
import { LazyLoadHintPlugin } from './plugins/lazy-load'
import type { FeatureFlags, FeaturesName } from './runtime/core/types'
import type { Features } from './runtime/core/types'
import { isFeatureDevtoolsEnabled, isFeatureEnabled } from './features'

// Module options TypeScript interface definition
export interface ModuleOptions {
devtools: boolean
features: Record<FeaturesName, boolean | FeatureFlags>
features: Features
}

const moduleName = '@nuxt/hints'
Expand Down
13 changes: 11 additions & 2 deletions src/runtime/core/features.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
// @ts-expect-error virtual file
import { features } from '#hints-config'
import type { FeaturesName } from './types'
import type { FeatureOptionsMap } from '../feature-options'

export function isFeatureDevtoolsEnabled(feature: FeaturesName): boolean {
return typeof features[feature] === 'object' ? features[feature].devtools : !!features[feature]
return typeof features[feature] === 'object' ? features[feature].devtools !== false : !!features[feature]
}

export function isFeatureLogsEnabled(feature: FeaturesName): boolean {
return typeof features[feature] === 'object' ? features[feature].logs : !!features[feature]
return typeof features[feature] === 'object' ? features[feature].logs !== false : !!features[feature]
Comment on lines +7 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard object checks against null before property access.

Lines 7, 11, and 20 use typeof value === 'object' and then access fields. If a feature is null, this will throw at runtime.

Suggested fix
 export function isFeatureDevtoolsEnabled(feature: FeaturesName): boolean {
-  return typeof features[feature] === 'object' ? features[feature].devtools !== false : !!features[feature]
+  const value = features[feature]
+  return value && typeof value === 'object' ? value.devtools !== false : !!value
 }
 
 export function isFeatureLogsEnabled(feature: FeaturesName): boolean {
-  return typeof features[feature] === 'object' ? features[feature].logs !== false : !!features[feature]
+  const value = features[feature]
+  return value && typeof value === 'object' ? value.logs !== false : !!value
 }
@@
 export function getFeatureOptions<K extends keyof FeatureOptionsMap>(feature: K): FeatureOptionsMap[K] | undefined {
   const val = features[feature]
-  if (typeof val === 'object' && val.options) {
+  if (val && typeof val === 'object' && val.options) {
     return val.options as FeatureOptionsMap[K]
   }
   return undefined
 }

Also applies to: 18-23

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/core/features.ts` around lines 7 - 11, The object-type checks
access properties without guarding against null; update the conditions in
isFeatureLogsEnabled and the analogous function isFeatureDevtoolsEnabled (and
any similar checks in this file) to first ensure the feature value is not null
before testing typeof (e.g., use features[feature] !== null && typeof
features[feature] === 'object' or features[feature] != null && typeof ...), then
read .logs or .devtools as before so the expression preserves the original
boolean semantics but avoids a runtime crash when a feature is null.

}

export function isFeatureEnabled(feature: FeaturesName): boolean {
return !!features[feature]
}

export function getFeatureOptions<K extends keyof FeatureOptionsMap>(feature: K): FeatureOptionsMap[K] | undefined {
const val = features[feature]
if (typeof val === 'object' && val.options) {
return val.options as FeatureOptionsMap[K]
}
return undefined
}
21 changes: 15 additions & 6 deletions src/runtime/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import type { FeatureOptionsMap } from '../feature-options'

export type FeaturesName = 'hydration' | 'lazyLoad' | 'webVitals' | 'thirdPartyScripts' | 'htmlValidate'

export type FeatureFlags<T extends Record<string, any> = Record<string, never>> = {

Check failure on line 5 in src/runtime/core/types.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace explicit any in generic bound to fix lint failure.

Line 5 violates @typescript-eslint/no-explicit-any, which is currently failing CI.

Suggested fix
-export type FeatureFlags<T extends Record<string, any> = Record<string, never>> = {
+export type FeatureFlags<T extends Record<string, unknown> = Record<string, never>> = {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type FeatureFlags<T extends Record<string, any> = Record<string, never>> = {
export type FeatureFlags<T extends Record<string, unknown> = Record<string, never>> = {
🧰 Tools
🪛 GitHub Actions: ci

[error] 5-5: eslint error: Unexpected any. Specify a different type (@typescript-eslint/no-explicit-any)

🪛 GitHub Check: ci

[failure] 5-5:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/core/types.ts` at line 5, The generic type bound for FeatureFlags
uses an explicit any which violates lint; update the declaration of FeatureFlags
so the generic constraint uses unknown instead of any (e.g., change T extends
Record<string, any> to T extends Record<string, unknown> and keep the default as
Record<string, never>) so that the type remains equivalent but avoids
`@typescript-eslint/no-explicit-any`; modify the FeatureFlags<T ...> declaration
accordingly.

logs?: boolean
devtools?: boolean
/**
* Any feature specific options
*/
options?: T
}

/**
* FF used by modules options and to expose in the payload for devtools
* Fully-resolved features configuration type, where each feature
* can be a simple boolean or a FeatureFlags with its own options.
*/
export type FeatureFlags = {
logs: boolean
devtools: boolean
export type Features = {
[K in FeaturesName]: boolean | FeatureFlags<K extends keyof FeatureOptionsMap ? FeatureOptionsMap[K] : Record<string, never>>
}

export type Features = Record<FeaturesName, FeatureFlags>
9 changes: 9 additions & 0 deletions src/runtime/feature-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { HtmlValidateFeatureOptions } from './html-validate/types'
import type { ThirdPartyScriptsFeatureOptions } from './third-party-scripts/types'
import type { WebVitalsFeatureOptions } from './web-vitals/types'

export interface FeatureOptionsMap {
thirdPartyScripts: ThirdPartyScriptsFeatureOptions
htmlValidate: HtmlValidateFeatureOptions
webVitals: WebVitalsFeatureOptions
}
48 changes: 28 additions & 20 deletions src/runtime/html-validate/nitro.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
import type { NitroAppPlugin } from 'nitropack/types'
import { HtmlValidate } from 'html-validate'
import { HtmlValidate, type ConfigData, type RuleConfig } from 'html-validate'
import { addBeforeBodyEndTag } from './utils'
import { storage } from './storage'
import { randomUUID } from 'crypto'
import { stringify } from 'devalue'
import type { HtmlValidateReport } from './types'
import { format } from 'prettier/standalone'
import html from 'prettier/parser-html'
import { getFeatureOptions } from '../core/features'
import { defu } from 'defu'

const DEFAULT_EXTENDS = [
'html-validate:standard',
'html-validate:document',
'html-validate:browser',
]

const DEFAULT_RULES: RuleConfig = {
'svg-focusable': 'off',
'no-unknown-elements': 'error',
'void-style': 'off',
'no-trailing-whitespace': 'off',
// Conflict with Nuxt defaults
'require-sri': 'off',
'attribute-boolean-style': 'off',
'doctype-style': 'off',
// Unreasonable rule
'no-inline-style': 'off',
}

export default <NitroAppPlugin> function (nitro) {
const validator = new HtmlValidate({
extends: [
'html-validate:standard',
'html-validate:document',
'html-validate:browser',
],
rules: {
'svg-focusable': 'off',
'no-unknown-elements': 'error',
'void-style': 'off',
'no-trailing-whitespace': 'off',
// Conflict with Nuxt defaults
'require-sri': 'off',
'attribute-boolean-style': 'off',
'doctype-style': 'off',
// Unreasonable rule
'no-inline-style': 'off',
},
})
const opts: ConfigData = defu({

Check failure on line 33 in src/runtime/html-validate/nitro.plugin.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove trailing whitespace on Line 33 to clear CI style checks.

The current CI output flags trailing spaces here.

🧰 Tools
🪛 GitHub Check: ci

[failure] 33-33:
Trailing spaces not allowed

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/html-validate/nitro.plugin.ts` at line 33, Remove the trailing
whitespace after the object passed to defu when creating opts (the const opts:
ConfigData = defu({...}) expression) so the code contains no trailing spaces;
update the line in the nitro.plugin.ts file (around the defu call that
initializes opts) to eliminate the extra space at the end of the line to satisfy
CI style checks.

extends: DEFAULT_EXTENDS,
rules: DEFAULT_RULES,
}, getFeatureOptions('htmlValidate') ?? {})
Comment on lines +33 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

defu npm package function argument precedence which argument has priority

💡 Result:

In defu(object, ...defaults), the leftmost argument wins.

Priority order (highest → lowest):

  1. object (first argument)
  2. first item in defaults
  3. next item in defaults
  4. … last default (lowest)

So if the same key exists in multiple arguments, the earliest (leftmost) value is kept, and later arguments only fill in missing properties. [1]

Example: defu({ a: 2 }, { a: 1 }, { a: 0 }){ a: 2 } (because the first arg has priority). [1]

Source: UnJS defu docs. [1]

References:
[1] (unjs.pages.dev)

Citations:


🏁 Script executed:

find . -name "nitro.plugin.ts" -type f

Repository: nuxt/hints

Length of output: 227


🏁 Script executed:

cat -n ./src/runtime/html-validate/nitro.plugin.ts | head -50

Repository: nuxt/hints

Length of output: 2154


User htmlValidate options are shadowed by defaults due to defu argument order.

In defu(object, ...defaults), the first argument has priority. Currently, defaults are passed first, preventing user-provided options from getFeatureOptions('htmlValidate') from overriding them. This prevents customization of validation rules and extended configurations.

Suggested fix
-  const opts: ConfigData = defu({ 
-    extends: DEFAULT_EXTENDS,
-    rules: DEFAULT_RULES,
-  }, getFeatureOptions('htmlValidate') ?? {})
+  const opts: ConfigData = defu(getFeatureOptions('htmlValidate') ?? {}, {
+    extends: DEFAULT_EXTENDS,
+    rules: DEFAULT_RULES,
+  })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const opts: ConfigData = defu({
extends: DEFAULT_EXTENDS,
rules: DEFAULT_RULES,
}, getFeatureOptions('htmlValidate') ?? {})
const opts: ConfigData = defu(getFeatureOptions('htmlValidate') ?? {}, {
extends: DEFAULT_EXTENDS,
rules: DEFAULT_RULES,
})
🧰 Tools
🪛 GitHub Check: ci

[failure] 33-33:
Trailing spaces not allowed

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/html-validate/nitro.plugin.ts` around lines 33 - 36, The options
are being merged with defu in the wrong order so user options from
getFeatureOptions('htmlValidate') are shadowed by DEFAULT_EXTENDS/DEFAULT_RULES;
change the merge to pass the user options (getFeatureOptions('htmlValidate') ??
{}) as the first argument and the defaults ({ extends: DEFAULT_EXTENDS, rules:
DEFAULT_RULES }) as the subsequent argument so that user-provided values
override the defaults when building opts (ConfigData) using defu.


const validator = new HtmlValidate(opts)

nitro.hooks.hook('render:response', async (response, { event }) => {
if (typeof response.body === 'string' && (response.headers?.['Content-Type'] || response.headers?.['content-type'])?.includes('html')) {
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/html-validate/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import type { ConfigData } from 'html-validate'

export type HtmlValidateFeatureOptions = ConfigData

export type HtmlValidateReport = {
id: string
html: string
Expand Down
32 changes: 27 additions & 5 deletions src/runtime/third-party-scripts/plugin.client.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { defineNuxtPlugin, ref, useNuxtApp } from '#imports'
import { defu } from 'defu'
import { logger } from './utils'
import { getFeatureOptions } from '../core/features'
import type { ThirdPartyScriptsFeatureOptions } from './types'

Check failure on line 5 in src/runtime/third-party-scripts/plugin.client.ts

View workflow job for this annotation

GitHub Actions / ci

'ThirdPartyScriptsFeatureOptions' is defined but never used. Allowed unused vars must match /^_/u
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove unused ThirdPartyScriptsFeatureOptions import to unblock CI.

Line 5 is currently unused and reported by the lint job.

Suggested fix
-import type { ThirdPartyScriptsFeatureOptions } from './types'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { ThirdPartyScriptsFeatureOptions } from './types'
🧰 Tools
🪛 GitHub Check: ci

[failure] 5-5:
'ThirdPartyScriptsFeatureOptions' is defined but never used. Allowed unused vars must match /^_/u

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/third-party-scripts/plugin.client.ts` at line 5, Remove the
unused type import ThirdPartyScriptsFeatureOptions from plugin.client.ts; locate
the import statement "import type { ThirdPartyScriptsFeatureOptions } from
'./types'" and delete it (or remove ThirdPartyScriptsFeatureOptions from the
import list) so the file no longer references that unused symbol and the
linter/CI error is resolved.


const EXTENSIONS_SCHEMES_RE = /^(chrome-extension|moz-extension|safari-extension|ms-browser-extension):/
const DEFAULT_EXTENSION_SCHEMES = ['chrome-extension', 'moz-extension', 'safari-extension', 'ms-browser-extension']

function isExtensionScript(src: string) {
function buildExtensionSchemesRegex(schemes: string[]) {
return new RegExp(`^(${schemes.join('|')}):`)
Comment on lines +9 to +10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Escape configured schemes before interpolating into RegExp.

Lines 9–10 directly join config values into regex source. A scheme containing regex metacharacters can produce invalid patterns or unintended matches.

Suggested fix
+function escapeRegex(source: string): string {
+  return source.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+}
+
 function buildExtensionSchemesRegex(schemes: string[]) {
-  return new RegExp(`^(${schemes.join('|')}):`)
+  return new RegExp(`^(${schemes.map(escapeRegex).join('|')}):`)
 }
🧰 Tools
🪛 ast-grep (0.41.0)

[warning] 9-9: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^(${schemes.join('|')}):)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/third-party-scripts/plugin.client.ts` around lines 9 - 10, The
function buildExtensionSchemesRegex is vulnerable because it interpolates raw
scheme strings into a RegExp; map the input schemes through a regex-escaping
routine (e.g., escape any -\/\^$*+?.()|[]{} characters) before joining, then
build the RegExp from the escaped strings so metacharacters in configured
schemes cannot break or change the pattern; add a small helper named
escapeRegExp and use it when constructing the regex in
buildExtensionSchemesRegex.

}

function isExtensionScript(src: string, schemesRegex: RegExp) {
try {
const url = new URL(src, window.location.origin)
return EXTENSIONS_SCHEMES_RE.test(url.protocol)
return schemesRegex.test(url.protocol)
}
catch {
return false
Expand All @@ -24,14 +30,30 @@
}
}

function isIgnoredScript(src: string) {
return isSameOriginScript(src) || isExtensionScript(src)
function isIgnoredDomain(src: string, ignoredDomains: string[]) {
if (ignoredDomains.length === 0) return false
try {
const url = new URL(src, window.location.origin)
return ignoredDomains.some(domain => url.hostname === domain || url.hostname.endsWith(`.${domain}`))
}
catch {
return false
}
}

export default defineNuxtPlugin({
name: 'nuxt-hints:third-party-scripts',
setup() {
const nuxtApp = useNuxtApp()
const opts = getFeatureOptions('thirdPartyScripts') ?? {}

const extensionSchemes = [...DEFAULT_EXTENSION_SCHEMES, ...(opts.ignoredSchemes ?? [])]
const schemesRegex = buildExtensionSchemesRegex(extensionSchemes)
const ignoredDomains = opts.ignoredDomains ?? []

function isIgnoredScript(src: string) {
return isSameOriginScript(src) || isExtensionScript(src, schemesRegex) || isIgnoredDomain(src, ignoredDomains)
}

nuxtApp.payload.__hints = defu(nuxtApp.payload.__hints, {
thirdPartyScripts: ref<{ element: HTMLScriptElement, loaded: boolean }[]>([]),
Expand Down
6 changes: 6 additions & 0 deletions src/runtime/third-party-scripts/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface ThirdPartyScriptsFeatureOptions {
/** Additional domains to ignore when detecting third-party scripts */
ignoredDomains?: string[]
/** Additional URL scheme patterns to ignore (default includes browser extension schemes) */
ignoredSchemes?: string[]
}
4 changes: 2 additions & 2 deletions src/runtime/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { LCPMetricWithAttribution, INPMetricWithAttribution, CLSMetricWithAttribution } from 'web-vitals/attribution'
import type { HydrationMismatchPayload, LocalHydrationMismatch } from './hydration/types'
import type { DirectImportInfo, LazyHydrationState } from './lazy-load/composables'
import type { FeaturesName, FeatureFlags } from './core/types'
import type { FeaturesName, Features } from './core/types'

Check failure on line 5 in src/runtime/types.d.ts

View workflow job for this annotation

GitHub Actions / ci

'FeaturesName' is defined but never used. Allowed unused vars must match /^_/u
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove unused FeaturesName import to satisfy lint gate.

FeaturesName on Line 5 is never referenced, and CI already reports this as a failure.

Suggested fix
-import type { FeaturesName, Features } from './core/types'
+import type { Features } from './core/types'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { FeaturesName, Features } from './core/types'
import type { Features } from './core/types'
🧰 Tools
🪛 GitHub Check: ci

[failure] 5-5:
'FeaturesName' is defined but never used. Allowed unused vars must match /^_/u

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/types.d.ts` at line 5, Remove the unused type import FeaturesName
from the import statement: update the import that currently reads "import type {
FeaturesName, Features } from './core/types'" to only import Features (i.e.,
"import type { Features } from './core/types'") so the unused symbol
FeaturesName is no longer imported and the lint error is resolved.


declare global {
interface Window {
Expand Down Expand Up @@ -40,7 +40,7 @@
__tracerRecord: typeof import('vite-plugin-vue-tracer/client/record')
hints: {
config: {
features: Record<FeaturesName, FeatureFlags | boolean>
features: Features
}
}
}
Expand Down
Loading
Loading