diff --git a/.gitignore b/.gitignore index 41d6afd70..84247861d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,10 @@ node_modules package-lock.json yarn.lock pnpm-lock.yaml + +# Generated framework wrappers +js/hang-ui/src/wrappers/ +js/hang/src/wrappers/ + +# Generated manifest (created during build) +custom-elements.json \ No newline at end of file diff --git a/bun.lock b/bun.lock index fc302a543..ffaf4aea9 100644 --- a/bun.lock +++ b/bun.lock @@ -48,6 +48,7 @@ "zod": "^4.1.5", }, "devDependencies": { + "@custom-elements-manifest/analyzer": "^0.11.0", "@types/audioworklet": "^0.0.77", "@typescript/lib-dom": "npm:@types/web@^0.0.241", "fast-glob": "^3.3.3", @@ -76,6 +77,7 @@ "name": "@moq/hang-ui", "version": "0.1.2", "devDependencies": { + "@custom-elements-manifest/analyzer": "^0.11.0", "@types/audioworklet": "^0.0.77", "@typescript/lib-dom": "npm:@types/web@^0.0.241", "rimraf": "^6.0.1", @@ -84,6 +86,7 @@ "typescript": "^5.9.2", "unplugin-solid": "^1.0.0", "vite": "^7.3.1", + "vite-plugin-dts": "^4.5.4", "vite-plugin-solid": "^2.11.10", }, "peerDependencies": { @@ -265,6 +268,10 @@ "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + "@custom-elements-manifest/analyzer": ["@custom-elements-manifest/analyzer@0.11.0", "", { "dependencies": { "@custom-elements-manifest/find-dependencies": "^0.0.7", "@github/catalyst": "^1.6.0", "@web/config-loader": "0.1.3", "chokidar": "3.5.2", "command-line-args": "5.1.2", "comment-parser": "1.2.4", "custom-elements-manifest": "1.0.0", "debounce": "1.2.1", "globby": "11.0.4", "typescript": "~5.4.2" }, "bin": { "custom-elements-manifest": "cem.js", "cem": "cem.js" } }, "sha512-F2jQFk6igV5vrTZYDBLVr0GDQF3cTJ2VwwzPdsmkzUE+SHiYAQNKYebIq8qphZdJeTcZtVhvw336FQVZsMqh4A=="], + + "@custom-elements-manifest/find-dependencies": ["@custom-elements-manifest/find-dependencies@0.0.7", "", { "dependencies": { "oxc-resolver": "^11.9.0", "rs-module-lexer": "^2.5.1" } }, "sha512-icHEBPHcOXSrpDOFkQhvM7vljEbqrEReW251RBxSzDctXzYWIL0Hk2yMDINn3d6mZ4KSsqLZlaFiGFp/2nn9rA=="], + "@dependents/detective-less": ["@dependents/detective-less@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ=="], "@docsearch/css": ["@docsearch/css@3.8.2", "", {}, "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ=="], @@ -273,8 +280,12 @@ "@docsearch/react": ["@docsearch/react@3.8.2", "", { "dependencies": { "@algolia/autocomplete-core": "1.17.7", "@algolia/autocomplete-preset-algolia": "1.17.7", "@docsearch/css": "3.8.2", "algoliasearch": "^5.14.2" }, "peerDependencies": { "@types/react": ">= 16.8.0 < 19.0.0", "react": ">= 16.8.0 < 19.0.0", "react-dom": ">= 16.8.0 < 19.0.0", "search-insights": ">= 1 < 3" }, "optionalPeers": ["@types/react", "react", "react-dom", "search-insights"] }, "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg=="], + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], @@ -331,6 +342,8 @@ "@fails-components/webtransport-transport-http3-quiche": ["@fails-components/webtransport-transport-http3-quiche@1.5.2", "", { "dependencies": { "@types/debug": "^4.1.7", "bindings": "^1.5.0", "cmake-js": "^7.2.1", "debug": "^4.3.4", "node-addon-api": "^7.0.0", "prebuild-install": "^7.1.1" } }, "sha512-Z2oufdIoNrniMK5YtRWEI6t7MdzyREcCK80zwuONi17aP2AAtiq1jztywuZf+8tiqCAYTS7Ho5IgK5XKOVqAaw=="], + "@github/catalyst": ["@github/catalyst@1.7.0", "", {}, "sha512-qOAxrDdRZz9+v4y2WoAfh11rpRY/x4FRofPNmJyZFzAjubtzE3sCa/tAycWWufmQGoYiwwzL/qJBBgyg7avxPw=="], + "@hexagon/base64": ["@hexagon/base64@2.0.4", "", {}, "sha512-H/ZY6rGyaEuk0mwQgZ3BVi9hMjFTYpBNFbmtOuec/pPibuGhCMXd8fGtwBaO0h44FkWMurysMsDrpkJsBRmoWQ=="], "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.65", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-v/O0UeqrDz6ASuRVE5g2Puo5aWyej4M/CxX6WYDBARgswwxK0mp3VQbGgPFEAAUU9QN02IjTgjMuO021gpWf2w=="], @@ -397,6 +410,14 @@ "@libav.js/variant-opus-af": ["@libav.js/variant-opus-af@6.8.8", "", {}, "sha512-8KBQyA8n5goN7lyctOaPxpcx7dapOgqKh8dWW/NAcl87AgM/WoUGSex3fFc46oCtTHYrUKEm1OmZUrtkt3Q56A=="], + "@microsoft/api-extractor": ["@microsoft/api-extractor@7.56.3", "", { "dependencies": { "@microsoft/api-extractor-model": "7.32.2", "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.0", "@rushstack/node-core-library": "5.19.1", "@rushstack/rig-package": "0.6.0", "@rushstack/terminal": "0.21.0", "@rushstack/ts-command-line": "5.2.0", "diff": "~8.0.2", "lodash": "~4.17.23", "minimatch": "10.1.2", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", "typescript": "5.8.2" }, "bin": { "api-extractor": "bin/api-extractor" } }, "sha512-fRqok4aRNq5GpgGBv2fKlSSKbirPKTJ75vQefthB5x9dwt4Zz+AezUzdc1p/AG4wUBIgmhjcEwn/Rj+N4Wh4Mw=="], + + "@microsoft/api-extractor-model": ["@microsoft/api-extractor-model@7.32.2", "", { "dependencies": { "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.0", "@rushstack/node-core-library": "5.19.1" } }, "sha512-Ussc25rAalc+4JJs9HNQE7TuO9y6jpYQX9nWD1DhqUzYPBr3Lr7O9intf+ZY8kD5HnIqeIRJX7ccCT0QyBy2Ww=="], + + "@microsoft/tsdoc": ["@microsoft/tsdoc@0.16.0", "", {}, "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA=="], + + "@microsoft/tsdoc-config": ["@microsoft/tsdoc-config@0.18.0", "", { "dependencies": { "@microsoft/tsdoc": "0.16.0", "ajv": "~8.12.0", "jju": "~1.4.0", "resolve": "~1.22.2" } }, "sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw=="], + "@moq/clock": ["@moq/clock@workspace:js/clock"], "@moq/hang": ["@moq/hang@workspace:js/hang"], @@ -413,12 +434,54 @@ "@moq/web-transport-ws": ["@moq/web-transport-ws@0.1.2", "", {}, "sha512-mYha+AkLNPT3uOGnTA5YWjpxc9LO/yriFSoWzKkR0zN3UMZb9RXbsD8Gbhg1pJZod6QD4tevHoOWTBADYN7yAQ=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.17.1", "", { "os": "android", "cpu": "arm" }, "sha512-+VuZyMYYaap5uDAU1xDU3Kul0FekLqpBS8kI5JozlWfYQKnc/HsZg2gHPkQrj0SC9lt74WMNCfOzZZJlYXSdEQ=="], + + "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.17.1", "", { "os": "android", "cpu": "arm64" }, "sha512-YlDDTjvOEKhom/cRSVsXsMVeXVIAM9PJ/x2mfe08rfuS0iIEfJd8PngKbEIhG72WPxleUa+vkEZj9ncmC14z3Q=="], + + "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.17.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HOYYLSY4JDk14YkXaz/ApgJYhgDP4KsG8EZpgpOxdszGW9HmIMMY/vXqVKYW74dSH+GQkIXYxBrEh3nv+XODVg=="], + + "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.17.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-JHPJbsa5HvPq2/RIdtGlqfaG9zV2WmgvHrKTYmlW0L5esqtKCBuetFudXTBzkNcyD69kSZLzH92AzTr6vFHMFg=="], + + "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.17.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UD1FRC8j8xZstFXYsXwQkNmmg7vUbee006IqxokwDUUA+xEgKZDpLhBEiVKM08Urb+bn7Q0gn6M1pyNR0ng5mg=="], + + "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.17.1", "", { "os": "linux", "cpu": "arm" }, "sha512-wFWC1wyf2ROFWTxK5x0Enm++DSof3EBQ/ypyAesMDLiYxOOASDoMOZG1ylWUnlKaCt5W7eNOWOzABpdfFf/ssA=="], + + "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.17.1", "", { "os": "linux", "cpu": "arm" }, "sha512-k/hUif0GEBk/csSqCfTPXb8AAVs1NNWCa/skBghvNbTtORcWfOVqJ3mM+2pE189+enRm4UnryLREu5ysI0kXEQ=="], + + "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.17.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Cwm6A071ww60QouJ9LoHAwBgEoZzHQ0Qaqk2E7WLfBdiQN9mLXIDhnrpn04hlRElRPhLiu/dtg+o5PPLvaINXQ=="], + + "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.17.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+hwlE2v3m0r3sk93SchJL1uyaKcPjf+NGO/TD2DZUDo+chXx7FfaEj0nUMewigSt7oZ2sQN9Z4NJOtUa75HE5Q=="], + + "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.17.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-bO+rsaE5Ox8cFyeL5Ct5tzot1TnQpFa/Wmu5k+hqBYSH2dNVDGoi0NizBN5QV8kOIC6O5MZr81UG4yW/2FyDTA=="], + + "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.17.1", "", { "os": "linux", "cpu": "none" }, "sha512-B/P+hxKQ1oX4YstI9Lyh4PGzqB87Ddqj/A4iyRBbPdXTcxa+WW3oRLx1CsJKLmHPdDk461Hmbghq1Bm3pl+8Aw=="], + + "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.17.1", "", { "os": "linux", "cpu": "none" }, "sha512-ulp2H3bFXzd/th2maH+QNKj5qgOhJ3v9Yspdf1svTw3CDOuuTl6sRKsWQ7MUw0vnkSNvQndtflBwVXgzZvURsQ=="], + + "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.17.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-LAXYVe3rKk09Zo9YKF2ZLBcH8sz8Oj+JIyiUxiHtq0hiYLMsN6dOpCf2hzQEjPAmsSEA/hdC1PVKeXo+oma8mQ=="], + + "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.17.1", "", { "os": "linux", "cpu": "x64" }, "sha512-3RAhxipMKE8RCSPn7O//sj440i+cYTgYbapLeOoDvQEt6R1QcJjTsFgI4iz99FhVj3YbPxlZmcLB5VW+ipyRTA=="], + + "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.17.1", "", { "os": "linux", "cpu": "x64" }, "sha512-wpjMEubGU8r9VjZTLdZR3aPHaBqTl8Jl8F4DBbgNoZ+yhkhQD1/MGvY70v2TLnAI6kAHSvcqgfvaqKDa2iWsPQ=="], + + "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.17.1", "", { "os": "none", "cpu": "arm64" }, "sha512-XIE4w17RYAVIgx+9Gs3deTREq5tsmalbatYOOBGNdH7n0DfTE600c7wYXsp7ANc3BPDXsInnOzXDEPCvO1F6cg=="], + + "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.17.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-Lqi5BlHX3zS4bpSOkIbOKVf7DIk6Gvmdifr2OuOI58eUUyP944M8/OyaB09cNpPy9Vukj7nmmhOzj8pwLgAkIg=="], + + "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.17.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-l6lTcLBQVj1HNquFpXSsrkCIM8X5Hlng5YNQJrg00z/KyovvDV5l3OFhoRyZ+aLBQ74zUnMRaJZC7xcBnHyeNg=="], + + "@oxc-resolver/binding-win32-ia32-msvc": ["@oxc-resolver/binding-win32-ia32-msvc@11.17.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-VTzVtfnCCsU/6GgvursWoyZrhe3Gj/RyXzDWmh4/U1Y3IW0u1FZbp+hCIlBL16pRPbDc5YvXVtCOnA41QOrOoQ=="], + + "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.17.1", "", { "os": "win32", "cpu": "x64" }, "sha512-jRPVU+6/12baj87q2+UGRh30FBVBzqKdJ7rP/mSqiL1kpNQB9yZ1j0+m3sru1m+C8hiFK7lBFwjUtYUBI7+UpQ=="], + "@poppinss/colors": ["@poppinss/colors@4.1.6", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg=="], "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], @@ -477,6 +540,16 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw=="], + "@rushstack/node-core-library": ["@rushstack/node-core-library@5.19.1", "", { "dependencies": { "ajv": "~8.13.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1", "fs-extra": "~11.3.0", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", "semver": "~7.5.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-ESpb2Tajlatgbmzzukg6zyAhH+sICqJR2CNXNhXcEbz6UGCQfrKCtkxOpJTftWc8RGouroHG0Nud1SJAszvpmA=="], + + "@rushstack/problem-matcher": ["@rushstack/problem-matcher@0.1.1", "", { "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA=="], + + "@rushstack/rig-package": ["@rushstack/rig-package@0.6.0", "", { "dependencies": { "resolve": "~1.22.1", "strip-json-comments": "~3.1.1" } }, "sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw=="], + + "@rushstack/terminal": ["@rushstack/terminal@0.21.0", "", { "dependencies": { "@rushstack/node-core-library": "5.19.1", "@rushstack/problem-matcher": "0.1.1", "supports-color": "~8.1.1" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-cLaI4HwCNYmknM5ns4G+drqdEB6q3dCPV423+d3TZeBusYSSm09+nR7CnhzJMjJqeRcdMAaLnrA4M/3xDz4R3w=="], + + "@rushstack/ts-command-line": ["@rushstack/ts-command-line@5.2.0", "", { "dependencies": { "@rushstack/terminal": "0.21.0", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-lYxCX0nDdkDtCkVpvF0m25ymf66SaMWuppbD6b7MdkIzvGXKBXNIVZlwBH/C0YfkanrupnICWf2n4z3AKSfaHw=="], + "@shikijs/core": ["@shikijs/core@2.5.0", "", { "dependencies": { "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg=="], "@shikijs/engine-javascript": ["@shikijs/engine-javascript@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^3.1.0" } }, "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w=="], @@ -543,6 +616,10 @@ "@ts-graphviz/core": ["@ts-graphviz/core@2.0.7", "", { "dependencies": { "@ts-graphviz/ast": "^2.0.7", "@ts-graphviz/common": "^2.1.5" } }, "sha512-w071DSzP94YfN6XiWhOxnLpYT3uqtxJBDYdh6Jdjzt+Ce6DNspJsPQgpC7rbts/B8tEkq0LHoYuIF/O5Jh5rPg=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="], + "@types/audioworklet": ["@types/audioworklet@0.0.77", "", {}, "sha512-aPQ0DurtnDRWO3qvu8iK1R0aDlKS7sDOWx7MVhMWkGTmlyfnf50GPKYJlKdq8UP159ntPiqPJ5XZ/2v1R0V0Bw=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -597,6 +674,12 @@ "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="], + "@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="], + + "@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="], + + "@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="], + "@vue/compiler-core": ["@vue/compiler-core@3.5.26", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.26", "entities": "^7.0.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w=="], "@vue/compiler-dom": ["@vue/compiler-dom@3.5.26", "", { "dependencies": { "@vue/compiler-core": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A=="], @@ -605,12 +688,16 @@ "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.26", "", { "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw=="], + "@vue/compiler-vue2": ["@vue/compiler-vue2@2.7.16", "", { "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" } }, "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A=="], + "@vue/devtools-api": ["@vue/devtools-api@7.7.9", "", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="], "@vue/devtools-kit": ["@vue/devtools-kit@7.7.9", "", { "dependencies": { "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA=="], "@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="], + "@vue/language-core": ["@vue/language-core@2.2.0", "", { "dependencies": { "@volar/language-core": "~2.4.11", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^0.4.9", "minimatch": "^9.0.3", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw=="], + "@vue/reactivity": ["@vue/reactivity@3.5.26", "", { "dependencies": { "@vue/shared": "3.5.26" } }, "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ=="], "@vue/runtime-core": ["@vue/runtime-core@3.5.26", "", { "dependencies": { "@vue/reactivity": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q=="], @@ -629,26 +716,62 @@ "@vueuse/shared": ["@vueuse/shared@12.8.2", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w=="], + "@web/config-loader": ["@web/config-loader@0.1.3", "", { "dependencies": { "semver": "^7.3.4" } }, "sha512-XVKH79pk4d3EHRhofete8eAnqto1e8mCRAqPV00KLNFzCWSe8sWmLnqKCqkPNARC6nksMaGrATnA5sPDRllMpQ=="], + + "@xn-sakina/rml-darwin-arm64": ["@xn-sakina/rml-darwin-arm64@2.6.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RuFHj6ro6Q24gPqNQGvH4uxpsvbgqBBy+ZUK+jbMuMaw4wyti7F6klQWuikBJAxhWpmRbhAB/jrq0PC82qlh5A=="], + + "@xn-sakina/rml-darwin-x64": ["@xn-sakina/rml-darwin-x64@2.6.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-85bsP7viqtgw5nVYBdl8I4c2+q4sYFcBMTeFnTf4RqhUUwBLerP7D+XXnWwv3waO+aZ0Fe0ij9Fji3oTiREOCg=="], + + "@xn-sakina/rml-linux-arm-gnueabihf": ["@xn-sakina/rml-linux-arm-gnueabihf@2.6.0", "", { "os": "linux", "cpu": "arm" }, "sha512-ySI529TPraG1Mf/YiKhLLNGJ1js0Y3BnZRAihUpF4IlyFKmeL3slXEdvK2tVndyX2O21EYWv/DcSAmFMNOolfA=="], + + "@xn-sakina/rml-linux-arm64-gnu": ["@xn-sakina/rml-linux-arm64-gnu@2.6.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Ytzkmty4vVWAqe+mbu/ql5dqwUH49eVgPT38uJK78LTZRsdogxlQbuAoLKlb/N8CIXAE7BRoywz3lSEGToXylw=="], + + "@xn-sakina/rml-linux-arm64-musl": ["@xn-sakina/rml-linux-arm64-musl@2.6.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-DIBSDWlTmWk+r6Xp7mL9Cw8DdWNyJGg7YhOV1sSSRykdGs2TNtS3z0nbHRuUBMqrbtDk0IwqFSepLx12Bix/zw=="], + + "@xn-sakina/rml-linux-x64-gnu": ["@xn-sakina/rml-linux-x64-gnu@2.6.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8Pks6hMicFGWYQmylKul7Gmn64pG4HkRL7skVWEPAF0LZHeI5yvV/EnQUnXXbxPp4Viy2H4420jl6BVS7Uetng=="], + + "@xn-sakina/rml-linux-x64-musl": ["@xn-sakina/rml-linux-x64-musl@2.6.0", "", { "os": "linux", "cpu": "x64" }, "sha512-xHX/rNKcATVrJt2no0FdO6kqnV4P5cP/3MgHA0KwhD/YJmWa66JIfWtzrPv9n/s0beGSorLkh8PLt5lVLFGvlQ=="], + + "@xn-sakina/rml-win32-arm64-msvc": ["@xn-sakina/rml-win32-arm64-msvc@2.6.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-aIOu5frDsxRp5naN6YjBtbCHS4K2WHIx2EClGclv3wGFrOn1oSROxpVOV/MODUuWITj/26pWbZ/tnbvva6ZV8A=="], + + "@xn-sakina/rml-win32-x64-msvc": ["@xn-sakina/rml-win32-x64-msvc@2.6.0", "", { "os": "win32", "cpu": "x64" }, "sha512-XXbzy2gLEs6PpHdM2IUC5QujOIjz6LpSQpJ+ow43gVc7BhagIF5YlMyTFZCbJehjK9yNgPCzdrzsukCjsH5kIA=="], + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], + "ajv": ["ajv@8.12.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA=="], + + "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], + + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + "algoliasearch": ["algoliasearch@5.46.2", "", { "dependencies": { "@algolia/abtesting": "1.12.2", "@algolia/client-abtesting": "5.46.2", "@algolia/client-analytics": "5.46.2", "@algolia/client-common": "5.46.2", "@algolia/client-insights": "5.46.2", "@algolia/client-personalization": "5.46.2", "@algolia/client-query-suggestions": "5.46.2", "@algolia/client-search": "5.46.2", "@algolia/ingestion": "1.46.2", "@algolia/monitoring": "1.46.2", "@algolia/recommend": "5.46.2", "@algolia/requester-browser-xhr": "5.46.2", "@algolia/requester-fetch": "5.46.2", "@algolia/requester-node-http": "5.46.2" } }, "sha512-qqAXW9QvKf2tTyhpDA4qXv1IfBwD2eduSW6tUEBFIfCeE9gn9HQ9I5+MaKoenRuHrzk5sQoNh1/iof8mY7uD6Q=="], + "alien-signals": ["alien-signals@0.4.14", "", {}, "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + "app-module-path": ["app-module-path@2.2.0", "", {}, "sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ=="], "aproba": ["aproba@2.1.0", "", {}, "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="], "are-we-there-yet": ["are-we-there-yet@3.0.1", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg=="], + "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + "array-back": ["array-back@6.2.2", "", {}, "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw=="], + + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], + "ast-module-types": ["ast-module-types@6.0.1", "", {}, "sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA=="], "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], @@ -669,6 +792,8 @@ "baseline-browser-mapping": ["baseline-browser-mapping@2.9.14", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg=="], + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], "birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="], @@ -705,6 +830,8 @@ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + "chokidar": ["chokidar@3.5.2", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ=="], + "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], @@ -737,16 +864,24 @@ "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + "command-line-args": ["command-line-args@5.1.2", "", { "dependencies": { "array-back": "^6.1.2", "find-replace": "^3.0.0", "lodash.camelcase": "^4.3.0", "typical": "^4.0.0" } }, "sha512-fytTsbndLbl+pPWtS0CxLV3BEWw9wJayB8NnU2cbQqVPsNdYezQeT+uIQv009m+GShnMNyuoBrRo8DTmuTfSCA=="], + "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], + "comment-parser": ["comment-parser@1.2.4", "", {}, "sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw=="], + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + "compare-versions": ["compare-versions@6.1.1", "", {}, "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="], + "component-register": ["component-register@0.8.8", "", {}, "sha512-djhwcxjY+X9dacaYUEOkOm7tda8uOEDiMDigWysu3xv54M8o6XDlsjR1qt5Y8QLGiKg51fqXFIR2HUTmt9ys0Q=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], + "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], + "connect-history-api-fallback": ["connect-history-api-fallback@1.6.0", "", {}, "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="], "consola": ["consola@2.15.3", "", {}, "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="], @@ -769,6 +904,12 @@ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "custom-elements-manifest": ["custom-elements-manifest@1.0.0", "", {}, "sha512-j59k0ExGCKA8T6Mzaq+7axc+KVHwpEphEERU7VZ99260npu/p/9kd+Db+I3cGKxHkM5y6q5gnlXn00mzRQkX2A=="], + + "de-indent": ["de-indent@1.0.2", "", {}, "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg=="], + + "debounce": ["debounce@1.2.1", "", {}, "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], @@ -807,6 +948,10 @@ "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + "diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="], + + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], "dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], @@ -869,6 +1014,10 @@ "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], @@ -883,6 +1032,8 @@ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + "find-replace": ["find-replace@3.0.0", "", { "dependencies": { "array-back": "^3.0.1" } }, "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ=="], + "focus-trap": ["focus-trap@7.8.0", "", { "dependencies": { "tabbable": "^6.4.0" } }, "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA=="], "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], @@ -923,6 +1074,8 @@ "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + "globby": ["globby@11.0.4", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.1.1", "ignore": "^5.1.4", "merge2": "^1.3.0", "slash": "^3.0.0" } }, "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg=="], + "gonzales-pe": ["gonzales-pe@4.3.0", "", { "dependencies": { "minimist": "^1.2.5" }, "bin": { "gonzales": "bin/gonzales.js" } }, "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ=="], "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], @@ -957,6 +1110,10 @@ "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="], + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], @@ -967,6 +1124,8 @@ "is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="], + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -997,18 +1156,24 @@ "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "jju": ["jju@1.4.0", "", {}, "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="], + "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], @@ -1033,6 +1198,12 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], + "local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], + + "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], @@ -1097,6 +1268,8 @@ "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], + "module-definition": ["module-definition@6.0.1", "", { "dependencies": { "ast-module-types": "^6.0.1", "node-source-walk": "^7.0.1" }, "bin": { "module-definition": "bin/cli.js" } }, "sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g=="], "module-lookup-amd": ["module-lookup-amd@9.0.5", "", { "dependencies": { "commander": "^12.1.0", "glob": "^7.2.3", "requirejs": "^2.3.7", "requirejs-config-file": "^4.0.0" }, "bin": { "lookup-amd": "bin/cli.js" } }, "sha512-Rs5FVpVcBYRHPLuhHOjgbRhosaQYLtEo3JIeDIbmNo7mSssi1CTzwMh8v36gAzpbzLGXI9wB/yHh+5+3fY1QVw=="], @@ -1105,6 +1278,8 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="], + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], @@ -1123,6 +1298,8 @@ "node-source-walk": ["node-source-walk@7.0.1", "", { "dependencies": { "@babel/parser": "^7.26.7" } }, "sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg=="], + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "npmlog": ["npmlog@6.0.2", "", { "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.3", "set-blocking": "^2.0.0" } }, "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg=="], "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], @@ -1135,6 +1312,8 @@ "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + "oxc-resolver": ["oxc-resolver@11.17.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.17.1", "@oxc-resolver/binding-android-arm64": "11.17.1", "@oxc-resolver/binding-darwin-arm64": "11.17.1", "@oxc-resolver/binding-darwin-x64": "11.17.1", "@oxc-resolver/binding-freebsd-x64": "11.17.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.17.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.17.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.17.1", "@oxc-resolver/binding-linux-arm64-musl": "11.17.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.17.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.17.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.17.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.17.1", "@oxc-resolver/binding-linux-x64-gnu": "11.17.1", "@oxc-resolver/binding-linux-x64-musl": "11.17.1", "@oxc-resolver/binding-openharmony-arm64": "11.17.1", "@oxc-resolver/binding-wasm32-wasi": "11.17.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.17.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.17.1", "@oxc-resolver/binding-win32-x64-msvc": "11.17.1" } }, "sha512-pyRXK9kH81zKlirHufkFhOFBZRks8iAMLwPH8gU7lvKFiuzUH9L8MxDEllazwOb8fjXMcWjY1PMDfMJ2/yh5cw=="], + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], "param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="], @@ -1145,6 +1324,8 @@ "pascal-case": ["pascal-case@3.1.2", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="], + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], @@ -1153,6 +1334,8 @@ "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + "pathe": ["pathe@0.2.0", "", {}, "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw=="], "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], @@ -1161,6 +1344,8 @@ "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], @@ -1183,6 +1368,10 @@ "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "quote-unquote": ["quote-unquote@1.0.0", "", {}, "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg=="], @@ -1191,6 +1380,8 @@ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], @@ -1203,6 +1394,8 @@ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "requirejs": ["requirejs@2.3.8", "", { "bin": { "r.js": "bin/r.js", "r_js": "bin/r.js" } }, "sha512-7/cTSLOdYkNBNJcDMWf+luFvMriVm7eYxp4BcFCsAX0wF421Vyce5SXP17c+Jd5otXKGNehIonFlyQXSowL6Mw=="], "requirejs-config-file": ["requirejs-config-file@4.0.0", "", { "dependencies": { "esprima": "^4.0.0", "stringify-object": "^3.2.1" } }, "sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw=="], @@ -1221,6 +1414,8 @@ "rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="], + "rs-module-lexer": ["rs-module-lexer@2.6.0", "", { "optionalDependencies": { "@xn-sakina/rml-darwin-arm64": "2.6.0", "@xn-sakina/rml-darwin-x64": "2.6.0", "@xn-sakina/rml-linux-arm-gnueabihf": "2.6.0", "@xn-sakina/rml-linux-arm64-gnu": "2.6.0", "@xn-sakina/rml-linux-arm64-musl": "2.6.0", "@xn-sakina/rml-linux-x64-gnu": "2.6.0", "@xn-sakina/rml-linux-x64-musl": "2.6.0", "@xn-sakina/rml-win32-arm64-msvc": "2.6.0", "@xn-sakina/rml-win32-x64-msvc": "2.6.0" } }, "sha512-aT0lO0icZ3Hq0IWvo+ORgVc6BJDoKfaDBdRIDQkL2PtBnFQJ0DuvExiiWI4GxjEjH8Yyro++NPArHFaD8bvS9w=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], @@ -1253,6 +1448,8 @@ "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "solid-element": ["solid-element@1.9.1", "", { "dependencies": { "component-register": "^0.8.7" }, "peerDependencies": { "solid-js": "^1.9.3" } }, "sha512-baJy6Qz27oAUgkPlqOf3Y+7RsBiuVQrS51Nrh1ddDbrqrNPvJbIvehpUsTzLNFb2ZHIoHuNnDg330go/ZKcRdg=="], "solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="], @@ -1269,10 +1466,14 @@ "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="], + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], "stream-to-array": ["stream-to-array@2.3.0", "", { "dependencies": { "any-promise": "^1.1.0" } }, "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA=="], + "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], @@ -1331,6 +1532,10 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typical": ["typical@4.0.0", "", {}, "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="], + + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + "undici": ["undici@7.14.0", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], @@ -1355,6 +1560,8 @@ "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], @@ -1365,6 +1572,8 @@ "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + "vite-plugin-dts": ["vite-plugin-dts@4.5.4", "", { "dependencies": { "@microsoft/api-extractor": "^7.50.1", "@rollup/pluginutils": "^5.1.4", "@volar/typescript": "^2.4.11", "@vue/language-core": "2.2.0", "compare-versions": "^6.1.1", "debug": "^4.4.0", "kolorist": "^1.8.0", "local-pkg": "^1.0.0", "magic-string": "^0.30.17" }, "peerDependencies": { "typescript": "*", "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg=="], + "vite-plugin-html": ["vite-plugin-html@3.2.2", "", { "dependencies": { "@rollup/pluginutils": "^4.2.0", "colorette": "^2.0.16", "connect-history-api-fallback": "^1.6.0", "consola": "^2.15.3", "dotenv": "^16.0.0", "dotenv-expand": "^8.0.2", "ejs": "^3.1.6", "fast-glob": "^3.2.11", "fs-extra": "^10.0.1", "html-minifier-terser": "^6.1.0", "node-html-parser": "^5.3.3", "pathe": "^0.2.0" }, "peerDependencies": { "vite": ">=2.0.0" } }, "sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q=="], "vite-plugin-solid": ["vite-plugin-solid@2.11.10", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw=="], @@ -1373,6 +1582,8 @@ "vitepress": ["vitepress@1.6.4", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg=="], + "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="], + "vue": ["vue@3.5.26", "", { "dependencies": { "@vue/compiler-dom": "3.5.26", "@vue/compiler-sfc": "3.5.26", "@vue/runtime-dom": "3.5.26", "@vue/server-renderer": "3.5.26", "@vue/shared": "3.5.26" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA=="], "walkdir": ["walkdir@0.4.1", "", {}, "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ=="], @@ -1419,10 +1630,26 @@ "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@custom-elements-manifest/analyzer/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="], + + "@microsoft/api-extractor/minimatch": ["minimatch@10.1.2", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.1" } }, "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw=="], + + "@microsoft/api-extractor/semver": ["semver@7.5.4", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" } }, "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA=="], + + "@microsoft/api-extractor/typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], + "@moq/hang-ui/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "@rushstack/node-core-library/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], + + "@rushstack/node-core-library/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + + "@rushstack/node-core-library/semver": ["semver@7.5.4", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" } }, "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA=="], + + "@rushstack/rig-package/strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], @@ -1439,6 +1666,12 @@ "@vue/compiler-core/entities": ["entities@7.0.0", "", {}, "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ=="], + "@vue/language-core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "ajv-formats/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -1455,6 +1688,8 @@ "filing-cabinet/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "find-replace/array-back": ["array-back@3.1.0", "", {}, "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="], + "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "html-minifier-terser/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], @@ -1469,12 +1704,20 @@ "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "module-lookup-amd/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "module-lookup-amd/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "precinct/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "sass-lookup/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "stylus-lookup/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], @@ -1499,8 +1742,16 @@ "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "@microsoft/api-extractor/minimatch/@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.1", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ=="], + + "@microsoft/api-extractor/semver/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "@moq/hang-ui/vite/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + "@rushstack/node-core-library/semver/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "module-lookup-amd/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "unplugin-solid/merge-anything/is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], diff --git a/js/hang-ui/README.md b/js/hang-ui/README.md index 776f58ea0..539249770 100644 --- a/js/hang-ui/README.md +++ b/js/hang-ui/README.md @@ -37,15 +37,11 @@ Here's how you can use them (see also @moq/hang-demo for a complete example): ``` ```html - - - - - + + + + + ``` ## Project Structure @@ -108,3 +104,132 @@ Common components and utilities used across the package. - **Icon**: Icon wrapper component - **Stats**: Provides real-time statistics monitoring for both audio and video streams. Uses a provider pattern to collect and display metrics. - **CSS utilities**: Shared styles, variables, and flexbox utilities + +--- + +## Build System & Code Generation + +This package uses Custom Elements Manifest (CEM) to automatically generate framework-specific wrappers. + +### How It Works + +1. **CEM analysis** (`cem analyze`) scans Web Components and creates `custom-elements.json` +2. **JSDoc enhancement** extracts `@tag`, `@summary`, `@example` from source files +3. **Wrapper generation** creates typed framework components in `src/wrappers//` + +### Available Scripts + +```bash +bun run prebuild # Generate CEM + framework wrappers +bun run build # Build package with Vite + TypeScript declarations +``` + +The code generator lives in `../scripts/element-wrappers/`: + +### React Wrappers + +Auto-generated from CEM, exported from `@moq/hang-ui/react`: + +```tsx +import { HangWatchUI, HangPublishUI } from '@moq/hang-ui/react'; + + + + + + +``` + +### Generating Wrappers for Other Frameworks + +To add Vue, Angular, or other frameworks: + +#### 1. Create Generator + +Create `../scripts/element-wrappers/generators/vue.ts`: + +```ts +import { mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { extractCustomElements, loadManifest, tagNameToComponentName } from "../utils/manifest"; +import { formatCode, generateJSDoc } from "../utils/codegen"; + +function generateVueComponent(element) { + const name = tagNameToComponentName(element.tagName); + const jsDoc = generateJSDoc( + element.summary, element.description, + element.slots, element.events, + element.attributes, element.properties, + element.examples + ); + + return `${jsDoc} +export const ${name} = defineComponent({ + name: '${name}', + template: '<${element.tagName}>', +});`; +} + +export function generateVueWrappers(basePath = process.cwd()) { + console.log("\nπŸ”§ Generating Vue wrappers..."); + + const manifest = loadManifest(basePath); + const elements = extractCustomElements(manifest); + if (elements.length === 0) return; + + const output = `import { defineComponent } from 'vue';\n\n${ + elements.map(generateVueComponent).join("\n") + }`; + + const outputDir = join(basePath, "src", "wrappers", "vue"); + mkdirSync(outputDir, { recursive: true }); + writeFileSync(join(outputDir, "index.ts"), formatCode(output)); + + console.log(`βœ… Generated ${elements.length} Vue wrapper(s)`); +} +``` + +#### 2. Register Generator + +In `../scripts/element-wrappers/index.ts`: + +```ts +import { generateVueWrappers } from "./generators/vue"; + +const generators = [ + { name: "React", fn: generateReactWrappers, enabled: true }, + { name: "Vue", fn: generateVueWrappers, enabled: true }, +]; +``` + +#### 3. Update Package Configuration + +**package.json** - Add export: +```json +{ + "exports": { + "./vue": { + "types": "./wrappers/vue/index.d.ts", + "default": "./src/wrappers/vue/index.ts" + } + } +} +``` + +**vite.config.ts** - Add build entry: +```ts +entry: { + "wrappers/vue/index": resolve(__dirname, "src/wrappers/vue/index.ts"), +} +``` + +#### 4. Run + +```bash +bun run prebuild # Generates src/wrappers/vue/index.ts +bun run build # Compiles to dist/ +``` + +For more details, see [`../scripts/element-wrappers/README.md`](../scripts/element-wrappers/README.md). + +--- diff --git a/js/hang-ui/cem.config.js b/js/hang-ui/cem.config.js new file mode 100644 index 000000000..a332611fe --- /dev/null +++ b/js/hang-ui/cem.config.js @@ -0,0 +1,5 @@ +export default { + globs: ["src/publish/index.tsx", "src/watch/index.tsx"], + exclude: ["src/**/components/**", "src/**/hooks/**", "src/shared/**"], + outdir: ".", +}; diff --git a/js/hang-ui/package.json b/js/hang-ui/package.json index 46fd7cdbf..d4b908bfd 100644 --- a/js/hang-ui/package.json +++ b/js/hang-ui/package.json @@ -6,15 +6,26 @@ "license": "(MIT OR Apache-2.0)", "repository": "github:moq-dev/moq", "exports": { - "./publish": "./src/publish/index.tsx", - "./watch": "./src/watch/index.tsx" + "./publish": { + "types": "./publish/index.d.ts", + "default": "./src/publish/index.tsx" + }, + "./watch": { + "types": "./watch/index.d.ts", + "default": "./src/watch/index.tsx" + }, + "./react": { + "types": "./wrappers/react/index.d.ts", + "default": "./src/wrappers/react/index.ts" + } }, "sideEffects": [ "./src/publish/index.tsx", "./src/watch/index.tsx" ], "scripts": { - "build": "bun run clean && vite build && bun ../scripts/package.ts", + "prebuild": "bunx cem analyze --config cem.config.js && bun ../scripts/element-wrappers/index.ts", + "build": "bun run clean && vite build && cp custom-elements.json dist/ && bun ../scripts/package.ts", "check": "tsc --noEmit", "clean": "rimraf dist", "fix": "biome check src --fix", @@ -25,6 +36,7 @@ "@moq/signals": "workspace:^0.1.0" }, "devDependencies": { + "@custom-elements-manifest/analyzer": "^0.11.0", "@types/audioworklet": "^0.0.77", "@typescript/lib-dom": "npm:@types/web@^0.0.241", "rimraf": "^6.0.1", @@ -33,6 +45,8 @@ "typescript": "^5.9.2", "unplugin-solid": "^1.0.0", "vite": "^7.3.1", + "vite-plugin-dts": "^4.5.4", "vite-plugin-solid": "^2.11.10" - } + }, + "customElements": "custom-elements.json" } diff --git a/js/hang-ui/src/publish/element.tsx b/js/hang-ui/src/publish/element.tsx index 91974f173..85ac58812 100644 --- a/js/hang-ui/src/publish/element.tsx +++ b/js/hang-ui/src/publish/element.tsx @@ -1,16 +1,11 @@ import type HangPublish from "@moq/hang/publish/element"; import PublishControls from "./components/PublishControls"; import PublishControlsContextProvider from "./context"; -import styles from "./styles/index.css?inline"; export function PublishUI(props: { publish: HangPublish }) { return ( - <> - - - - - - + + + ); } diff --git a/js/hang-ui/src/publish/index.tsx b/js/hang-ui/src/publish/index.tsx index 509ab33a8..5c88a054d 100644 --- a/js/hang-ui/src/publish/index.tsx +++ b/js/hang-ui/src/publish/index.tsx @@ -1,27 +1,74 @@ import type HangPublish from "@moq/hang/publish/element"; -import { customElement } from "solid-element"; -import { createSignal, onMount } from "solid-js"; -import { Show } from "solid-js/web"; +import { render } from "solid-js/web"; import { PublishUI } from "./element.tsx"; +import styles from "./styles/index.css?inline"; -customElement("hang-publish-ui", (_, { element }) => { - const [nested, setNested] = createSignal(); +/** + * @tag hang-publish-ui + * @summary Publish audio/video stream with UI controls + * @description A custom element that provides a complete user interface for publishing live video or audio streams + * over Media over QUIC (MOQ). Includes media source selection (camera, microphone, screen, file) and publishing controls. + * + * @slot default - Container for the hang-publish element + * + * @example HTML + * ```html + * + * + * + * + * ``` + * + * @example React + * ```tsx + * import '@moq/hang/publish/element'; + * import '@moq/hang-ui/publish'; + * import { HangPublishUI } from '@moq/hang-ui/react'; + * + * export function HangPublishComponent({ url, path }) { + * return ( + * + * + * + * ); + * } + * ``` + */ +class HangPublishComponent extends HTMLElement { + #root?: ShadowRoot; + #dispose?: () => void; + #connected = false; - onMount(async () => { - await customElements.whenDefined("hang-publish"); - const publishEl = element.querySelector("hang-publish"); - setNested(publishEl ? (publishEl as HangPublish) : undefined); - }); + connectedCallback() { + this.#connected = true; - return ( - - {(publish: HangPublish) => } - - ); -}); + // Reuse existing shadow root on reconnect (attachShadow throws if called twice) + this.#root ??= this.attachShadow({ mode: "open" }); -declare global { - interface HTMLElementTagNameMap { - "hang-publish-ui": HTMLElement; + // Defer render to allow frameworks to append children first + queueMicrotask(() => { + if (!this.#connected || !this.#root) return; + + const publish = this.querySelector("hang-publish") as HangPublish | null; + this.#dispose = render( + () => ( + <> + + + {publish ? : null} + + ), + this.#root, + ); + }); + } + + disconnectedCallback() { + this.#connected = false; + this.#dispose?.(); + this.#dispose = undefined; } } + +customElements.define("hang-publish-ui", HangPublishComponent); +export { HangPublishComponent }; diff --git a/js/hang-ui/src/publish/styles/index.css b/js/hang-ui/src/publish/styles/index.css index 820c6c7a1..77c139519 100644 --- a/js/hang-ui/src/publish/styles/index.css +++ b/js/hang-ui/src/publish/styles/index.css @@ -8,3 +8,9 @@ @import "./source-button.css"; @import "./media-selector.css"; @import "./status-indicator.css"; + +/* Host element default styles */ +:host { + position: relative; + display: block; +} diff --git a/js/hang-ui/src/watch/element.tsx b/js/hang-ui/src/watch/element.tsx index 30f76a94a..16003e924 100644 --- a/js/hang-ui/src/watch/element.tsx +++ b/js/hang-ui/src/watch/element.tsx @@ -6,14 +6,11 @@ import { Stats } from "../shared/components/stats"; import BufferingIndicator from "./components/BufferingIndicator"; import WatchControls from "./components/WatchControls"; import WatchUIContextProvider, { WatchUIContext } from "./context"; -import styles from "./styles/index.css?inline"; export function WatchUI(props: { watch: HangWatch }) { return ( -
- {(() => { const context = useContext(WatchUIContext); if (!context) return null; diff --git a/js/hang-ui/src/watch/index.tsx b/js/hang-ui/src/watch/index.tsx index c33937e00..0eb12d45c 100644 --- a/js/hang-ui/src/watch/index.tsx +++ b/js/hang-ui/src/watch/index.tsx @@ -1,26 +1,77 @@ import type HangWatch from "@moq/hang/watch/element"; -import { customElement } from "solid-element"; -import { createSignal, onMount, Show } from "solid-js"; +import { render } from "solid-js/web"; import { WatchUI } from "./element.tsx"; +import styles from "./styles/index.css?inline"; -customElement("hang-watch-ui", (_, { element }) => { - const [nested, setNested] = createSignal(); +/** + * @tag hang-watch-ui + * @summary Watch video stream with full UI controls + * @description A custom element that provides a complete user interface for watching live or on-demand video streams + * over Media over QUIC (MOQ). Includes playback controls, quality selection, stats panel, and automatic buffering. + * + * @slot default - Container for the hang-watch element and canvas + * + * @example HTML + * ```html + * + * + * + * + * + * ``` + * + * @example React + * ```tsx + * import '@moq/hang/watch/element'; + * import '@moq/hang-ui/watch'; + * import { HangWatchUI } from '@moq/hang-ui/react'; + * + * export function HangWatchComponent({ url, path }) { + * return ( + * + * + * + * + * + * ); + * } + * ``` + */ +class HangWatchComponent extends HTMLElement { + #root?: ShadowRoot; + #dispose?: () => void; + #connected = false; - onMount(async () => { - await customElements.whenDefined("hang-watch"); - const watchEl = element.querySelector("hang-watch"); - setNested(watchEl ? (watchEl as HangWatch) : undefined); - }); + connectedCallback() { + this.#connected = true; - return ( - - {(watch: HangWatch) => } - - ); -}); + // Reuse existing shadow root on reconnect (attachShadow throws if called twice) + this.#root ??= this.attachShadow({ mode: "open" }); -declare global { - interface HTMLElementTagNameMap { - "hang-watch-ui": HTMLElement; + // Defer render to allow frameworks to append children first + queueMicrotask(() => { + if (!this.#connected || !this.#root) return; + + const watch = this.querySelector("hang-watch") as HangWatch | null; + this.#dispose = render( + () => ( + <> + + + {watch ? : null} + + ), + this.#root, + ); + }); + } + + disconnectedCallback() { + this.#connected = false; + this.#dispose?.(); + this.#dispose = undefined; } } + +customElements.define("hang-watch-ui", HangWatchComponent); +export { HangWatchComponent }; diff --git a/js/hang-ui/src/watch/styles/index.css b/js/hang-ui/src/watch/styles/index.css index 995c63553..6981f5979 100644 --- a/js/hang-ui/src/watch/styles/index.css +++ b/js/hang-ui/src/watch/styles/index.css @@ -3,6 +3,12 @@ @import "../../shared/components/button/button.css"; @import "../../shared/components/stats/styles/index.css"; +/* Host element default styles */ +:host { + position: relative; + display: block; +} + /* Color variables for buffer states */ :root { --buffer-green: #4ade80; @@ -12,9 +18,11 @@ .watchVideoContainer { display: block; - position: relative; + position: absolute; + top: 0; + left: 0; width: 100%; - height: auto; + height: 100%; border-radius: 4px; margin: 0 auto; pointer-events: none; @@ -89,6 +97,7 @@ 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } diff --git a/js/hang-ui/vite.config.ts b/js/hang-ui/vite.config.ts index 33ab016c9..398427083 100644 --- a/js/hang-ui/vite.config.ts +++ b/js/hang-ui/vite.config.ts @@ -1,19 +1,29 @@ import { resolve } from "path"; import { defineConfig } from "vite"; +import dts from "vite-plugin-dts"; import solidPlugin from "vite-plugin-solid"; export default defineConfig({ - plugins: [solidPlugin()], + plugins: [ + solidPlugin(), + dts({ + include: ["src"], + outDir: "dist", + entryRoot: "src", + }), + ], build: { lib: { entry: { "publish/index": resolve(__dirname, "src/publish/index.tsx"), "watch/index": resolve(__dirname, "src/watch/index.tsx"), + // Auto-generated by scripts/generate-wrappers.ts during prebuild phase + "wrappers/react/index": resolve(__dirname, "src/wrappers/react/index.ts"), }, formats: ["es"], }, rollupOptions: { - external: ["@moq/hang", "@moq/lite", "@moq/signals"], + external: ["@moq/hang", "@moq/lite", "@moq/signals", "react"], }, sourcemap: true, target: "esnext", diff --git a/js/hang/README.md b/js/hang/README.md index 61ae82a5c..df825a969 100644 --- a/js/hang/README.md +++ b/js/hang/README.md @@ -218,6 +218,38 @@ useEffect(() => { }, [media]); ``` +## Build System & Code Generation + +This package uses Custom Elements Manifest (CEM) to automatically generate framework-specific wrappers. + +### React Wrappers + +Auto-generated from CEM, exported from `@moq/hang/react`: + +```tsx +import { HangWatch, HangPublish } from '@moq/hang/react'; + + + + + + + +``` + +### Generating Wrappers for Other Frameworks + +To add Vue, Angular, or other frameworks, see the [element-wrappers guide](../scripts/element-wrappers/README.md) for step-by-step instructions. + +The process: +1. Create a generator in `../scripts/element-wrappers/generators/.ts` +2. Register it in `../scripts/element-wrappers/index.ts` +3. Add package export in `package.json` +4. Run `bun run prebuild` to generate wrappers + +Full details: [`../scripts/element-wrappers/README.md`](../scripts/element-wrappers/README.md) + ## License Licensed under either: diff --git a/js/hang/cem.config.js b/js/hang/cem.config.js new file mode 100644 index 000000000..34f9674c5 --- /dev/null +++ b/js/hang/cem.config.js @@ -0,0 +1,4 @@ +export default { + globs: ["src/publish/element.ts", "src/watch/element.ts"], + outdir: ".", +}; diff --git a/js/hang/package.json b/js/hang/package.json index 77ae34d23..51a8f39c9 100644 --- a/js/hang/package.json +++ b/js/hang/package.json @@ -13,7 +13,11 @@ "./watch/element": "./src/watch/element.ts", "./catalog": "./src/catalog/index.ts", "./support": "./src/support/index.ts", - "./support/element": "./src/support/element.ts" + "./support/element": "./src/support/element.ts", + "./react": { + "types": "./wrappers/react/index.d.ts", + "default": "./src/wrappers/react/index.ts" + } }, "sideEffects": [ "./src/publish/element.ts", @@ -21,7 +25,8 @@ "./src/support/element.ts" ], "scripts": { - "build": "rimraf dist && tsc -b && bun ../scripts/package.ts", + "prebuild": "bunx cem analyze --config cem.config.js && bun ../scripts/element-wrappers/index.ts", + "build": "rimraf dist && tsc -b && cp custom-elements.json dist/ && bun ../scripts/package.ts", "check": "tsc --noEmit", "test": "bun test --only-failures", "release": "bun ../scripts/release.ts" @@ -37,10 +42,12 @@ "zod": "^4.1.5" }, "devDependencies": { + "@custom-elements-manifest/analyzer": "^0.11.0", "@types/audioworklet": "^0.0.77", "@typescript/lib-dom": "npm:@types/web@^0.0.241", "fast-glob": "^3.3.3", "rimraf": "^6.0.1", "typescript": "^5.9.2" - } + }, + "customElements": "custom-elements.json" } diff --git a/js/hang/src/publish/element.ts b/js/hang/src/publish/element.ts index cc209cd90..9957508eb 100644 --- a/js/hang/src/publish/element.ts +++ b/js/hang/src/publish/element.ts @@ -14,11 +14,54 @@ type SourceType = "camera" | "screen" | "file"; // There's no destructor for web components so this is the best we can do. const cleanup = new FinalizationRegistry((signals) => signals.close()); +/** + * @tag hang-publish + * @summary Publish live video streams over Media over QUIC (MOQ) + * @description A custom element that captures and publishes video/audio streams over the Media over QUIC protocol. + * Supports multiple input sources including camera, screen sharing, and file playback. Handles encoding, + * transmission, and connection management to MOQ relay servers. Includes optional preview via video element. + * + * @attr {string} url - The WebTransport URL of the MOQ relay server (e.g., "https://relay.example.com") + * @attr {string} path - The broadcast path to publish to (e.g., "/live/mystream") + * @attr {string} source - Input source type: "camera", "screen", or "file" + * @attr {boolean} muted - Whether audio is muted (disables audio track) + * @attr {boolean} invisible - Whether video is disabled (disables video track) + * + * @slot default - Optional video element for local preview of the published stream + * + * @example HTML with camera + * ```html + * + * + * + * ``` + * + * @example HTML with screen sharing + * ```html + * + * + * + * ``` + * + * @example React + * ```tsx + * import '@moq/hang/publish/element'; + * import { HangPublish } from '@moq/hang/react'; + * + * export function HangPublishComponent({ url, path }) { + * return ( + * + * + * ); + * } + * ``` + */ export default class HangPublish extends HTMLElement { static observedAttributes = OBSERVED; - url = new Signal(undefined); - path = new Signal(undefined); + #url = new Signal(undefined); + #path = new Signal(undefined); source = new Signal(undefined); // Controls whether audio/video is enabled. @@ -50,7 +93,7 @@ export default class HangPublish extends HTMLElement { cleanup.register(this, this.signals); this.connection = new Moq.Connection.Reload({ - url: this.url, + url: this.#url, enabled: this.#enabled, }); this.signals.cleanup(() => this.connection.close()); @@ -72,7 +115,7 @@ export default class HangPublish extends HTMLElement { this.broadcast = new Broadcast({ connection: this.connection.established, enabled: this.#enabled, - path: this.path, + path: this.#path, audio: { enabled: this.#audioEnabled, @@ -146,6 +189,22 @@ export default class HangPublish extends HTMLElement { } } + get url(): Signal { + return this.#url; + } + + set url(value: string | URL | undefined) { + value ? this.setAttribute("url", String(value)) : this.removeAttribute("url"); + } + + get path(): Signal { + return this.#path; + } + + set path(value: string | Moq.Path.Valid | undefined) { + value ? this.setAttribute("path", String(value)) : this.removeAttribute("path"); + } + #runSource(effect: Effect) { const source = effect.get(this.source); if (!source) return; @@ -225,8 +284,4 @@ export default class HangPublish extends HTMLElement { customElements.define("hang-publish", HangPublish); -declare global { - interface HTMLElementTagNameMap { - "hang-publish": HangPublish; - } -} +export { HangPublish }; diff --git a/js/hang/src/watch/element.ts b/js/hang/src/watch/element.ts index 7834b706f..d8ff9d28a 100644 --- a/js/hang/src/watch/element.ts +++ b/js/hang/src/watch/element.ts @@ -17,7 +17,52 @@ type Observed = (typeof OBSERVED)[number]; // There's no destructor for web components so this is the best we can do. const cleanup = new FinalizationRegistry((signals) => signals.close()); -// An optional web component that wraps a +/** + * @tag hang-watch + * @summary Watch live or on-demand video streams over Media over QUIC (MOQ) + * @description A custom element that provides core playback functionality for watching video streams + * transmitted over Media over QUIC protocol. Wraps a canvas or video element and handles connection, + * decoding, synchronization, and rendering. Supports configurable jitter buffer, volume control, + * pause/resume, and automatic reconnection. + * + * @attr {string} url - The WebTransport URL of the MOQ relay server (e.g., "https://relay.example.com") + * @attr {string} path - The broadcast path to subscribe to (e.g., "/live/stream") + * @attr {boolean} paused - Whether playback is paused + * @attr {number} volume - Audio volume level (0.0 to 1.0, default: 0.5) + * @attr {boolean} muted - Whether audio is muted + * @attr {boolean} reload - Whether to automatically reconnect on connection loss + * @attr {number} jitter - Target jitter buffer in milliseconds (default: 100) + * + * @slot default - Container for the canvas or video element + * + * @example HTML with canvas + * ```html + * + * + * + * ``` + * + * @example HTML with video element + * ```html + * + * + * + * ``` + * + * @example React + * ```tsx + * import '@moq/hang/watch/element'; + * import { HangWatch } from '@moq/hang/react'; + * + * export function HangWatchComponent({ url, path }) { + * return ( + * + * + * + * ); + * } + * ``` + */ export default class HangWatch extends HTMLElement implements Backend { static observedAttributes = OBSERVED; @@ -170,14 +215,26 @@ export default class HangWatch extends HTMLElement implements Backend { return this.connection.url; } + set url(value: string | URL | undefined) { + value ? this.setAttribute("url", String(value)) : this.removeAttribute("url"); + } + get path(): Signal { return this.broadcast.path; } + set path(value: string | Moq.Path.Valid | undefined) { + value ? this.setAttribute("path", String(value)) : this.removeAttribute("path"); + } + get jitter(): Signal { return this.#backend.jitter; } + set jitter(value: string | Time.Milli | undefined) { + value != null ? this.setAttribute("jitter", String(value)) : this.removeAttribute("jitter"); + } + get paused(): Signal { return this.#backend.paused; } @@ -193,8 +250,4 @@ export default class HangWatch extends HTMLElement implements Backend { customElements.define("hang-watch", HangWatch); -declare global { - interface HTMLElementTagNameMap { - "hang-watch": HangWatch; - } -} +export { HangWatch }; diff --git a/js/scripts/element-wrappers/README.md b/js/scripts/element-wrappers/README.md new file mode 100644 index 000000000..5d2f5ecc3 --- /dev/null +++ b/js/scripts/element-wrappers/README.md @@ -0,0 +1,173 @@ +# Element Wrappers β€” Code Generation + +Generates typed framework wrappers from [Custom Elements Manifest](https://custom-elements-manifest.open-wc.org/) (CEM). + +**Input:** `custom-elements.json` + JSDoc annotations β†’ **Output:** Framework components with full TypeScript support + +## Architecture + +```text +element-wrappers/ +β”œβ”€β”€ index.ts # Orchestrator β€” runs all enabled generators +β”œβ”€β”€ generators/ +β”‚ └── react.ts # React wrapper generator (forwardRef + JSX types) +└── utils/ + β”œβ”€β”€ manifest.ts # CEM loader + JSDoc metadata extraction + β”œβ”€β”€ codegen.ts # JSDoc generation + code formatting + └── types.ts # TypeScript interfaces for CEM structures +``` + +## How It Works + +### 1. CEM Analysis + +```bash +bunx cem analyze --config cem.config.js +``` + +Generates `custom-elements.json` from your Web Component source files. + +### 2. JSDoc Enhancement + +The loader scans all `.ts`/`.tsx` files in `src/` and extracts: + +| Annotation | Purpose | +| -------------- | ------------------------------------ | +| `@tag` | Custom element tag name | +| `@summary` | Brief one-line description | +| `@description` | Detailed description | +| `@attr` | Attribute with type and description | +| `@slot` | Slot definition | +| `@example` | Labeled code example (HTML, React…) | + +Example: + +```typescript +/** + * @tag my-player + * @summary Video player component + * @description Renders live or on-demand video over MOQ. + * + * @attr {string} url - Relay server URL + * @attr {boolean} muted - Mute audio + * + * @example HTML + * ```html + * + * ``` + * + * @example React + * ```tsx + * + * ``` + */ +export class MyPlayerElement extends HTMLElement { } +``` + +### 3. Wrapper Generation + +Each enabled generator creates framework-specific code: + +- **React** β€” `React.forwardRef` components, typed props from CEM attributes, `JSX.IntrinsicElements` augmentation + +## Usage + +Add to your package's `package.json`: + +```json +{ + "scripts": { + "prebuild": "bunx cem analyze && bun ../scripts/element-wrappers/index.ts" + } +} +``` + +Output: `src/wrappers//index.ts` (auto-generated, add to `.gitignore`) + +## Adding a New Framework + +### 1. Create the Generator + +Create `generators/.ts`: + +```typescript +import { mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { formatCode, generateJSDoc } from "../utils/codegen"; +import { extractCustomElements, loadManifest, tagNameToComponentName } from "../utils/manifest"; +import type { CustomElement } from "../utils/types"; + +function generateComponent(element: CustomElement): string { + const name = tagNameToComponentName(element.tagName); + const jsDoc = generateJSDoc( + element.summary, element.description, + element.slots, element.events, + element.attributes, element.properties, + element.examples, + ); + // Return framework-specific component code + return `${jsDoc}\nexport const ${name} = /* ... */;\n`; +} + +export function generateFrameworkWrappers(basePath: string = process.cwd()): void { + console.log("\nπŸ”§ Generating wrappers..."); + + const manifest = loadManifest(basePath); + const elements = extractCustomElements(manifest); + if (elements.length === 0) return; + + const output = elements.map(generateComponent).join("\n"); + const outputDir = join(basePath, "src", "wrappers", ""); + + mkdirSync(outputDir, { recursive: true }); + writeFileSync(join(outputDir, "index.ts"), formatCode(output)); + + console.log(`βœ… Generated ${elements.length} wrappers`); +} +``` + +### 2. Register It + +In `index.ts`: + +```typescript +import { generateFrameworkWrappers } from "./generators/"; + +const generators: Generator[] = [ + { name: "React", fn: generateReactWrappers, enabled: true }, + { name: "", fn: generateFrameworkWrappers, enabled: true }, +]; +``` + +### 3. Export from Package + +In the consuming package's `package.json`: + +```json +{ + "exports": { + "./": { + "types": "./wrappers//index.d.ts", + "default": "./src/wrappers//index.ts" + } + } +} +``` + +## Utilities + +| Function | Description | +| ----------------------------------- | ---------------------------------------------- | +| `loadManifest(basePath)` | Loads CEM + enhances with JSDoc metadata | +| `extractCustomElements(manifest)` | Extracts custom element definitions from CEM | +| `tagNameToComponentName(tagName)` | `kebab-case` β†’ `PascalCase` (e.g. `my-el` β†’ `MyEl`) | +| `generateJSDoc(...)` | Creates JSDoc comment blocks from metadata | +| `formatCode(code)` | Ensures consistent formatting | + +## Troubleshooting + +| Problem | Solution | +| ------------------------------ | --------------------------------------------------------- | +| "No custom elements found" | Run `cem analyze` first; ensure `@tag` annotations exist | +| "Failed to load manifest" | Check `custom-elements.json` exists and is valid JSON | +| Missing types in wrappers | Verify JSDoc `@attr` annotations have `{type}` specified | diff --git a/js/scripts/element-wrappers/generators/react.ts b/js/scripts/element-wrappers/generators/react.ts new file mode 100644 index 000000000..dcdef88f3 --- /dev/null +++ b/js/scripts/element-wrappers/generators/react.ts @@ -0,0 +1,168 @@ +/** + * React wrapper generator + * + * Generates React components that wrap custom elements, providing: + * - Proper TypeScript types + * - React.forwardRef for ref forwarding + * - JSX intrinsic element declarations + * - Complete JSDoc documentation from CEM + */ + +import { mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { formatCode, generateJSDoc } from "../utils/codegen"; +import { extractCustomElements, loadManifest, tagNameToComponentName } from "../utils/manifest"; +import type { CustomElement } from "../utils/types"; + +/** + * Generate TypeScript interface for custom element attributes + * + * Creates an interface with properly typed attributes from the custom element. + */ +function generateAttributesInterface(element: CustomElement): string { + if (!element.attributes || element.attributes.length === 0) { + return "React.HTMLAttributes"; + } + + const attrs = element.attributes + .map((attr) => { + let type = "string"; + if (attr.type?.text) { + // Map CEM types to TypeScript types + if (attr.type.text === "boolean") { + type = "boolean"; + } else if (attr.type.text === "number") { + type = "number"; + } else { + type = "string"; + } + } + // Attributes are optional in JSX + return ` "${attr.name}"?: ${type};`; + }) + .join("\n"); + + return `React.HTMLAttributes & {\n${attrs}\n }`; +} + +/** + * Generate a React wrapper component for a custom element + * + * Creates a forwardRef component that renders the custom element + * with proper TypeScript types and JSDoc documentation. + */ +function generateReactComponent(element: CustomElement): string { + const componentName = tagNameToComponentName(element.tagName); + const jsDoc = generateJSDoc( + element.summary, + element.description, + element.slots, + element.events, + element.attributes, + element.properties, + element.examples, + ); + + const attributesType = generateAttributesInterface(element); + + return `${jsDoc} +export const ${componentName} = React.forwardRef< + HTMLElement, + ${attributesType} & { + children?: React.ReactNode; + } +>(({ children, ...props }, ref) => { + return React.createElement("${element.tagName}", { ...props, ref }, children); +}); + +${componentName}.displayName = "${componentName}"; +`; +} + +/** + * Generate TypeScript module augmentation for JSX intrinsic elements + * + * Declares custom elements in React.JSX.IntrinsicElements so TypeScript + * recognizes them as valid JSX elements. + */ +function generateJSXModuleAugmentation(elements: CustomElement[]): string { + if (elements.length === 0) return ""; + + const intrinsicElements = elements + .map((el) => { + const attrType = generateAttributesInterface(el); + return `\t\t\t"${el.tagName}": ${attrType} & { children?: React.ReactNode };`; + }) + .join("\n"); + + return ` +declare module "react" { +\tnamespace JSX { +\t\tinterface IntrinsicElements { +${intrinsicElements} +\t\t} +\t} +} +`; +} + +/** + * Generate file header with auto-generation warning and timestamp + */ +function generateFileHeader(): string { + const timestamp = new Date().toISOString(); + return `/** + * Auto-generated React wrappers for custom elements + * DO NOT EDIT MANUALLY - Generated from custom-elements.json + * + * Generated: ${timestamp} + */ + +import React from "react"; +`; +} + +/** + * Generate React wrappers for all custom elements + * + * Main entry point for React wrapper generation. Loads CEM, extracts elements, + * generates wrapper components, and writes to src/wrappers/react/index.ts. + * + * @param basePath - Project root directory + */ +export function generateReactWrappers(basePath: string = process.cwd()): void { + console.log("\nπŸ”§ Generating React wrappers..."); + + try { + const manifest = loadManifest(basePath); + const elements = extractCustomElements(manifest); + + if (elements.length === 0) { + console.warn("⚠️ No custom elements found"); + return; + } + + const header = generateFileHeader(); + const components = elements.map(generateReactComponent).join("\n"); + const moduleAugmentation = generateJSXModuleAugmentation(elements); + + const output = `${header}\n${components}\n${moduleAugmentation}`; + + const outputDir = join(basePath, "src", "wrappers", "react"); + const outputPath = join(outputDir, "index.ts"); + + mkdirSync(outputDir, { recursive: true }); + writeFileSync(outputPath, formatCode(output)); + + console.log( + `βœ… Generated ${elements.length} wrapper${elements.length > 1 ? "s" : ""}: src/wrappers/react/index.ts`, + ); + for (const el of elements) { + console.log(` └─ ${tagNameToComponentName(el.tagName)} ← <${el.tagName}>`); + } + } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); + console.error(`❌ Failed to generate React wrappers: ${errorMsg}`); + throw error; + } +} diff --git a/js/scripts/element-wrappers/index.ts b/js/scripts/element-wrappers/index.ts new file mode 100644 index 000000000..67010c0d0 --- /dev/null +++ b/js/scripts/element-wrappers/index.ts @@ -0,0 +1,58 @@ +/** + * Code generation orchestrator + * + * Main entry point for framework wrapper generation. + * Runs enabled generators in sequence and tracks performance. + * + * To add a new framework: + * 1. Create a new generator in generators/.ts + * 2. Export a generateWrappers(basePath) function + * 3. Add it to the generators array below + */ + +import { generateReactWrappers } from "./generators/react"; + +type GeneratorFunction = (basePath: string) => void; + +interface Generator { + name: string; + fn: GeneratorFunction; + enabled: boolean; +} + +const generators: Generator[] = [{ name: "React", fn: generateReactWrappers, enabled: true }]; + +async function generateWrappers(): Promise { + const startTime = performance.now(); + + try { + console.log("\nπŸ“¦ Code Generation"); + + const basePath = process.cwd(); + const enabledGenerators = generators.filter((g) => g.enabled); + + if (enabledGenerators.length === 0) { + console.warn("⚠️ No generators enabled"); + return; + } + + for (const generator of enabledGenerators) { + try { + generator.fn(basePath); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); + console.error(`❌ ${generator.name} failed: ${errorMsg}`); + throw error; + } + } + + const duration = ((performance.now() - startTime) / 1000).toFixed(2); + console.log(`\n✨ Complete in ${duration}s\n`); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); + console.error(`\n❌ Generation failed: ${errorMsg}\n`); + process.exit(1); + } +} + +generateWrappers(); diff --git a/js/scripts/element-wrappers/utils/codegen.ts b/js/scripts/element-wrappers/utils/codegen.ts new file mode 100644 index 000000000..b5595ea92 --- /dev/null +++ b/js/scripts/element-wrappers/utils/codegen.ts @@ -0,0 +1,167 @@ +/** + * Code generation utilities + * + * Provides functions for: + * - Formatting generated code + * - Generating JSDoc comments from metadata + * - Escaping special characters for documentation + */ + +import type { Attribute, EventDeclaration, Property, Slot } from "./types"; + +/** + * Format generated code with consistent trailing newline + */ +export function formatCode(code: string): string { + return `${code.trim()}\n`; +} + +/** + * Escape special characters in JSDoc content + * Prevents premature closing of JSDoc blocks + */ +function escapeJSDoc(text: string): string { + return text.replace(/\*\//g, "*\\/"); +} + +/** + * Format a documentation section with consistent indentation + * + * @param title - Section title (e.g., "slots", "events") + * @param items - Array of items with name, description, and optional extra text + * @returns Array of formatted JSDoc lines + */ +function formatDocSection( + title: string, + items: Array<{ name: string; description?: string; extra?: string }>, +): string[] { + if (items.length === 0) return []; + + return [ + ` * @${title}`, + ...items.map((item) => { + const extra = item.extra ?? ""; + const desc = item.description ? ` - ${escapeJSDoc(item.description)}` : ""; + return ` * - \`${item.name}\`${extra}${desc}`; + }), + ]; +} + +/** + * Generate JSDoc comment block from custom element metadata + * + * Creates comprehensive JSDoc with @summary, @description, section tags + * (@slots, @events, @attributes, @properties), and multiple @example blocks. + * + * @param summary - Brief one-line summary + * @param description - Detailed description + * @param slots - Slot definitions + * @param events - Event definitions + * @param attributes - Attribute definitions + * @param properties - Property definitions + * @param examples - Labeled code examples (e.g., {"HTML": "...", "React": "..."}) + * @returns Formatted JSDoc comment block + */ +export function generateJSDoc( + summary?: string, + description?: string, + slots?: Slot[], + events?: EventDeclaration[], + attributes?: Attribute[], + properties?: Property[], + examples?: Record, +): string { + const lines: string[] = ["/**"]; + + // Add summary + if (summary) { + lines.push(` * @summary ${escapeJSDoc(summary)}`); + } + + // Add description only if different from summary + if (description && description !== summary) { + lines.push(` * @description ${escapeJSDoc(description)}`); + } + + // Add documentation sections + if (slots?.length) { + lines.push( + ...formatDocSection( + "slots", + slots.map((slot) => ({ + name: slot.name || "default", + description: slot.description, + })), + ), + ); + } + + if (events?.length) { + lines.push( + ...formatDocSection( + "events", + events.map((event) => ({ + name: event.name, + description: event.description, + })), + ), + ); + } + + if (attributes?.length) { + lines.push( + ...formatDocSection( + "attributes", + attributes.map((attr) => ({ + name: attr.name, + description: attr.description, + })), + ), + ); + } + + if (properties?.length) { + lines.push( + ...formatDocSection( + "properties", + properties.map((prop) => ({ + name: prop.name, + description: prop.description, + extra: prop.readonly ? " (readonly)" : "", + })), + ), + ); + } + + // Add examples with proper JSDoc formatting + if (examples && Object.keys(examples).length > 0) { + const exampleEntries = Object.entries(examples); + for (let i = 0; i < exampleEntries.length; i++) { + const [label, content] = exampleEntries[i]; + // Use @example with caption for label + lines.push(` * @example`); + lines.push(` * ${label}`); + // Remove markdown code fences and add proper indentation + const exampleLines = content.split("\n"); + for (const line of exampleLines) { + // Skip markdown code fence lines (```html, ```tsx, ```) + if (line.trim().startsWith("```")) { + continue; + } + // Add indentation for code (standard JSDoc format) + if (line.trim()) { + lines.push(` * ${line}`); + } else { + lines.push(` *`); + } + } + // Add empty line between examples for better separation + if (i < exampleEntries.length - 1) { + lines.push(` *`); + } + } + } + + lines.push(` */`); + return lines.join("\n"); +} diff --git a/js/scripts/element-wrappers/utils/manifest.ts b/js/scripts/element-wrappers/utils/manifest.ts new file mode 100644 index 000000000..5f9232334 --- /dev/null +++ b/js/scripts/element-wrappers/utils/manifest.ts @@ -0,0 +1,232 @@ +/** + * Utilities for loading and parsing Custom Elements Manifest (CEM) + * + * This module provides functions to: + * - Load custom-elements.json generated by @custom-elements-manifest/analyzer + * - Extract JSDoc metadata (@summary, @description, @example) from source files + * - Enhance manifest with metadata from source comments + * - Extract custom element definitions for code generation + */ + +import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; +import { join } from "node:path"; +import type { CustomElement, CustomElementsManifest, Declaration } from "./types"; + +type DeclarationWithExamples = Declaration & { examples?: Record; customElement?: boolean }; + +/** + * Extract JSDoc metadata from source file content + * + * Parses JSDoc blocks to find @tag, @summary, @description, and @example annotations. + * Supports multiple labeled examples (e.g., @example HTML, @example React). + * + * @param content - Raw source file content to parse + * @returns Map of tag names to their metadata (summary, description, examples) + */ +function extractJSDocMetadata( + content: string, +): Map }> { + const metadata = new Map }>(); + + // Match JSDoc blocks with @tag, @summary, and @description + const jsDocRegex = /\/\*\*([\s\S]*?)\*\//g; + + for (const match of content.matchAll(jsDocRegex)) { + const jsDocContent = match[1]; + + // Extract @tag value β€” skip blocks without @tag + const tagMatch = jsDocContent.match(/@tag\s+(\S+)/); + if (!tagMatch) continue; + + const tag = tagMatch[1]; + + // Extract @summary value (single line) + const summaryMatch = jsDocContent.match(/@summary\s+([^\n]+)/); + const summary = summaryMatch ? summaryMatch[1].trim() : undefined; + + // Extract @description value (can be multi-line until next @) + const descriptionMatch = jsDocContent.match(/@description\s+([\s\S]*?)(?=@\w+|\*\/)/); + const description = descriptionMatch ? descriptionMatch[1].trim() : undefined; + + // Extract all @example blocks with labels + // Use matchAll() instead of exec() to avoid stateful regex issues + const examples: Record = {}; + + // Match each @example with a label and its content + // Content goes until we hit another @example or end of JSDoc block + const exampleMatches = jsDocContent.matchAll( + /@example\s+(\w+)\s*([\s\S]*?)(?=\n\s*\*\s*@example\s+\w|\*\/|$)/g, + ); + + for (const exampleMatch of exampleMatches) { + const label = exampleMatch[1]; + let content = exampleMatch[2]; + + // Remove JSDoc asterisks and clean up formatting + content = content + .split("\n") + .map((line) => line.replace(/^\s*\*\s?/, "")) + .join("\n") + .trim(); + + if (content) { + examples[label] = content; + } + } + + metadata.set(tag, { + summary, + description, + ...(Object.keys(examples).length > 0 && { examples }), + }); + } + + return metadata; +} + +/** + * Load and enhance Custom Elements Manifest + * + * Loads custom-elements.json and enhances it with JSDoc metadata from source files. + * This combines CEM analyzer output with hand-written documentation. + * + * @param basePath - Project root directory (defaults to cwd) + * @returns Enhanced custom elements manifest + * @throws Error if manifest file cannot be loaded + */ +export function loadManifest(basePath: string = process.cwd()): CustomElementsManifest { + const manifestPath = join(basePath, "custom-elements.json"); + try { + const content = readFileSync(manifestPath, "utf-8"); + const manifest = JSON.parse(content) as CustomElementsManifest; + + // Enhance manifest with JSDoc metadata from source files + // Scan all .ts/.tsx files in src/ directory for JSDoc annotations + try { + const allMetadata = new Map< + string, + { summary?: string; description?: string; examples?: Record } + >(); + + // Recursively find and parse all TypeScript source files + const srcDir = join(basePath, "src"); + + if (existsSync(srcDir)) { + const scanDirectory = (dir: string): void => { + const entries = readdirSync(dir); + for (const entry of entries) { + const fullPath = join(dir, entry); + const stat = statSync(fullPath); + + if (stat.isDirectory()) { + scanDirectory(fullPath); + } else if (entry.endsWith(".ts") || entry.endsWith(".tsx")) { + const source = readFileSync(fullPath, "utf-8"); + const metadata = extractJSDocMetadata(source); + for (const [tag, data] of metadata) { + allMetadata.set(tag, data); + } + } + } + }; + + scanDirectory(srcDir); + } + + // Update manifest declarations + manifest.modules.forEach((mod) => { + mod.declarations?.forEach((decl) => { + if (decl.tagName && allMetadata.has(decl.tagName)) { + const data = allMetadata.get(decl.tagName); + if (!data) return; + const declWithExamples = decl as DeclarationWithExamples; + if (data.summary && !declWithExamples.summary) { + declWithExamples.summary = data.summary; + } + if (data.description && !declWithExamples.description) { + declWithExamples.description = data.description; + } + if (data.examples && !declWithExamples.examples) { + declWithExamples.examples = data.examples; + } + } + }); + }); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); + console.warn(`⚠️ JSDoc enhancement failed: ${errorMsg}`); + } + + return manifest; + } catch (error) { + const errorMsg = error instanceof Error ? error.message : String(error); + console.error(`❌ Failed to load manifest: ${errorMsg}`); + throw error; + } +} + +/** + * Extract custom element definitions from manifest + * + * Filters manifest declarations to find only custom elements and extracts + * their public API (attributes, properties, events, slots, etc.). + * Deduplicates elements by tagName. + * + * @param manifest - Custom Elements Manifest to extract from + * @returns Array of custom element definitions + */ +export function extractCustomElements(manifest: CustomElementsManifest): CustomElement[] { + const elements: CustomElement[] = []; + const seenTagNames = new Set(); + + manifest.modules.forEach((mod) => { + mod.declarations?.forEach((decl: Declaration) => { + const declWithExamples = decl as DeclarationWithExamples; + // Look for custom elements either by kind or by customElement flag + if ((decl.kind === "custom-element" || declWithExamples.customElement) && decl.tagName) { + // Deduplicate by tagName + if (!seenTagNames.has(decl.tagName)) { + seenTagNames.add(decl.tagName); + elements.push({ + tagName: decl.tagName, + className: decl.name, + summary: decl.summary, + description: decl.description, + slots: decl.slots, + events: decl.events, + attributes: decl.attributes, + properties: decl.properties, + examples: declWithExamples.examples, + }); + } + } + }); + }); + + return elements; +} + +/** + * Convert kebab-case tag name to PascalCase component name + * + * Common abbreviations (e.g., "ui", "api") are kept uppercase. + * + * @example + * tagNameToComponentName("my-element") // "MyElement" + * tagNameToComponentName("video-player-ui") // "VideoPlayerUI" + * + * @param tagName - Kebab-case custom element tag name + * @returns PascalCase component name + */ +export function tagNameToComponentName(tagName: string): string { + return tagName + .split("-") + .map((part) => { + // Keep "ui" uppercase if it's the last part + if (part.toLowerCase() === "ui") { + return "UI"; + } + return part.charAt(0).toUpperCase() + part.slice(1); + }) + .join(""); +} diff --git a/js/scripts/element-wrappers/utils/types.ts b/js/scripts/element-wrappers/utils/types.ts new file mode 100644 index 000000000..9df6445e8 --- /dev/null +++ b/js/scripts/element-wrappers/utils/types.ts @@ -0,0 +1,64 @@ +/** + * Type definitions for Custom Elements Manifest + */ + +export interface Slot { + name?: string; + description?: string; +} + +export interface EventDeclaration { + name: string; + description?: string; + type?: { text: string }; +} + +export interface Attribute { + name: string; + description?: string; + type?: { text: string }; +} + +export interface Property { + name: string; + description?: string; + type?: { text: string }; + readonly?: boolean; +} + +export interface Declaration { + kind: string; + name: string; + tagName?: string; + summary?: string; + description?: string; + slots?: Slot[]; + events?: EventDeclaration[]; + attributes?: Attribute[]; + properties?: Property[]; +} + +export interface Module { + kind: string; + path: string; + declarations?: Declaration[]; + exports?: Array<{ kind: string; name: string }>; +} + +export interface CustomElementsManifest { + schemaVersion: string; + readme?: string; + modules: Module[]; +} + +export interface CustomElement { + tagName: string; + className: string; + summary?: string; + description?: string; + slots?: Slot[]; + events?: EventDeclaration[]; + attributes?: Attribute[]; + properties?: Property[]; + examples?: Record; +} diff --git a/js/scripts/package.ts b/js/scripts/package.ts index 16bf04b79..010f6ef7a 100644 --- a/js/scripts/package.ts +++ b/js/scripts/package.ts @@ -9,6 +9,9 @@ console.log("✍️ Rewriting package.json..."); const pkg = JSON.parse(readFileSync("package.json", "utf8")); function rewritePath(p: string): string { + if (p.endsWith(".d.ts")) { + return p.replace(/^\.\/src/, "."); + } return p.replace(/^\.\/src/, ".").replace(/\.ts(x)?$/, ".js"); }