diff --git a/packages/web-ui/package.json b/packages/web-ui/package.json
index 9a36ad25d..f38daa98a 100644
--- a/packages/web-ui/package.json
+++ b/packages/web-ui/package.json
@@ -6,7 +6,10 @@
"scripts": {
"lint": "eslint ./src",
"tc": "tsc --noEmit",
- "prettier": "prettier --write src/**/*.ts"
+ "prettier": "prettier --write src/**/*.ts",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:debug": "pnpm run test:watch --inspect-brk --pool threads --poolOptions.threads.singleThread"
},
"type": "module",
"main": "src/index.ts",
@@ -47,10 +50,16 @@
"devDependencies": {
"@latitude-data/eslint-config": "workspace:*",
"@latitude-data/typescript-config": "workspace:*",
+ "@testing-library/dom": "^10.3.2",
+ "@testing-library/react": "^16.0.0",
+ "@testing-library/react-hooks": "^8.0.1",
"@types/react": "18.3.0",
"@types/react-dom": "18.3.0",
"autoprefixer": "^10.4.19",
+ "jsdom": "^24.1.0",
"postcss": "^8.4.39",
- "tailwindcss": "^3.4.4"
+ "tailwindcss": "^3.4.4",
+ "vite-tsconfig-paths": "^4.3.2",
+ "vitest": "^2.0.3"
}
}
diff --git a/packages/web-ui/postcss.config.js b/packages/web-ui/postcss.config.mjs
similarity index 76%
rename from packages/web-ui/postcss.config.js
rename to packages/web-ui/postcss.config.mjs
index 33ad091d2..2e7af2b7f 100644
--- a/packages/web-ui/postcss.config.js
+++ b/packages/web-ui/postcss.config.mjs
@@ -1,4 +1,4 @@
-module.exports = {
+export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
diff --git a/packages/web-ui/src/layouts/index.ts b/packages/web-ui/src/layouts/index.ts
index 3c4ce74d4..c6ea72db6 100644
--- a/packages/web-ui/src/layouts/index.ts
+++ b/packages/web-ui/src/layouts/index.ts
@@ -1,3 +1,4 @@
export { default as FocusLayout } from './FocusLayout'
export { default as AppLayout } from './AppLayout'
export { default as AppHeader } from './AppLayout/Header'
+export { default as DocumentsSidebar } from './DocumentsSidebar'
diff --git a/packages/web-ui/src/sections/DocumentsSidebar/index.tsx b/packages/web-ui/src/sections/DocumentsSidebar/index.tsx
new file mode 100644
index 000000000..73e1184d8
--- /dev/null
+++ b/packages/web-ui/src/sections/DocumentsSidebar/index.tsx
@@ -0,0 +1,37 @@
+'use client'
+
+import { SidebarDocument, useTree, Node } from '$ui/sections/DocumentsSidebar/useTree'
+
+function TreeNode({ node, level = 0 }: { node: Node; level?: number }) {
+ return (
+
+
+ {!!node.doc && (
+
+ {node.doc.documentType === 'folder' ? (
+ <>
+
{node.doc.name}
+
+ >
+ ) : (
+
{node.doc.name}
+ )}
+
+ )}
+ {node.children.map((node, idx) => (
+
+ ))}
+
+
+ )
+}
+
+export default function DocumentTree({
+ documents,
+}: {
+ documents: SidebarDocument[]
+}) {
+ const rootNode = useTree({ documents })
+
+ return
+}
diff --git a/packages/web-ui/src/sections/DocumentsSidebar/useTree/index.test.ts b/packages/web-ui/src/sections/DocumentsSidebar/useTree/index.test.ts
new file mode 100644
index 000000000..4153cca65
--- /dev/null
+++ b/packages/web-ui/src/sections/DocumentsSidebar/useTree/index.test.ts
@@ -0,0 +1,64 @@
+import { renderHook } from '@testing-library/react'
+import { describe, expect, it } from 'vitest'
+
+import { Node, useTree } from './index'
+
+let list = [
+ { path: 'things/doc1', doumentUuid: '1' },
+ { path: 'things/doc2', doumentUuid: '2' },
+ { path: 'things/other-things/doc3', doumentUuid: '3' },
+ { path: 'something-else/doc4', doumentUuid: '4' },
+]
+
+describe('useTree', () => {
+ it('should return a tree with children', () => {
+ const { result } = renderHook(() => useTree({ documents: list }))
+ expect(result.current).toEqual(
+ new Node({
+ doc: undefined,
+ isRoot: true,
+ name: 'root',
+ children: [
+ new Node({
+ doc: undefined,
+ name: 'things',
+ children: [
+ new Node({
+ doc: { path: 'things/doc1', doumentUuid: '1' },
+ name: 'doc1',
+ children: [],
+ }),
+ new Node({
+ doc: { path: 'things/doc2', doumentUuid: '2' },
+ name: 'doc2',
+ children: [],
+ }),
+ new Node({
+ doc: undefined,
+ name: 'other-things',
+ children: [
+ new Node({
+ doc: { path: 'things/other-things/doc3', doumentUuid: '3' },
+ name: 'doc3',
+ children: [],
+ }),
+ ],
+ }),
+ ],
+ }),
+ new Node({
+ doc: undefined,
+ name: 'something-else',
+ children: [
+ new Node({
+ doc: { path: 'something-else/doc4', doumentUuid: '4' },
+ name: 'doc4',
+ children: [],
+ }),
+ ],
+ }),
+ ],
+ }),
+ )
+ })
+})
diff --git a/packages/web-ui/src/sections/DocumentsSidebar/useTree/index.ts b/packages/web-ui/src/sections/DocumentsSidebar/useTree/index.ts
new file mode 100644
index 000000000..098cbecd6
--- /dev/null
+++ b/packages/web-ui/src/sections/DocumentsSidebar/useTree/index.ts
@@ -0,0 +1,84 @@
+import { useMemo } from 'react'
+
+export type SidebarDocument = {
+ path: string
+ doumentUuid: string
+}
+
+export class Node {
+ public doc?: SidebarDocument
+ public children: Node[] = []
+ public isRoot: boolean = false
+ private name: string = ''
+
+ constructor({
+ doc,
+ children = [],
+ isRoot = false,
+ name = '',
+ }: {
+ doc?: SidebarDocument
+ children?: Node[]
+ isRoot?: boolean
+ name?: string
+ }) {
+ this.doc = doc
+ this.children = children
+ this.isRoot = isRoot
+ this.name = isRoot ? 'root' : name
+ }
+}
+
+function sortByPathDepth(a: SidebarDocument, b: SidebarDocument) {
+ const depth1 = (a.path.match(/\//g) || []).length
+ const depth2 = (b.path.match(/\//g) || []).length
+ return depth1 - depth2
+}
+
+function buildTree({
+ root,
+ nodeMap,
+ documents,
+}: {
+ root: Node
+ nodeMap: Map
+ documents: SidebarDocument[]
+}) {
+ documents.forEach((doc) => {
+ const segments = doc.path.split('/')
+ let path = ''
+
+ segments.forEach((segment, index) => {
+ const isFile = index === segments.length - 1
+ path = path ? `${path}/${segment}` : segment
+
+ if (!nodeMap.has(path)) {
+ const file = isFile ? doc : undefined
+ const node = new Node({ doc: file, name: segment })
+ nodeMap.set(path, node)
+
+ const parentPath = path.split('/').slice(0, -1).join('/')
+
+ // We force TypeScript to check that the parentPath is not empty
+ // We pre-sorted documents by path depth, so we know
+ // that the parent node exists
+ const parent = nodeMap.get(parentPath)!
+ parent.children.push(node)
+ }
+ })
+ })
+
+ return root
+}
+
+export function useTree({ documents }: { documents: SidebarDocument[] }) {
+ return useMemo(() => {
+ const root = new Node({ children: [], isRoot: true })
+ const nodeMap = new Map()
+ nodeMap.set('', root)
+ const sorted = documents.slice().sort(sortByPathDepth)
+
+ const tree = buildTree({ root, nodeMap, documents: sorted })
+ return tree
+ }, [documents])
+}
diff --git a/packages/web-ui/vitest.config.mjs b/packages/web-ui/vitest.config.mjs
new file mode 100644
index 000000000..c1e662a01
--- /dev/null
+++ b/packages/web-ui/vitest.config.mjs
@@ -0,0 +1,13 @@
+import { defineConfig } from 'vitest/config'
+import { resolve } from 'path'
+
+export default defineConfig({
+ resolve: {
+ alias: {
+ $ui: resolve(__dirname, './src'),
+ },
+ },
+ test: {
+ environment: 'jsdom',
+ },
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 313096e05..fe2cac6c7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -520,6 +520,15 @@ importers:
'@latitude-data/typescript-config':
specifier: workspace:*
version: link:../../tools/typescript
+ '@testing-library/dom':
+ specifier: ^10.3.2
+ version: 10.3.2
+ '@testing-library/react':
+ specifier: ^16.0.0
+ version: 16.0.0(@testing-library/dom@10.3.2)(@types/react-dom@18.3.0)(@types/react@18.3.0)(react-dom@18.3.0)(react@18.3.0)
+ '@testing-library/react-hooks':
+ specifier: ^8.0.1
+ version: 8.0.1(@types/react@18.3.0)(react-dom@18.3.0)(react@18.3.0)
'@types/react':
specifier: 18.3.0
version: 18.3.0
@@ -529,12 +538,21 @@ importers:
autoprefixer:
specifier: ^10.4.19
version: 10.4.19(postcss@8.4.39)
+ jsdom:
+ specifier: ^24.1.0
+ version: 24.1.0
postcss:
specifier: ^8.4.39
version: 8.4.39
tailwindcss:
specifier: ^3.4.4
version: 3.4.4
+ vite-tsconfig-paths:
+ specifier: ^4.3.2
+ version: 4.3.2(typescript@5.5.3)
+ vitest:
+ specifier: ^2.0.3
+ version: 2.0.3(jsdom@24.1.0)
tools/eslint:
devDependencies:
@@ -759,6 +777,13 @@ packages:
'@babel/types': 7.24.7
dev: true
+ /@babel/runtime@7.24.8:
+ resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.14.1
+ dev: true
+
/@babel/template@7.24.7:
resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
engines: {node: '>=6.9.0'}
@@ -3264,6 +3289,66 @@ packages:
zod: 3.23.8
dev: false
+ /@testing-library/dom@10.3.2:
+ resolution: {integrity: sha512-0bxIdP9mmPiOJ6wHLj8bdJRq+51oddObeCGdEf6PNEhYd93ZYAN+lPRnEOVFtheVwDM7+p+tza3LAQgp0PTudg==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@babel/code-frame': 7.24.7
+ '@babel/runtime': 7.24.8
+ '@types/aria-query': 5.0.4
+ aria-query: 5.3.0
+ chalk: 4.1.2
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ pretty-format: 27.5.1
+ dev: true
+
+ /@testing-library/react-hooks@8.0.1(@types/react@18.3.0)(react-dom@18.3.0)(react@18.3.0):
+ resolution: {integrity: sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@types/react': ^16.9.0 || ^17.0.0
+ react: ^16.9.0 || ^17.0.0 || 19.x
+ react-dom: ^16.9.0 || ^17.0.0 || 19.x
+ react-test-renderer: ^16.9.0 || ^17.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react-dom:
+ optional: true
+ react-test-renderer:
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.8
+ '@types/react': 18.3.0
+ react: 18.3.0
+ react-dom: 18.3.0(react@18.3.0)
+ react-error-boundary: 3.1.4(react@18.3.0)
+ dev: true
+
+ /@testing-library/react@16.0.0(@testing-library/dom@10.3.2)(@types/react-dom@18.3.0)(@types/react@18.3.0)(react-dom@18.3.0)(react@18.3.0):
+ resolution: {integrity: sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@testing-library/dom': ^10.0.0
+ '@types/react': ^18.0.0
+ '@types/react-dom': ^18.0.0
+ react: ^18.0.0 || 19.x
+ react-dom: ^18.0.0 || 19.x
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.8
+ '@testing-library/dom': 10.3.2
+ '@types/react': 18.3.0
+ '@types/react-dom': 18.3.0
+ react: 18.3.0
+ react-dom: 18.3.0(react@18.3.0)
+ dev: true
+
/@tybys/wasm-util@0.8.3:
resolution: {integrity: sha512-Z96T/L6dUFFxgFJ+pQtkPpne9q7i6kIPYCFnQBHSgSPV9idTsKfIhCss0h5iM9irweZCatkrdeP8yi5uM1eX6Q==}
requiresBuild: true
@@ -3272,6 +3357,10 @@ packages:
dev: false
optional: true
+ /@types/aria-query@5.0.4:
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+ dev: true
+
/@types/bcrypt@5.0.2:
resolution: {integrity: sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==}
dependencies:
@@ -3964,6 +4053,15 @@ packages:
- supports-color
dev: false
+ /agent-base@7.1.1:
+ resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ debug: 4.3.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/agentkeepalive@4.5.0:
resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==}
engines: {node: '>= 8.0.0'}
@@ -4052,6 +4150,12 @@ packages:
deep-equal: 2.2.3
dev: true
+ /aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+ dependencies:
+ dequal: 2.0.3
+ dev: true
+
/array-back@3.1.0:
resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==}
engines: {node: '>=6'}
@@ -4631,6 +4735,13 @@ packages:
engines: {node: '>=4'}
hasBin: true
+ /cssstyle@4.0.1:
+ resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ rrweb-cssom: 0.6.0
+ dev: true
+
/csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -4638,6 +4749,14 @@ packages:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
dev: true
+ /data-urls@5.0.0:
+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+ engines: {node: '>=18'}
+ dependencies:
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.0.0
+ dev: true
+
/data-view-buffer@1.0.1:
resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
engines: {node: '>= 0.4'}
@@ -4698,6 +4817,10 @@ packages:
dependencies:
ms: 2.1.2
+ /decimal.js@10.4.3:
+ resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
+ dev: true
+
/deep-eql@4.1.4:
resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
engines: {node: '>=6'}
@@ -4779,6 +4902,11 @@ packages:
engines: {node: '>= 0.8'}
dev: false
+ /dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+ dev: true
+
/destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -4843,6 +4971,10 @@ packages:
esutils: 2.0.3
dev: true
+ /dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+ dev: true
+
/dotenv@16.0.3:
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
engines: {node: '>=12'}
@@ -4987,6 +5119,11 @@ packages:
tapable: 2.2.1
dev: true
+ /entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+ dev: true
+
/error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
dependencies:
@@ -6336,6 +6473,13 @@ packages:
engines: {node: '>=14'}
dev: false
+ /html-encoding-sniffer@4.0.0:
+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ whatwg-encoding: 3.1.1
+ dev: true
+
/http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
@@ -6347,6 +6491,16 @@ packages:
toidentifier: 1.0.1
dev: false
+ /http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+ dependencies:
+ agent-base: 7.1.1
+ debug: 4.3.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
@@ -6357,6 +6511,16 @@ packages:
- supports-color
dev: false
+ /https-proxy-agent@7.0.5:
+ resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
+ engines: {node: '>= 14'}
+ dependencies:
+ agent-base: 7.1.1
+ debug: 4.3.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
@@ -6375,6 +6539,13 @@ packages:
safer-buffer: 2.1.2
dev: false
+ /iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: true
+
/ignore@5.3.1:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
@@ -6592,6 +6763,10 @@ packages:
engines: {node: '>=12'}
dev: true
+ /is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+ dev: true
+
/is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
dependencies:
@@ -6721,6 +6896,42 @@ packages:
argparse: 2.0.1
dev: true
+ /jsdom@24.1.0:
+ resolution: {integrity: sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ canvas: ^2.11.2
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+ dependencies:
+ cssstyle: 4.0.1
+ data-urls: 5.0.0
+ decimal.js: 10.4.3
+ form-data: 4.0.0
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.5
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.12
+ parse5: 7.1.2
+ rrweb-cssom: 0.7.1
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 4.1.4
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.0.0
+ ws: 8.18.0
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+ dev: true
+
/jsesc@0.5.0:
resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
hasBin: true
@@ -6918,6 +7129,11 @@ packages:
engines: {node: '>=12'}
dev: false
+ /lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+ dev: true
+
/magic-string@0.30.10:
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
dependencies:
@@ -7276,6 +7492,10 @@ packages:
set-blocking: 2.0.0
dev: false
+ /nwsapi@2.2.12:
+ resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==}
+ dev: true
+
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -7483,6 +7703,12 @@ packages:
lines-and-columns: 1.2.4
dev: true
+ /parse5@7.1.2:
+ resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+ dependencies:
+ entities: 4.5.0
+ dev: true
+
/parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -7792,6 +8018,15 @@ packages:
hasBin: true
dev: true
+ /pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+ dev: true
+
/pretty-format@29.7.0:
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -7817,6 +8052,10 @@ packages:
ipaddr.js: 1.9.1
dev: false
+ /psl@1.9.0:
+ resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
+ dev: true
+
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -7836,6 +8075,10 @@ packages:
side-channel: 1.0.6
dev: true
+ /querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+ dev: true
+
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -7862,7 +8105,6 @@ packages:
loose-envify: 1.4.0
react: 18.3.0
scheduler: 0.23.2
- dev: false
/react-dom@19.0.0-rc-378b305958-20240710(react@19.0.0-rc-378b305958-20240710):
resolution: {integrity: sha512-WpE0+4pnFMyuC9WxJGj7+XysxNChbwnCcFS7INR428/uUoECSTRmlQt05hTGFIyfpYBO1zGlXfMBAkrFmqh3wg==}
@@ -7873,10 +8115,24 @@ packages:
scheduler: 0.25.0-rc-378b305958-20240710
dev: false
+ /react-error-boundary@3.1.4(react@18.3.0):
+ resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==}
+ engines: {node: '>=10', npm: '>=6'}
+ peerDependencies:
+ react: '>=16.13.1 || 19.x'
+ dependencies:
+ '@babel/runtime': 7.24.8
+ react: 18.3.0
+ dev: true
+
/react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
+ /react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+ dev: true
+
/react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
dev: true
@@ -7938,7 +8194,6 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
loose-envify: 1.4.0
- dev: false
/react@19.0.0-rc-378b305958-20240710:
resolution: {integrity: sha512-z+c5SdYuX74FSlyDcBWXMmR7KN30rpak804OtidcgxvYoyU43YCT0GWHubH6UvnNDvaLsr5nl66AKmC2y7VwYA==}
@@ -8014,6 +8269,10 @@ packages:
which-builtin-type: 1.1.3
dev: true
+ /regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+ dev: true
+
/regexp-tree@0.1.27:
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
hasBin: true
@@ -8041,6 +8300,10 @@ packages:
jsesc: 0.5.0
dev: true
+ /requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+ dev: true
+
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -8125,6 +8388,14 @@ packages:
fsevents: 2.3.3
dev: true
+ /rrweb-cssom@0.6.0:
+ resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
+ dev: true
+
+ /rrweb-cssom@0.7.1:
+ resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==}
+ dev: true
+
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
@@ -8159,13 +8430,18 @@ packages:
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
- dev: false
+
+ /saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+ dependencies:
+ xmlchars: 2.2.0
+ dev: true
/scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
dependencies:
loose-envify: 1.4.0
- dev: false
/scheduler@0.25.0-rc-378b305958-20240710:
resolution: {integrity: sha512-j6dzH6LeNjhKFSpxUiZT2E8tFvFTCQOn339mmzYA3QBLvIkgAtHzSrpdReKhFzw9x4hxazBjgE/4YwBLQBUNlw==}
@@ -8625,6 +8901,10 @@ packages:
use-sync-external-store: 1.2.2(react@19.0.0-rc-378b305958-20240710)
dev: false
+ /symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+ dev: true
+
/synckit@0.9.0:
resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -8762,9 +9042,26 @@ packages:
engines: {node: '>=0.6'}
dev: false
+ /tough-cookie@4.1.4:
+ resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
+ engines: {node: '>=6'}
+ dependencies:
+ psl: 1.9.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+ dev: true
+
/tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ /tr46@5.0.0:
+ resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
+ engines: {node: '>=18'}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
/traverse-chain@0.1.0:
resolution: {integrity: sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg==}
dev: true
@@ -9025,6 +9322,11 @@ packages:
engines: {node: '>=18.17'}
dev: false
+ /universalify@0.2.0:
+ resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+ engines: {node: '>= 4.0.0'}
+ dev: true
+
/universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@@ -9052,6 +9354,13 @@ packages:
punycode: 2.3.1
dev: true
+ /url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+ dev: true
+
/use-callback-ref@1.3.2(@types/react@18.3.0)(react@18.3.0):
resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
engines: {node: '>=10'}
@@ -9137,6 +9446,27 @@ packages:
- terser
dev: true
+ /vite-node@2.0.3:
+ resolution: {integrity: sha512-14jzwMx7XTcMB+9BhGQyoEAmSl0eOr3nrnn+Z12WNERtOvLN+d2scbRUvyni05rT3997Bg+rZb47NyP4IQPKXg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ dependencies:
+ cac: 6.7.14
+ debug: 4.3.5
+ pathe: 1.1.2
+ tinyrainbow: 1.2.0
+ vite: 5.3.3
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
/vite-node@2.0.3(@types/node@20.14.10):
resolution: {integrity: sha512-14jzwMx7XTcMB+9BhGQyoEAmSl0eOr3nrnn+Z12WNERtOvLN+d2scbRUvyni05rT3997Bg+rZb47NyP4IQPKXg==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -9174,6 +9504,41 @@ packages:
- typescript
dev: true
+ /vite@5.3.3:
+ resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ esbuild: 0.21.5
+ postcss: 8.4.39
+ rollup: 4.18.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
/vite@5.3.3(@types/node@20.14.10):
resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -9321,6 +9686,68 @@ packages:
- terser
dev: true
+ /vitest@2.0.3(jsdom@24.1.0):
+ resolution: {integrity: sha512-o3HRvU93q6qZK4rI2JrhKyZMMuxg/JRt30E6qeQs6ueaiz5hr1cPj+Sk2kATgQzMMqsa2DiNI0TIK++1ULx8Jw==}
+ 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.0.3
+ '@vitest/ui': 2.0.3
+ 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
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@vitest/expect': 2.0.3
+ '@vitest/pretty-format': 2.0.3
+ '@vitest/runner': 2.0.3
+ '@vitest/snapshot': 2.0.3
+ '@vitest/spy': 2.0.3
+ '@vitest/utils': 2.0.3
+ chai: 5.1.1
+ debug: 4.3.5
+ execa: 8.0.1
+ jsdom: 24.1.0
+ magic-string: 0.30.10
+ pathe: 1.1.2
+ std-env: 3.7.0
+ tinybench: 2.8.0
+ tinypool: 1.0.0
+ tinyrainbow: 1.2.0
+ vite: 5.3.3
+ vite-node: 2.0.3
+ why-is-node-running: 2.3.0
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
+ /w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+ dependencies:
+ xml-name-validator: 5.0.0
+ dev: true
+
/web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
@@ -9334,6 +9761,31 @@ packages:
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ /webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /whatwg-encoding@3.1.1:
+ resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ iconv-lite: 0.6.3
+ dev: true
+
+ /whatwg-mimetype@4.0.0:
+ resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /whatwg-url@14.0.0:
+ resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
+ engines: {node: '>=18'}
+ dependencies:
+ tr46: 5.0.0
+ webidl-conversions: 7.0.0
+ dev: true
+
/whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
dependencies:
@@ -9443,6 +9895,28 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ /ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ dev: true
+
+ /xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+ dev: true
+
/xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}