mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
fix(frontend-lib): harden URL input parsing
- Extract URL input parsing and formatting into tested helpers - Preserve pasted HTTP URLs, paths, query strings, and explicit ports - Add Vitest coverage for URL input edge cases
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"test": "vitest run",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -43,10 +44,11 @@
|
||||
"typescript": "~5.6.3",
|
||||
"vite": "^5.4.21",
|
||||
"vite-plugin-dts": "^4.3.0",
|
||||
"vitest": "^2.1.9",
|
||||
"vue-tsc": "^2.1.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.5.12",
|
||||
"primevue": "^4.3.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import InputGroup from 'primevue/inputgroup'
|
||||
import InputGroupAddon from 'primevue/inputgroupaddon'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { buildUrlInputValue, getHostInputValue, parseHostInputOnBlur, parseUrlInput } from '../modules/url-input'
|
||||
|
||||
const props = defineProps<{
|
||||
placeholder?: string
|
||||
@@ -32,73 +33,11 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const parseUrl = (val: string | null | undefined): { proto: string; host: string; port: number | null } => {
|
||||
const getValidPort = (portStr: string, proto: string) => {
|
||||
const p = parseInt(portStr)
|
||||
return isNaN(p) ? (props.protos[proto] ?? 11010) : p
|
||||
}
|
||||
const parseByPattern = (input: string) => {
|
||||
const trimmed = input.trim()
|
||||
if (!trimmed) {
|
||||
return null
|
||||
}
|
||||
const match = trimmed.match(/^(\w+):\/\/(.*)$/)
|
||||
const proto = match ? match[1] : 'tcp'
|
||||
const rest = match ? match[2] : trimmed
|
||||
const authority = rest.split(/[/?#]/)[0]
|
||||
if (!authority) {
|
||||
return null
|
||||
}
|
||||
const hostAndMaybePort = authority.includes('@') ? authority.slice(authority.lastIndexOf('@') + 1) : authority
|
||||
if (hostAndMaybePort.startsWith('[')) {
|
||||
const ipv6End = hostAndMaybePort.indexOf(']')
|
||||
if (ipv6End > 0) {
|
||||
const host = hostAndMaybePort.slice(0, ipv6End + 1)
|
||||
const remain = hostAndMaybePort.slice(ipv6End + 1)
|
||||
// null = no explicit port in URL; do not fabricate a default
|
||||
const port: number | null = remain.startsWith(':') ? getValidPort(remain.slice(1), proto) : null
|
||||
return { proto, host, port }
|
||||
}
|
||||
}
|
||||
const portMatch = hostAndMaybePort.match(/^(.*):(\d+)$/)
|
||||
const host = portMatch ? portMatch[1] : hostAndMaybePort
|
||||
// null = no explicit port in URL; buildUrlValue will omit the port entirely,
|
||||
// preserving the protocol's implied standard port (e.g. 443 for wss://).
|
||||
const port: number | null = portMatch ? parseInt(portMatch[2]) : null
|
||||
return { proto, host, port }
|
||||
}
|
||||
|
||||
if (!val) {
|
||||
return { proto: 'tcp', host: '', port: props.protos['tcp'] ?? 11010 }
|
||||
}
|
||||
const parsedByPattern = parseByPattern(val)
|
||||
if (parsedByPattern) {
|
||||
return parsedByPattern
|
||||
}
|
||||
return { proto: 'tcp', host: '', port: null }
|
||||
}
|
||||
|
||||
const internalValue = ref(parseUrl(url.value))
|
||||
const internalValue = ref(parseUrlInput(url.value, props.protos))
|
||||
const defaultHost = '0.0.0.0'
|
||||
|
||||
const buildUrlValue = (value: { proto: string, host: string, port: number | null }, forceDefaultHost = false) => {
|
||||
const proto = value.proto || 'tcp'
|
||||
const rawHost = (value.host ?? '').trim()
|
||||
const host = rawHost || (forceDefaultHost ? defaultHost : '')
|
||||
if (!host) {
|
||||
return null
|
||||
}
|
||||
// Omit port when the protocol uses no port (protos value = 0), or when the
|
||||
// original URL had no explicit port (port === null) – avoids overwriting an
|
||||
// implicit standard port (e.g. 443 for wss) with an EasyTier default (11012).
|
||||
if (props.protos[proto] === 0 || value.port === null) {
|
||||
return `${proto}://${host}`
|
||||
}
|
||||
return `${proto}://${host}:${value.port}`
|
||||
}
|
||||
|
||||
const syncUrlFromInternal = (forceDefaultHost = false) => {
|
||||
const nextUrl = buildUrlValue(internalValue.value, forceDefaultHost)
|
||||
const nextUrl = buildUrlInputValue(internalValue.value, props.protos, forceDefaultHost)
|
||||
if (!nextUrl || nextUrl === url.value) {
|
||||
return
|
||||
}
|
||||
@@ -107,6 +46,10 @@ const syncUrlFromInternal = (forceDefaultHost = false) => {
|
||||
|
||||
const onHostBlur = () => {
|
||||
hostFocused.value = false
|
||||
const parsedHost = parseHostInputOnBlur(internalValue.value.host ?? '', internalValue.value.proto, props.protos)
|
||||
if (parsedHost) {
|
||||
internalValue.value = parsedHost
|
||||
}
|
||||
syncUrlFromInternal(true)
|
||||
}
|
||||
|
||||
@@ -123,12 +66,20 @@ const isNoPortProto = computed(() => {
|
||||
return props.protos[internalValue.value.proto] === 0
|
||||
})
|
||||
|
||||
const hostInputValue = computed({
|
||||
get: () => getHostInputValue(internalValue.value),
|
||||
set: (value: string) => {
|
||||
internalValue.value.host = value
|
||||
internalValue.value.suffix = undefined
|
||||
},
|
||||
})
|
||||
|
||||
// Sync from external
|
||||
watch(() => url.value, (newVal) => {
|
||||
if (hostFocused.value) {
|
||||
return
|
||||
}
|
||||
const parsed = parseUrl(newVal)
|
||||
const parsed = parseUrlInput(newVal, props.protos)
|
||||
const internalHost = internalValue.value.host ?? ''
|
||||
const sameHost = parsed.host === internalHost || (!internalHost.trim() && parsed.host === defaultHost)
|
||||
if (parsed.proto !== internalValue.value.proto ||
|
||||
@@ -140,6 +91,9 @@ watch(() => url.value, (newVal) => {
|
||||
|
||||
// Sync to external
|
||||
watch(internalValue, () => {
|
||||
if (hostFocused.value) {
|
||||
return
|
||||
}
|
||||
syncUrlFromInternal(false)
|
||||
}, { deep: true })
|
||||
|
||||
@@ -165,6 +119,8 @@ const onProtoChange = (newProto: string) => {
|
||||
internalValue.value.port = newDefault
|
||||
}
|
||||
internalValue.value.proto = newProto
|
||||
internalValue.value.suffix = undefined
|
||||
internalValue.value.hasExplicitPort = true
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -174,7 +130,7 @@ const onProtoChange = (newProto: string) => {
|
||||
<AutoComplete :model-value="internalValue.proto" :suggestions="filteredProtos" dropdown
|
||||
class="max-w-32 proto-autocomplete-in-group" @complete="searchProtos"
|
||||
@update:model-value="onProtoChange" />
|
||||
<InputText v-model="internalValue.host" :placeholder="placeholder || '0.0.0.0'" class="grow"
|
||||
<InputText v-model="hostInputValue" :placeholder="placeholder || '0.0.0.0'" class="grow"
|
||||
@focus="onHostFocus" @blur="onHostBlur" />
|
||||
<template v-if="!isNoPortProto">
|
||||
<InputGroupAddon>
|
||||
@@ -204,7 +160,7 @@ const onProtoChange = (newProto: string) => {
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label>{{ t('web.common.address') || 'Address' }}</label>
|
||||
<InputText v-model="internalValue.host" :placeholder="placeholder || '0.0.0.0'" class="w-full"
|
||||
<InputText v-model="hostInputValue" :placeholder="placeholder || '0.0.0.0'" class="w-full"
|
||||
@focus="onHostFocus" @blur="onHostBlur" />
|
||||
</div>
|
||||
<div v-if="!isNoPortProto" class="flex flex-col gap-2">
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { buildUrlInputValue, getHostInputValue, parseHostInputOnBlur, parseUrlInput, type ProtoPorts } from './url-input'
|
||||
|
||||
const protos: ProtoPorts = {
|
||||
tcp: 11010,
|
||||
udp: 11010,
|
||||
wg: 11011,
|
||||
ws: 11011,
|
||||
wss: 11012,
|
||||
quic: 11012,
|
||||
faketcp: 11013,
|
||||
http: 80,
|
||||
https: 443,
|
||||
txt: 0,
|
||||
srv: 0,
|
||||
}
|
||||
|
||||
function normalizeUrl(input: string, defaultProto = 'tcp') {
|
||||
return buildUrlInputValue(parseUrlInput(input, protos, defaultProto), protos, true)
|
||||
}
|
||||
|
||||
describe('parseUrlInput', () => {
|
||||
it.each([
|
||||
['https://raw.githubusercontent.com/aaa/bb/cc.txt', {
|
||||
proto: 'https',
|
||||
host: 'raw.githubusercontent.com',
|
||||
port: null,
|
||||
suffix: '/aaa/bb/cc.txt',
|
||||
hasExplicitPort: false,
|
||||
}],
|
||||
['https://host:4443/path?x=1#hash', {
|
||||
proto: 'https',
|
||||
host: 'host',
|
||||
port: 4443,
|
||||
suffix: '/path?x=1#hash',
|
||||
hasExplicitPort: true,
|
||||
}],
|
||||
['[::1]:11010/path', {
|
||||
proto: 'tcp',
|
||||
host: '[::1]',
|
||||
port: 11010,
|
||||
suffix: '/path',
|
||||
hasExplicitPort: true,
|
||||
}],
|
||||
[' http://host/path ', {
|
||||
proto: 'http',
|
||||
host: 'host',
|
||||
port: null,
|
||||
suffix: '/path',
|
||||
hasExplicitPort: false,
|
||||
}],
|
||||
])('parses %s', (input, expected) => {
|
||||
expect(parseUrlInput(input, protos)).toEqual(expected)
|
||||
})
|
||||
|
||||
it('parses IPv6 host without an explicit port', () => {
|
||||
expect(parseUrlInput('[::1]', protos)).toEqual({
|
||||
proto: 'tcp',
|
||||
host: '[::1]',
|
||||
port: null,
|
||||
suffix: '',
|
||||
hasExplicitPort: false,
|
||||
})
|
||||
})
|
||||
|
||||
it.each([
|
||||
['host:', 'host'],
|
||||
['host:notaport', 'host'],
|
||||
])('falls back to the default port for invalid port input %s', (input, host) => {
|
||||
expect(parseUrlInput(input, protos)).toEqual({
|
||||
proto: 'tcp',
|
||||
host,
|
||||
port: 11010,
|
||||
suffix: '',
|
||||
hasExplicitPort: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps the explicit proto for an input without authority', () => {
|
||||
expect(parseUrlInput('https://', protos)).toEqual({
|
||||
proto: 'https',
|
||||
host: '',
|
||||
port: null,
|
||||
suffix: '',
|
||||
hasExplicitPort: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildUrlInputValue', () => {
|
||||
it.each([
|
||||
['https://host', 'https://host'],
|
||||
['http://host', 'http://host'],
|
||||
['https://host:4443/path', 'https://host:4443/path'],
|
||||
['https://host:443/path', 'https://host:443/path'],
|
||||
['tcp://host', 'tcp://host'],
|
||||
['wss://host', 'wss://host'],
|
||||
['http://host/path?x=1#hash', 'http://host/path?x=1#hash'],
|
||||
['https://host?x=1', 'https://host?x=1'],
|
||||
['https://host#hash', 'https://host#hash'],
|
||||
['txt://example.com/path.txt', 'txt://example.com/path.txt'],
|
||||
['srv://_easytier._tcp.example.com', 'srv://_easytier._tcp.example.com'],
|
||||
['custom://host/path', 'custom://host/path'],
|
||||
])('normalizes %s to %s', (input, expected) => {
|
||||
expect(normalizeUrl(input)).toBe(expected)
|
||||
})
|
||||
|
||||
it('returns null for empty host unless default host is forced', () => {
|
||||
const parsed = parseUrlInput('', protos)
|
||||
|
||||
expect(buildUrlInputValue(parsed, protos, false)).toBeNull()
|
||||
expect(buildUrlInputValue(parsed, protos, true)).toBe('tcp://0.0.0.0:11010')
|
||||
})
|
||||
|
||||
it('does not build a broken URL for a protocol without authority', () => {
|
||||
const parsed = parseUrlInput('https://', protos)
|
||||
|
||||
expect(buildUrlInputValue(parsed, protos, false)).toBeNull()
|
||||
expect(buildUrlInputValue(parsed, protos, true)).toBe('https://0.0.0.0')
|
||||
})
|
||||
})
|
||||
|
||||
describe('parseHostInputOnBlur', () => {
|
||||
it('infers https for a pasted host:port/path when the current proto is tcp', () => {
|
||||
const parsed = parseHostInputOnBlur('raw.githubusercontent.com:4443/aaa/bb/cc.txt', 'tcp', protos)
|
||||
|
||||
expect(parsed).toEqual({
|
||||
proto: 'https',
|
||||
host: 'raw.githubusercontent.com',
|
||||
port: 4443,
|
||||
suffix: '/aaa/bb/cc.txt',
|
||||
hasExplicitPort: true,
|
||||
})
|
||||
expect(buildUrlInputValue(parsed!, protos, true)).toBe('https://raw.githubusercontent.com:4443/aaa/bb/cc.txt')
|
||||
})
|
||||
|
||||
it.each([
|
||||
['raw.githubusercontent.com/aaa/bb/cc.txt', 'tcp', 'https://raw.githubusercontent.com/aaa/bb/cc.txt'],
|
||||
['raw.githubusercontent.com:4443/aaa/bb/cc.txt', 'https', 'https://raw.githubusercontent.com:4443/aaa/bb/cc.txt'],
|
||||
['https://raw.githubusercontent.com:4443/aaa/bb/cc.txt', 'tcp', 'https://raw.githubusercontent.com:4443/aaa/bb/cc.txt'],
|
||||
[' https://raw.githubusercontent.com/aaa/bb/cc.txt ', 'tcp', 'https://raw.githubusercontent.com/aaa/bb/cc.txt'],
|
||||
])('normalizes pasted host input %s with current proto %s', (input, currentProto, expected) => {
|
||||
const parsed = parseHostInputOnBlur(input, currentProto, protos)
|
||||
|
||||
expect(buildUrlInputValue(parsed!, protos, true)).toBe(expected)
|
||||
})
|
||||
|
||||
it('keeps ordinary host:port input on the current tcp protocol', () => {
|
||||
const parsed = parseHostInputOnBlur('example.com:11010', 'tcp', protos)
|
||||
|
||||
expect(buildUrlInputValue(parsed!, protos, true)).toBe('tcp://example.com:11010')
|
||||
})
|
||||
|
||||
it('returns null for a simple host without port or suffix', () => {
|
||||
expect(parseHostInputOnBlur('example.com', 'tcp', protos)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('getHostInputValue', () => {
|
||||
it('shows host and suffix while keeping the port in the port field', () => {
|
||||
const parsed = parseUrlInput('https://raw.githubusercontent.com:4443/aaa/bb/cc.txt', protos)
|
||||
|
||||
expect(getHostInputValue(parsed)).toBe('raw.githubusercontent.com/aaa/bb/cc.txt')
|
||||
})
|
||||
|
||||
it('shows query and hash in the host input suffix', () => {
|
||||
const parsed = parseUrlInput('https://host/path?x=1#hash', protos)
|
||||
|
||||
expect(getHostInputValue(parsed)).toBe('host/path?x=1#hash')
|
||||
})
|
||||
})
|
||||
|
||||
describe('round trip scenarios', () => {
|
||||
it.each([
|
||||
['https://raw.githubusercontent.com/aaa/bb/cc.txt'],
|
||||
['https://raw.githubusercontent.com:4443/aaa/bb/cc.txt'],
|
||||
['http://host/path?x=1#hash'],
|
||||
['tcp://example.com:11010'],
|
||||
['txt://example.com/path.txt'],
|
||||
['srv://_easytier._tcp.example.com'],
|
||||
])('keeps %s stable after parse and build', (input) => {
|
||||
expect(normalizeUrl(input)).toBe(input)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,105 @@
|
||||
export interface UrlInputParts {
|
||||
proto: string
|
||||
host: string
|
||||
port: number | null
|
||||
suffix?: string
|
||||
hasExplicitPort?: boolean
|
||||
}
|
||||
|
||||
export type ProtoPorts = Record<string, number>
|
||||
|
||||
const fallbackProto = 'tcp'
|
||||
const fallbackPort = 11010
|
||||
const defaultHost = '0.0.0.0'
|
||||
|
||||
function defaultPortFor(protos: ProtoPorts, proto: string) {
|
||||
return protos[proto] ?? fallbackPort
|
||||
}
|
||||
|
||||
function getValidPort(portStr: string, protos: ProtoPorts, proto: string) {
|
||||
const p = parseInt(portStr)
|
||||
return isNaN(p) ? defaultPortFor(protos, proto) : p
|
||||
}
|
||||
|
||||
export function parseUrlInput(val: string | null | undefined, protos: ProtoPorts, defaultProto = fallbackProto): UrlInputParts {
|
||||
const parseByPattern = (input: string) => {
|
||||
const trimmed = input.trim()
|
||||
if (!trimmed) {
|
||||
return null
|
||||
}
|
||||
|
||||
const match = trimmed.match(/^(\w+):\/\/(.*)$/)
|
||||
const proto = match ? match[1] : defaultProto
|
||||
const rest = match ? match[2] : trimmed
|
||||
const suffixStart = rest.search(/[/?#]/)
|
||||
const authority = suffixStart >= 0 ? rest.slice(0, suffixStart) : rest
|
||||
const suffix = suffixStart >= 0 ? rest.slice(suffixStart) : ''
|
||||
if (!authority) {
|
||||
return { proto, host: '', port: null, suffix, hasExplicitPort: false }
|
||||
}
|
||||
|
||||
const hostAndMaybePort = authority.includes('@') ? authority.slice(authority.lastIndexOf('@') + 1) : authority
|
||||
if (hostAndMaybePort.startsWith('[')) {
|
||||
const ipv6End = hostAndMaybePort.indexOf(']')
|
||||
if (ipv6End > 0) {
|
||||
const host = hostAndMaybePort.slice(0, ipv6End + 1)
|
||||
const remain = hostAndMaybePort.slice(ipv6End + 1)
|
||||
const hasExplicitPort = remain.startsWith(':')
|
||||
const port = hasExplicitPort ? getValidPort(remain.slice(1), protos, proto) : null
|
||||
return { proto, host, port, suffix, hasExplicitPort }
|
||||
}
|
||||
}
|
||||
|
||||
const portMatch = hostAndMaybePort.match(/^(.*):(\d+)$/)
|
||||
if (portMatch) {
|
||||
return { proto, host: portMatch[1], port: parseInt(portMatch[2]), suffix, hasExplicitPort: true }
|
||||
}
|
||||
|
||||
const invalidPortMatch = hostAndMaybePort.match(/^([^:]+):[^:]*$/)
|
||||
const host = invalidPortMatch ? invalidPortMatch[1] : hostAndMaybePort
|
||||
const port = invalidPortMatch ? defaultPortFor(protos, proto) : null
|
||||
return { proto, host, port, suffix, hasExplicitPort: false }
|
||||
}
|
||||
|
||||
if (!val) {
|
||||
return { proto: defaultProto, host: '', port: defaultPortFor(protos, defaultProto) }
|
||||
}
|
||||
const parsedByPattern = parseByPattern(val)
|
||||
if (parsedByPattern) {
|
||||
return parsedByPattern
|
||||
}
|
||||
return { proto: defaultProto, host: '', port: defaultPortFor(protos, defaultProto) }
|
||||
}
|
||||
|
||||
export function buildUrlInputValue(value: UrlInputParts, protos: ProtoPorts, forceDefaultHost = false) {
|
||||
const proto = value.proto || fallbackProto
|
||||
const rawHost = (value.host ?? '').trim()
|
||||
const host = rawHost || (forceDefaultHost ? defaultHost : '')
|
||||
if (!host) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (protos[proto] === 0 || value.port === null) {
|
||||
return `${proto}://${host}${value.suffix ?? ''}`
|
||||
}
|
||||
|
||||
let port = value.port
|
||||
if (isNaN(parseInt(port as any))) {
|
||||
port = defaultPortFor(protos, proto)
|
||||
}
|
||||
|
||||
return `${proto}://${host}:${port}${value.suffix ?? ''}`
|
||||
}
|
||||
|
||||
export function parseHostInputOnBlur(rawHost: string, currentProto: string, protos: ProtoPorts) {
|
||||
const inferredProto = rawHost.includes('/') && currentProto === fallbackProto ? 'https' : currentProto
|
||||
const parsedHost = parseUrlInput(rawHost, protos, inferredProto)
|
||||
if (parsedHost.host && (parsedHost.proto !== currentProto || parsedHost.hasExplicitPort || parsedHost.suffix)) {
|
||||
return parsedHost
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getHostInputValue(value: UrlInputParts) {
|
||||
return `${value.host ?? ''}${value.suffix ?? ''}`
|
||||
}
|
||||
Generated
+271
-4
@@ -59,7 +59,7 @@ importers:
|
||||
devDependencies:
|
||||
'@antfu/eslint-config':
|
||||
specifier: ^3.7.3
|
||||
version: 3.16.0(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3))(@vue/compiler-sfc@3.5.21)(eslint-plugin-format@0.1.3(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)
|
||||
version: 3.16.0(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3))(@vue/compiler-sfc@3.5.21)(eslint-plugin-format@0.1.3(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)(vitest@2.1.9(@types/node@22.18.1))
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: ^5.2.0
|
||||
version: 5.3.1(@vue/compiler-dom@3.5.21)(eslint@9.35.0(jiti@2.5.1))(rollup@4.50.1)(typescript@5.6.3)(vue-i18n@10.0.8(vue@3.5.21(typescript@5.6.3)))(vue@3.5.21(typescript@5.6.3))
|
||||
@@ -287,6 +287,9 @@ importers:
|
||||
vite-plugin-dts:
|
||||
specifier: ^4.3.0
|
||||
version: 4.5.4(@types/node@22.18.1)(rollup@4.50.1)(typescript@5.6.3)(vite@5.4.21(@types/node@22.18.1))
|
||||
vitest:
|
||||
specifier: ^2.1.9
|
||||
version: 2.1.9(@types/node@22.18.1)
|
||||
vue-tsc:
|
||||
specifier: ^2.1.10
|
||||
version: 2.2.12(typescript@5.6.3)
|
||||
@@ -1674,6 +1677,35 @@ packages:
|
||||
vitest:
|
||||
optional: true
|
||||
|
||||
'@vitest/expect@2.1.9':
|
||||
resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
|
||||
|
||||
'@vitest/mocker@2.1.9':
|
||||
resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==}
|
||||
peerDependencies:
|
||||
msw: ^2.4.9
|
||||
vite: ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
msw:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
'@vitest/pretty-format@2.1.9':
|
||||
resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
|
||||
|
||||
'@vitest/runner@2.1.9':
|
||||
resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==}
|
||||
|
||||
'@vitest/snapshot@2.1.9':
|
||||
resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==}
|
||||
|
||||
'@vitest/spy@2.1.9':
|
||||
resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==}
|
||||
|
||||
'@vitest/utils@2.1.9':
|
||||
resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
|
||||
|
||||
'@volar/language-core@2.4.15':
|
||||
resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==}
|
||||
|
||||
@@ -2073,6 +2105,10 @@ packages:
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
assertion-error@2.0.1:
|
||||
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
ast-kit@1.4.3:
|
||||
resolution: {integrity: sha512-MdJqjpodkS5J149zN0Po+HPshkTdUyrvF7CKTafUgv69vBSPtncrj+3IiUgqdd7ElIEkbeXCsEouBUwLrw9Ilg==}
|
||||
engines: {node: '>=16.14.0'}
|
||||
@@ -2135,6 +2171,10 @@ packages:
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
call-bind-apply-helpers@1.0.2:
|
||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2153,6 +2193,10 @@ packages:
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
|
||||
chai@5.3.3:
|
||||
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
chalk@4.1.2:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2164,6 +2208,10 @@ packages:
|
||||
resolution: {integrity: sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==}
|
||||
engines: {pnpm: '>=8'}
|
||||
|
||||
check-error@2.1.3:
|
||||
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
chokidar@3.6.0:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
@@ -2252,6 +2300,10 @@ packages:
|
||||
decode-named-character-reference@1.2.0:
|
||||
resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
|
||||
|
||||
deep-eql@5.0.2:
|
||||
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
@@ -2329,6 +2381,9 @@ packages:
|
||||
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-module-lexer@1.7.0:
|
||||
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2597,6 +2652,10 @@ packages:
|
||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||
engines: {node: '>=16.17'}
|
||||
|
||||
expect-type@1.3.0:
|
||||
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
exsolve@1.0.7:
|
||||
resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==}
|
||||
|
||||
@@ -3018,6 +3077,9 @@ packages:
|
||||
longest-streak@3.1.0:
|
||||
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
||||
|
||||
loupe@3.2.1:
|
||||
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
|
||||
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
@@ -3371,6 +3433,10 @@ packages:
|
||||
pathe@2.0.3:
|
||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||
|
||||
pathval@2.0.1:
|
||||
resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
|
||||
engines: {node: '>= 14.16'}
|
||||
|
||||
perfect-debounce@1.0.0:
|
||||
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
|
||||
|
||||
@@ -3613,6 +3679,9 @@ packages:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
|
||||
signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
||||
@@ -3665,6 +3734,12 @@ packages:
|
||||
resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
stackback@0.0.2:
|
||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||
|
||||
std-env@3.10.0:
|
||||
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
|
||||
|
||||
string-argv@0.3.2:
|
||||
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
|
||||
engines: {node: '>=0.6.19'}
|
||||
@@ -3754,9 +3829,27 @@ packages:
|
||||
thenify@3.3.1:
|
||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||
|
||||
tinybench@2.9.0:
|
||||
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||
|
||||
tinyexec@0.3.2:
|
||||
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
|
||||
|
||||
tinyexec@1.0.1:
|
||||
resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==}
|
||||
|
||||
tinypool@1.1.1:
|
||||
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
|
||||
tinyrainbow@1.2.0:
|
||||
resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
tinyspy@3.0.2:
|
||||
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
@@ -3976,6 +4069,11 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0
|
||||
|
||||
vite-node@2.1.9:
|
||||
resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
|
||||
vite-plugin-dts@4.5.4:
|
||||
resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==}
|
||||
peerDependencies:
|
||||
@@ -4051,6 +4149,31 @@ packages:
|
||||
terser:
|
||||
optional: true
|
||||
|
||||
vitest@2.1.9:
|
||||
resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
'@vitest/browser': 2.1.9
|
||||
'@vitest/ui': 2.1.9
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
peerDependenciesMeta:
|
||||
'@edge-runtime/vm':
|
||||
optional: true
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@vitest/browser':
|
||||
optional: true
|
||||
'@vitest/ui':
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
|
||||
vscode-uri@3.1.0:
|
||||
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
||||
|
||||
@@ -4123,6 +4246,11 @@ packages:
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
why-is-node-running@2.3.0:
|
||||
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
|
||||
engines: {node: '>=8'}
|
||||
hasBin: true
|
||||
|
||||
word-wrap@1.2.5:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -4181,7 +4309,7 @@ snapshots:
|
||||
|
||||
'@alloc/quick-lru@5.2.0': {}
|
||||
|
||||
'@antfu/eslint-config@3.16.0(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3))(@vue/compiler-sfc@3.5.21)(eslint-plugin-format@0.1.3(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)':
|
||||
'@antfu/eslint-config@3.16.0(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3))(@vue/compiler-sfc@3.5.21)(eslint-plugin-format@0.1.3(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)(vitest@2.1.9(@types/node@22.18.1))':
|
||||
dependencies:
|
||||
'@antfu/install-pkg': 1.1.0
|
||||
'@clack/prompts': 0.9.1
|
||||
@@ -4190,7 +4318,7 @@ snapshots:
|
||||
'@stylistic/eslint-plugin': 2.13.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)
|
||||
'@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3))(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)
|
||||
'@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)
|
||||
'@vitest/eslint-plugin': 1.3.9(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)
|
||||
'@vitest/eslint-plugin': 1.3.9(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)(vitest@2.1.9(@types/node@22.18.1))
|
||||
eslint: 9.35.0(jiti@2.5.1)
|
||||
eslint-config-flat-gitignore: 1.0.1(eslint@9.35.0(jiti@2.5.1))
|
||||
eslint-flat-config-utils: 1.1.0
|
||||
@@ -5387,16 +5515,57 @@ snapshots:
|
||||
vite: 5.4.21(@types/node@22.18.1)
|
||||
vue: 3.5.21(typescript@5.6.3)
|
||||
|
||||
'@vitest/eslint-plugin@1.3.9(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)':
|
||||
'@vitest/eslint-plugin@1.3.9(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)(vitest@2.1.9(@types/node@22.18.1))':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.42.0
|
||||
'@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.6.3)
|
||||
eslint: 9.35.0(jiti@2.5.1)
|
||||
optionalDependencies:
|
||||
typescript: 5.6.3
|
||||
vitest: 2.1.9(@types/node@22.18.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitest/expect@2.1.9':
|
||||
dependencies:
|
||||
'@vitest/spy': 2.1.9
|
||||
'@vitest/utils': 2.1.9
|
||||
chai: 5.3.3
|
||||
tinyrainbow: 1.2.0
|
||||
|
||||
'@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.18.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 2.1.9
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.18
|
||||
optionalDependencies:
|
||||
vite: 5.4.21(@types/node@22.18.1)
|
||||
|
||||
'@vitest/pretty-format@2.1.9':
|
||||
dependencies:
|
||||
tinyrainbow: 1.2.0
|
||||
|
||||
'@vitest/runner@2.1.9':
|
||||
dependencies:
|
||||
'@vitest/utils': 2.1.9
|
||||
pathe: 1.1.2
|
||||
|
||||
'@vitest/snapshot@2.1.9':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 2.1.9
|
||||
magic-string: 0.30.18
|
||||
pathe: 1.1.2
|
||||
|
||||
'@vitest/spy@2.1.9':
|
||||
dependencies:
|
||||
tinyspy: 3.0.2
|
||||
|
||||
'@vitest/utils@2.1.9':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 2.1.9
|
||||
loupe: 3.2.1
|
||||
tinyrainbow: 1.2.0
|
||||
|
||||
'@volar/language-core@2.4.15':
|
||||
dependencies:
|
||||
'@volar/source-map': 2.4.15
|
||||
@@ -5971,6 +6140,8 @@ snapshots:
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
assertion-error@2.0.1: {}
|
||||
|
||||
ast-kit@1.4.3:
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.4
|
||||
@@ -6035,6 +6206,8 @@ snapshots:
|
||||
esbuild: 0.25.9
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
cac@6.7.14: {}
|
||||
|
||||
call-bind-apply-helpers@1.0.2:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@@ -6048,6 +6221,14 @@ snapshots:
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
chai@5.3.3:
|
||||
dependencies:
|
||||
assertion-error: 2.0.1
|
||||
check-error: 2.1.3
|
||||
deep-eql: 5.0.2
|
||||
loupe: 3.2.1
|
||||
pathval: 2.0.1
|
||||
|
||||
chalk@4.1.2:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
@@ -6059,6 +6240,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@kurkle/color': 0.3.4
|
||||
|
||||
check-error@2.1.3: {}
|
||||
|
||||
chokidar@3.6.0:
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
@@ -6139,6 +6322,8 @@ snapshots:
|
||||
dependencies:
|
||||
character-entities: 2.0.2
|
||||
|
||||
deep-eql@5.0.2: {}
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
default-browser-id@5.0.0: {}
|
||||
@@ -6199,6 +6384,8 @@ snapshots:
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
|
||||
es-module-lexer@1.7.0: {}
|
||||
|
||||
es-object-atoms@1.1.1:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@@ -6615,6 +6802,8 @@ snapshots:
|
||||
signal-exit: 4.1.0
|
||||
strip-final-newline: 3.0.0
|
||||
|
||||
expect-type@1.3.0: {}
|
||||
|
||||
exsolve@1.0.7: {}
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
@@ -6978,6 +7167,8 @@ snapshots:
|
||||
|
||||
longest-streak@3.1.0: {}
|
||||
|
||||
loupe@3.2.1: {}
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lru-cache@5.1.1:
|
||||
@@ -7503,6 +7694,8 @@ snapshots:
|
||||
|
||||
pathe@2.0.3: {}
|
||||
|
||||
pathval@2.0.1: {}
|
||||
|
||||
perfect-debounce@1.0.0: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
@@ -7739,6 +7932,8 @@ snapshots:
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
siginfo@2.0.0: {}
|
||||
|
||||
signal-exit@3.0.7: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
@@ -7786,6 +7981,10 @@ snapshots:
|
||||
|
||||
stable-hash-x@0.2.0: {}
|
||||
|
||||
stackback@0.0.2: {}
|
||||
|
||||
std-env@3.10.0: {}
|
||||
|
||||
string-argv@0.3.2: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
@@ -7896,8 +8095,18 @@ snapshots:
|
||||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
|
||||
tinybench@2.9.0: {}
|
||||
|
||||
tinyexec@0.3.2: {}
|
||||
|
||||
tinyexec@1.0.1: {}
|
||||
|
||||
tinypool@1.1.1: {}
|
||||
|
||||
tinyrainbow@1.2.0: {}
|
||||
|
||||
tinyspy@3.0.2: {}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
@@ -8200,6 +8409,24 @@ snapshots:
|
||||
dependencies:
|
||||
vite: 5.4.21(@types/node@22.18.1)
|
||||
|
||||
vite-node@2.1.9(@types/node@22.18.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.1
|
||||
es-module-lexer: 1.7.0
|
||||
pathe: 1.1.2
|
||||
vite: 5.4.21(@types/node@22.18.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
|
||||
vite-plugin-dts@4.5.4(@types/node@22.18.1)(rollup@4.50.1)(typescript@5.6.3)(vite@5.4.21(@types/node@22.18.1)):
|
||||
dependencies:
|
||||
'@microsoft/api-extractor': 7.52.11(@types/node@22.18.1)
|
||||
@@ -8291,6 +8518,41 @@ snapshots:
|
||||
'@types/node': 22.18.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
vitest@2.1.9(@types/node@22.18.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 2.1.9
|
||||
'@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.18.1))
|
||||
'@vitest/pretty-format': 2.1.9
|
||||
'@vitest/runner': 2.1.9
|
||||
'@vitest/snapshot': 2.1.9
|
||||
'@vitest/spy': 2.1.9
|
||||
'@vitest/utils': 2.1.9
|
||||
chai: 5.3.3
|
||||
debug: 4.4.1
|
||||
expect-type: 1.3.0
|
||||
magic-string: 0.30.18
|
||||
pathe: 1.1.2
|
||||
std-env: 3.10.0
|
||||
tinybench: 2.9.0
|
||||
tinyexec: 0.3.2
|
||||
tinypool: 1.1.1
|
||||
tinyrainbow: 1.2.0
|
||||
vite: 5.4.21(@types/node@22.18.1)
|
||||
vite-node: 2.1.9(@types/node@22.18.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 22.18.1
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
- msw
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
|
||||
vscode-uri@3.1.0: {}
|
||||
|
||||
vue-chartjs@5.3.2(chart.js@4.5.0)(vue@3.5.21(typescript@5.6.3)):
|
||||
@@ -8360,6 +8622,11 @@ snapshots:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
why-is-node-running@2.3.0:
|
||||
dependencies:
|
||||
siginfo: 2.0.0
|
||||
stackback: 0.0.2
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
|
||||
Reference in New Issue
Block a user