diff --git a/CHANGELOG.md b/CHANGELOG.md index 1028a59e..c3c08c81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,18 @@ Changelog * No changes. +Version 0.1.36 -- 2025-Sep-17 +----------------------------- + +* The system continues to work after a PC goes to sleep then wakes back up; + communication within previous versions fails after a sleep/wake up cycle. +* Communicate between the VSCode extension and the Server using queues instead + of a websocket and a queue. +* Remove the HTML editor's toolbar, to free up more space on the screen. +* Add a code formatting button to the quick toolbar which appears when tex is + selected in the HTML editor. +* Remove the File entry from the HTML editor's main menu. + Version 0.1.35 -- 2025-Sep-12 ----------------------------- diff --git a/builder/Cargo.lock b/builder/Cargo.lock index 2b6b2151..0748b384 100644 --- a/builder/Cargo.lock +++ b/builder/Cargo.lock @@ -358,18 +358,27 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", diff --git a/client/package.json5 b/client/package.json5 index 3a260f68..e579173f 100644 --- a/client/package.json5 +++ b/client/package.json5 @@ -43,7 +43,7 @@ url: 'https://github.com/bjones1/CodeChat_editor', }, type: 'module', - version: '0.1.35', + version: '0.1.36', dependencies: { '@codemirror/commands': '^6.8.1', '@codemirror/lang-cpp': '^6.0.3', @@ -67,19 +67,19 @@ mermaid: '^11.11.0', 'npm-check-updates': '^18.1.1', 'pdfjs-dist': '^5.4.149', - tinymce: '^8.0.2', + tinymce: '^8.1.1', 'toastify-js': '^1.12.0', }, devDependencies: { '@types/chai': '^5.2.2', '@types/js-beautify': '^1.14.3', '@types/mocha': '^10.0.10', - '@types/node': '^24.3.3', + '@types/node': '^24.5.1', '@types/toastify-js': '^1.12.4', - '@typescript-eslint/eslint-plugin': '^8.43.0', - '@typescript-eslint/parser': '^8.43.0', + '@typescript-eslint/eslint-plugin': '^8.44.0', + '@typescript-eslint/parser': '^8.44.0', chai: '^6.0.1', - esbuild: '^0.25.9', + esbuild: '^0.25.10', eslint: '^9.35.0', 'eslint-config-prettier': '^10.1.8', 'eslint-plugin-import': '^2.32.0', diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index a477df13..29f5cd4c 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -75,8 +75,8 @@ importers: specifier: ^5.4.149 version: 5.4.149 tinymce: - specifier: ^8.0.2 - version: 8.0.2 + specifier: ^8.1.1 + version: 8.1.1 toastify-js: specifier: ^1.12.0 version: 1.12.0 @@ -91,23 +91,23 @@ importers: specifier: ^10.0.10 version: 10.0.10 '@types/node': - specifier: ^24.3.3 - version: 24.3.3 + specifier: ^24.5.1 + version: 24.5.1 '@types/toastify-js': specifier: ^1.12.4 version: 1.12.4 '@typescript-eslint/eslint-plugin': - specifier: ^8.43.0 - version: 8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2) + specifier: ^8.44.0 + version: 8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2) '@typescript-eslint/parser': - specifier: ^8.43.0 - version: 8.43.0(eslint@9.35.0)(typescript@5.9.2) + specifier: ^8.44.0 + version: 8.44.0(eslint@9.35.0)(typescript@5.9.2) chai: specifier: ^6.0.1 version: 6.0.1 esbuild: - specifier: ^0.25.9 - version: 0.25.9 + specifier: ^0.25.10 + version: 0.25.10 eslint: specifier: ^9.35.0 version: 9.35.0 @@ -116,7 +116,7 @@ importers: version: 10.1.8(eslint@9.35.0) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0) + version: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0) eslint-plugin-prettier: specifier: ^5.5.4 version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.35.0))(eslint@9.35.0)(prettier@3.6.2) @@ -213,158 +213,158 @@ packages: '@codemirror/view@6.38.2': resolution: {integrity: sha512-bTWAJxL6EOFLPzTx+O5P5xAO3gTqpatQ2b/ARQ8itfU/v2LlpS3pH2fkL0A3E/Fx8Y2St2KES7ZEV0sHTsSW/A==} - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + '@esbuild/aix-ppc64@0.25.10': + resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + '@esbuild/android-arm64@0.25.10': + resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + '@esbuild/android-arm@0.25.10': + resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + '@esbuild/android-x64@0.25.10': + resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + '@esbuild/darwin-arm64@0.25.10': + resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + '@esbuild/darwin-x64@0.25.10': + resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + '@esbuild/freebsd-arm64@0.25.10': + resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + '@esbuild/freebsd-x64@0.25.10': + resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + '@esbuild/linux-arm64@0.25.10': + resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + '@esbuild/linux-arm@0.25.10': + resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + '@esbuild/linux-ia32@0.25.10': + resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + '@esbuild/linux-loong64@0.25.10': + resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + '@esbuild/linux-mips64el@0.25.10': + resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + '@esbuild/linux-ppc64@0.25.10': + resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + '@esbuild/linux-riscv64@0.25.10': + resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + '@esbuild/linux-s390x@0.25.10': + resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + '@esbuild/linux-x64@0.25.10': + resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + '@esbuild/netbsd-arm64@0.25.10': + resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + '@esbuild/netbsd-x64@0.25.10': + resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + '@esbuild/openbsd-arm64@0.25.10': + resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + '@esbuild/openbsd-x64@0.25.10': + resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + '@esbuild/openharmony-arm64@0.25.10': + resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + '@esbuild/sunos-x64@0.25.10': + resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + '@esbuild/win32-arm64@0.25.10': + resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + '@esbuild/win32-ia32@0.25.10': + resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + '@esbuild/win32-x64@0.25.10': + resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -426,8 +426,8 @@ packages: '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@iconify/utils@3.0.1': - resolution: {integrity: sha512-A78CUEnFGX8I/WlILxJCuIJXloL0j/OJ9PSchPAfCargEIKmUBWvvEMmKWB5oONwiUqlNt+5eRufdkLxeHIWYw==} + '@iconify/utils@3.0.2': + resolution: {integrity: sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -487,68 +487,68 @@ packages: '@mermaid-js/parser@0.6.2': resolution: {integrity: sha512-+PO02uGF6L6Cs0Bw8RpGhikVvMWEysfAyl27qTlroUB8jSWr1lL0Sf6zi78ZxlSnmgSY2AMMKVgghnN9jTtwkQ==} - '@napi-rs/canvas-android-arm64@0.1.79': - resolution: {integrity: sha512-ih6ZIztNDEXl7axvC4swOwLFrM9lOyJa9VAMq7xIBtEZhR/8IVDa0ZTup2fZEiTCmnjmXolzv7uDviHkOTEMKQ==} + '@napi-rs/canvas-android-arm64@0.1.80': + resolution: {integrity: sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/canvas-darwin-arm64@0.1.79': - resolution: {integrity: sha512-REMz1Fac2VlOYJDg+JjmQWSJc459cCgVom6GvKwWkDqzSjvG9BSo72MDmQY3uhb7r49Xuz5gTFcLYTfNcm4MoA==} + '@napi-rs/canvas-darwin-arm64@0.1.80': + resolution: {integrity: sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/canvas-darwin-x64@0.1.79': - resolution: {integrity: sha512-uQxLg6Bll7zv/ljp/YIeiUFWfV9C/ESv+2ioUh60hIAypuhtg6hhtWE/KnoW7G48wQls5VUStvEnJbnJ7bPKlA==} + '@napi-rs/canvas-darwin-x64@0.1.80': + resolution: {integrity: sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.79': - resolution: {integrity: sha512-X37B//TVIipL/3RyvyfNlbQK2uyIaK3PJ2bH7ZeU+jpkaYprBsV15GCN/LHTYAi6R0F/c53zK3aSFNKkGHM/Og==} + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.80': + resolution: {integrity: sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/canvas-linux-arm64-gnu@0.1.79': - resolution: {integrity: sha512-+T1fuau1heabE6zGXiqZBGPH5fTIQF+xEu/u4fuugxEiChRYlhnPjkw26MBi8ePg/jmzxLfJEij6LMJQ4AQa2A==} + '@napi-rs/canvas-linux-arm64-gnu@0.1.80': + resolution: {integrity: sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/canvas-linux-arm64-musl@0.1.79': - resolution: {integrity: sha512-KsrsR3+6uXv70W/1/kY0yRK4/bbdJgA1Vuxw4KyfSc6mjl1DMoYXDAjpBT/5w7AXy6cGG44jm3upvvt/y/dPfg==} + '@napi-rs/canvas-linux-arm64-musl@0.1.80': + resolution: {integrity: sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/canvas-linux-riscv64-gnu@0.1.79': - resolution: {integrity: sha512-EXaENnSJD6au6z4aKN2PpU9eVNWUsRI2cApm8gCa0WSRMaiYXZsFkXQmhB+Vz2pXahOS8BN2Zd8S1IeML/LCtg==} + '@napi-rs/canvas-linux-riscv64-gnu@0.1.80': + resolution: {integrity: sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - '@napi-rs/canvas-linux-x64-gnu@0.1.79': - resolution: {integrity: sha512-3xZhHlE9e3cd9D7Comy6/TTSs/8PUGXEXymIwYQrA1QxHojAlAOFlVai4rffzXd0bHylZu+/wD76LodvYqF1Yw==} + '@napi-rs/canvas-linux-x64-gnu@0.1.80': + resolution: {integrity: sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/canvas-linux-x64-musl@0.1.79': - resolution: {integrity: sha512-4yv550uCjIEoTFgrpxYZK67nFlDMCQa3LAheM2QrO+B8w1p5w04usIQSCHqHe6aPWlbLQCIqfVcew6/7Q4KuHg==} + '@napi-rs/canvas-linux-x64-musl@0.1.80': + resolution: {integrity: sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/canvas-win32-x64-msvc@0.1.79': - resolution: {integrity: sha512-sD5qP2njBRnhNlTNFJDdpeCN6aR3qVamLySTwhX3ec8sdfeT/chf/x2dw2UXoIGMoVaVk/y2ifwxBj/h2a2jug==} + '@napi-rs/canvas-win32-x64-msvc@0.1.80': + resolution: {integrity: sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/canvas@0.1.79': - resolution: {integrity: sha512-0SkvRRjyxY35eniEsQsjPYUMWunKlAWvionJOzJJADZF5ZDf/sL+ncJbMTV5LUiHg1iHOvVjWcuDOx/GNXr/lA==} + '@napi-rs/canvas@0.1.80': + resolution: {integrity: sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==} engines: {node: '>= 10'} '@nodelib/fs.scandir@2.1.5': @@ -691,8 +691,8 @@ packages: '@types/mocha@10.0.10': resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} - '@types/node@24.3.3': - resolution: {integrity: sha512-GKBNHjoNw3Kra1Qg5UXttsY5kiWMEfoHq2TmXb+b1rcm6N7B3wTrFYIf/oSZ1xNQ+hVVijgLkiDZh7jRRsh+Gw==} + '@types/node@24.5.1': + resolution: {integrity: sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q==} '@types/toastify-js@1.12.4': resolution: {integrity: sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==} @@ -700,63 +700,63 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.43.0': - resolution: {integrity: sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==} + '@typescript-eslint/eslint-plugin@8.44.0': + resolution: {integrity: sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.43.0 + '@typescript-eslint/parser': ^8.44.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.43.0': - resolution: {integrity: sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==} + '@typescript-eslint/parser@8.44.0': + resolution: {integrity: sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.43.0': - resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==} + '@typescript-eslint/project-service@8.44.0': + resolution: {integrity: sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.43.0': - resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==} + '@typescript-eslint/scope-manager@8.44.0': + resolution: {integrity: sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.43.0': - resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==} + '@typescript-eslint/tsconfig-utils@8.44.0': + resolution: {integrity: sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.43.0': - resolution: {integrity: sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==} + '@typescript-eslint/type-utils@8.44.0': + resolution: {integrity: sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.43.0': - resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==} + '@typescript-eslint/types@8.44.0': + resolution: {integrity: sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.43.0': - resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==} + '@typescript-eslint/typescript-estree@8.44.0': + resolution: {integrity: sha512-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.43.0': - resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==} + '@typescript-eslint/utils@8.44.0': + resolution: {integrity: sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.43.0': - resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==} + '@typescript-eslint/visitor-keys@8.44.0': + resolution: {integrity: sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: @@ -1102,8 +1102,8 @@ packages: supports-color: optional: true - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1137,8 +1137,8 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dompurify@3.2.6: - resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} @@ -1181,8 +1181,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + esbuild@0.25.10: + resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} engines: {node: '>=18'} hasBin: true @@ -2012,8 +2012,8 @@ packages: tinyexec@1.0.1: resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} - tinymce@8.0.2: - resolution: {integrity: sha512-Gkvn5mRcZCAK1EKP7hnk3VBzwqPbqpZU2AN0T08BMtvmY9Sg0C0ZqmMghJCQ3vgo+LWA38pDOPiaM8EW7BZEow==} + tinymce@8.1.1: + resolution: {integrity: sha512-+uJFY9TWBpP4/dRwylkQz2fnCxuYpAISXNbq05+ej+0x6OQNyhwKnzWT9R68ZjmBjqzIW6pe+cMaj9Zxo7Iihg==} to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -2067,8 +2067,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + undici-types@7.12.0: + resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -2323,82 +2323,82 @@ snapshots: style-mod: 4.1.2 w3c-keyname: 2.2.8 - '@esbuild/aix-ppc64@0.25.9': + '@esbuild/aix-ppc64@0.25.10': optional: true - '@esbuild/android-arm64@0.25.9': + '@esbuild/android-arm64@0.25.10': optional: true - '@esbuild/android-arm@0.25.9': + '@esbuild/android-arm@0.25.10': optional: true - '@esbuild/android-x64@0.25.9': + '@esbuild/android-x64@0.25.10': optional: true - '@esbuild/darwin-arm64@0.25.9': + '@esbuild/darwin-arm64@0.25.10': optional: true - '@esbuild/darwin-x64@0.25.9': + '@esbuild/darwin-x64@0.25.10': optional: true - '@esbuild/freebsd-arm64@0.25.9': + '@esbuild/freebsd-arm64@0.25.10': optional: true - '@esbuild/freebsd-x64@0.25.9': + '@esbuild/freebsd-x64@0.25.10': optional: true - '@esbuild/linux-arm64@0.25.9': + '@esbuild/linux-arm64@0.25.10': optional: true - '@esbuild/linux-arm@0.25.9': + '@esbuild/linux-arm@0.25.10': optional: true - '@esbuild/linux-ia32@0.25.9': + '@esbuild/linux-ia32@0.25.10': optional: true - '@esbuild/linux-loong64@0.25.9': + '@esbuild/linux-loong64@0.25.10': optional: true - '@esbuild/linux-mips64el@0.25.9': + '@esbuild/linux-mips64el@0.25.10': optional: true - '@esbuild/linux-ppc64@0.25.9': + '@esbuild/linux-ppc64@0.25.10': optional: true - '@esbuild/linux-riscv64@0.25.9': + '@esbuild/linux-riscv64@0.25.10': optional: true - '@esbuild/linux-s390x@0.25.9': + '@esbuild/linux-s390x@0.25.10': optional: true - '@esbuild/linux-x64@0.25.9': + '@esbuild/linux-x64@0.25.10': optional: true - '@esbuild/netbsd-arm64@0.25.9': + '@esbuild/netbsd-arm64@0.25.10': optional: true - '@esbuild/netbsd-x64@0.25.9': + '@esbuild/netbsd-x64@0.25.10': optional: true - '@esbuild/openbsd-arm64@0.25.9': + '@esbuild/openbsd-arm64@0.25.10': optional: true - '@esbuild/openbsd-x64@0.25.9': + '@esbuild/openbsd-x64@0.25.10': optional: true - '@esbuild/openharmony-arm64@0.25.9': + '@esbuild/openharmony-arm64@0.25.10': optional: true - '@esbuild/sunos-x64@0.25.9': + '@esbuild/sunos-x64@0.25.10': optional: true - '@esbuild/win32-arm64@0.25.9': + '@esbuild/win32-arm64@0.25.10': optional: true - '@esbuild/win32-ia32@0.25.9': + '@esbuild/win32-ia32@0.25.10': optional: true - '@esbuild/win32-x64@0.25.9': + '@esbuild/win32-x64@0.25.10': optional: true '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0)': @@ -2411,7 +2411,7 @@ snapshots: '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2425,7 +2425,7 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -2458,12 +2458,12 @@ snapshots: '@iconify/types@2.0.0': {} - '@iconify/utils@3.0.1': + '@iconify/utils@3.0.2': dependencies: '@antfu/install-pkg': 1.1.0 '@antfu/utils': 9.2.0 '@iconify/types': 2.0.0 - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) globals: 15.15.0 kolorist: 1.8.0 local-pkg: 1.1.2 @@ -2569,48 +2569,48 @@ snapshots: dependencies: langium: 3.3.1 - '@napi-rs/canvas-android-arm64@0.1.79': + '@napi-rs/canvas-android-arm64@0.1.80': optional: true - '@napi-rs/canvas-darwin-arm64@0.1.79': + '@napi-rs/canvas-darwin-arm64@0.1.80': optional: true - '@napi-rs/canvas-darwin-x64@0.1.79': + '@napi-rs/canvas-darwin-x64@0.1.80': optional: true - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.79': + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.80': optional: true - '@napi-rs/canvas-linux-arm64-gnu@0.1.79': + '@napi-rs/canvas-linux-arm64-gnu@0.1.80': optional: true - '@napi-rs/canvas-linux-arm64-musl@0.1.79': + '@napi-rs/canvas-linux-arm64-musl@0.1.80': optional: true - '@napi-rs/canvas-linux-riscv64-gnu@0.1.79': + '@napi-rs/canvas-linux-riscv64-gnu@0.1.80': optional: true - '@napi-rs/canvas-linux-x64-gnu@0.1.79': + '@napi-rs/canvas-linux-x64-gnu@0.1.80': optional: true - '@napi-rs/canvas-linux-x64-musl@0.1.79': + '@napi-rs/canvas-linux-x64-musl@0.1.80': optional: true - '@napi-rs/canvas-win32-x64-msvc@0.1.79': + '@napi-rs/canvas-win32-x64-msvc@0.1.80': optional: true - '@napi-rs/canvas@0.1.79': + '@napi-rs/canvas@0.1.80': optionalDependencies: - '@napi-rs/canvas-android-arm64': 0.1.79 - '@napi-rs/canvas-darwin-arm64': 0.1.79 - '@napi-rs/canvas-darwin-x64': 0.1.79 - '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.79 - '@napi-rs/canvas-linux-arm64-gnu': 0.1.79 - '@napi-rs/canvas-linux-arm64-musl': 0.1.79 - '@napi-rs/canvas-linux-riscv64-gnu': 0.1.79 - '@napi-rs/canvas-linux-x64-gnu': 0.1.79 - '@napi-rs/canvas-linux-x64-musl': 0.1.79 - '@napi-rs/canvas-win32-x64-msvc': 0.1.79 + '@napi-rs/canvas-android-arm64': 0.1.80 + '@napi-rs/canvas-darwin-arm64': 0.1.80 + '@napi-rs/canvas-darwin-x64': 0.1.80 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.80 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.80 + '@napi-rs/canvas-linux-arm64-musl': 0.1.80 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.80 + '@napi-rs/canvas-linux-x64-gnu': 0.1.80 + '@napi-rs/canvas-linux-x64-musl': 0.1.80 + '@napi-rs/canvas-win32-x64-msvc': 0.1.80 optional: true '@nodelib/fs.scandir@2.1.5': @@ -2767,23 +2767,23 @@ snapshots: '@types/mocha@10.0.10': {} - '@types/node@24.3.3': + '@types/node@24.5.1': dependencies: - undici-types: 7.10.0 + undici-types: 7.12.0 '@types/toastify-js@1.12.4': {} '@types/trusted-types@2.0.7': optional: true - '@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/type-utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.43.0 + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.0 eslint: 9.35.0 graphemer: 1.4.0 ignore: 7.0.5 @@ -2793,57 +2793,57 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.43.0 - debug: 4.4.1(supports-color@8.1.1) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.0 + debug: 4.4.3(supports-color@8.1.1) eslint: 9.35.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.43.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.44.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) - '@typescript-eslint/types': 8.43.0 - debug: 4.4.1(supports-color@8.1.1) + '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + debug: 4.4.3(supports-color@8.1.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.43.0': + '@typescript-eslint/scope-manager@8.44.0': dependencies: - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/visitor-keys': 8.44.0 - '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.44.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.43.0(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.44.0(eslint@9.35.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - debug: 4.4.1(supports-color@8.1.1) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 9.35.0 ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.43.0': {} + '@typescript-eslint/types@8.44.0': {} - '@typescript-eslint/typescript-estree@8.43.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.44.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.43.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 - debug: 4.4.1(supports-color@8.1.1) + '@typescript-eslint/project-service': 8.44.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/visitor-keys': 8.44.0 + debug: 4.4.3(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -2853,20 +2853,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.43.0(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/utils@8.44.0(eslint@9.35.0)(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0) - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) eslint: 9.35.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.43.0': + '@typescript-eslint/visitor-keys@8.44.0': dependencies: - '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/types': 8.44.0 eslint-visitor-keys: 4.2.1 acorn-jsx@5.3.2(acorn@8.15.0): @@ -3269,7 +3269,7 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.1(supports-color@8.1.1): + debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 optionalDependencies: @@ -3301,7 +3301,7 @@ snapshots: dependencies: esutils: 2.0.3 - dompurify@3.2.6: + dompurify@3.2.7: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -3399,34 +3399,34 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.25.9: + esbuild@0.25.10: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.9 - '@esbuild/android-arm': 0.25.9 - '@esbuild/android-arm64': 0.25.9 - '@esbuild/android-x64': 0.25.9 - '@esbuild/darwin-arm64': 0.25.9 - '@esbuild/darwin-x64': 0.25.9 - '@esbuild/freebsd-arm64': 0.25.9 - '@esbuild/freebsd-x64': 0.25.9 - '@esbuild/linux-arm': 0.25.9 - '@esbuild/linux-arm64': 0.25.9 - '@esbuild/linux-ia32': 0.25.9 - '@esbuild/linux-loong64': 0.25.9 - '@esbuild/linux-mips64el': 0.25.9 - '@esbuild/linux-ppc64': 0.25.9 - '@esbuild/linux-riscv64': 0.25.9 - '@esbuild/linux-s390x': 0.25.9 - '@esbuild/linux-x64': 0.25.9 - '@esbuild/netbsd-arm64': 0.25.9 - '@esbuild/netbsd-x64': 0.25.9 - '@esbuild/openbsd-arm64': 0.25.9 - '@esbuild/openbsd-x64': 0.25.9 - '@esbuild/openharmony-arm64': 0.25.9 - '@esbuild/sunos-x64': 0.25.9 - '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 escalade@3.2.0: {} @@ -3444,17 +3444,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0)(typescript@5.9.2) eslint: 9.35.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -3465,7 +3465,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.35.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -3477,7 +3477,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0)(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -3519,7 +3519,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -3934,7 +3934,7 @@ snapshots: mermaid@11.11.0: dependencies: '@braintree/sanitize-url': 7.1.1 - '@iconify/utils': 3.0.1 + '@iconify/utils': 3.0.2 '@mermaid-js/parser': 0.6.2 '@types/d3': 7.4.3 cytoscape: 3.33.1 @@ -3944,7 +3944,7 @@ snapshots: d3-sankey: 0.12.3 dagre-d3-es: 7.0.11 dayjs: 1.11.18 - dompurify: 3.2.6 + dompurify: 3.2.7 katex: 0.16.22 khroma: 2.1.0 lodash-es: 4.17.21 @@ -3984,7 +3984,7 @@ snapshots: dependencies: browser-stdout: 1.3.1 chokidar: 4.0.3 - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) diff: 7.0.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 @@ -4090,7 +4090,7 @@ snapshots: pdfjs-dist@5.4.149: optionalDependencies: - '@napi-rs/canvas': 0.1.79 + '@napi-rs/canvas': 0.1.80 picocolors@1.1.1: {} @@ -4345,7 +4345,7 @@ snapshots: tinyexec@1.0.1: {} - tinymce@8.0.2: {} + tinymce@8.1.1: {} to-regex-range@5.0.1: dependencies: @@ -4414,7 +4414,7 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.10.0: {} + undici-types@7.12.0: {} uri-js@4.4.1: dependencies: diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts index 8b647c7f..d65dee0b 100644 --- a/client/src/CodeChatEditor.mts +++ b/client/src/CodeChatEditor.mts @@ -267,7 +267,7 @@ const _open_lp = async ( // in`source.doc`. We don't need the CodeMirror editor at all; // instead, treat it like a single doc block contents div. doc_content = source.Plain.doc; - codechat_body.innerHTML = `
${doc_content}
`; + codechat_body.innerHTML = `
${doc_content}
`; await init({ selector: ".CodeChat-doc-contents", // In the doc-only mode, add autosave functionality. While there diff --git a/client/src/css/CodeChatEditor.css b/client/src/css/CodeChatEditor.css index 1422a70b..4339aa1d 100644 --- a/client/src/css/CodeChatEditor.css +++ b/client/src/css/CodeChatEditor.css @@ -37,7 +37,7 @@ This is used only to store a reused variable value. See the [CSS docs](https://drafts.csswg.org/css-variables/). */ :root { - --top-height: 6.7rem; + --top-height: 3.7rem; --body-padding: 0.2rem; } diff --git a/client/src/tinymce-config.mts b/client/src/tinymce-config.mts index c4459d74..42e1704d 100644 --- a/client/src/tinymce-config.mts +++ b/client/src/tinymce-config.mts @@ -14,9 +14,9 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // -// `tinymce-webpack.ts` -- integrate and configure the TinyMCE editor for use +// `tinymce-config.ts` -- integrate and configure the TinyMCE editor for use // with the CodeChat Editor -// ========================================================================== +// ========================================================================= // // Import TinyMCE. import { @@ -68,74 +68,107 @@ import "tinymce/plugins/visualblocks/index.js"; import "tinymce/plugins/visualchars/index.js"; // Import premium plugins. NOTE: Download separately and add these to -// /src/plugins. +// `src/plugins`. /// import './plugins/checklist/plugin'; /// import './plugins/powerpaste/plugin'; /// import './plugins/powerpaste/js/wordimport'; // Initialize TinyMCE. export const init = async ( - // Provide editor options; don't set \`\`plugins\`\` or \`\`skin\`\`, since - // these must be accompanied by the correct imports. + // Provide editor options; don't set `plugins` or `skin`, since these must + // be accompanied by the correct imports. options: RawEditorOptions, -) => - // See - // [init()](https://www.tiny.cloud/docs/tinymce/6/apis/tinymce.root/#init). - tinymce.init( - Object.assign({}, options, { - // See the list of - // [plugins](https://www.tiny.cloud/docs/tinymce/6/plugins/). These - // must be accompanied by the corresponding import above. - plugins: - "advlist anchor charmap directionality emoticons help image link lists media nonbreaking pagebreak quickbars searchreplace table visualblocks visualchars", - // The imports above apply the skins; don't try to dynamically load - // the skin's CSS. - skin: false, - // Enable the [browser-supplied - // spellchecker](https://www.tiny.cloud/docs/tinymce/6/spelling/#browser_spellcheck), - // since TinyMCE's spellchecker is a premium feature. - browser_spellcheck: true, - // Put more buttons on the [quick - // toolbar](https://www.tiny.cloud/docs/tinymce/6/quickbars/) that - // appears when text is selected. TODO: add a button for code format - // (can't find this one -- it's only on the [list of menu - // items](https://www.tiny.cloud/docs/tinymce/6/available-menu-items/#the-core-menu-items) - // as `codeformat`). - quickbars_selection_toolbar: - "align | bold italic underline | quicklink h2 h3 blockquote", - // Place the Tiny MCE menu bar at the top of the screen; otherwise, - // it floats in front of text, sometimes obscuring what the user - // wants to edit. See the - // [docs](https://www.tiny.cloud/docs/configure/editor-appearance/#fixed_toolbar_container). - fixed_toolbar_container: "#CodeChat-menu", - inline: true, - // When true, this still prevents hyperlinks to anchors on the - // current page from working correctly. There's an onClick handler - // that prevents links in the current page from working -- need to - // look into this. See also [a related GitHub - // issue](https://github.com/tinymce/tinymce/issues/3836). - //readonly: true // Per the comment above, this is commented out. - // TODO: Notes on this setting. - relative_urls: true, - // This combines the [default TinyMCE toolbar - // buttons](https://www.tiny.cloud/blog/tinymce-toolbar/) with a few - // more from plugins. I like the default, so this is currently - // disabled. - //toolbar: 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | ltr rtl | help', - // See [License - // key](https://www.tiny.cloud/docs/tinymce/latest/license-key). - license_key: "gpl", +) => { + // Merge the provided options with these default options. + let combinedOptions = Object.assign({}, options, { + // See the list of + // [plugins](https://www.tiny.cloud/docs/tinymce/6/plugins/). These must + // be accompanied by the corresponding import above. + plugins: + "advlist anchor charmap directionality emoticons help image link lists media nonbreaking pagebreak quickbars searchreplace table visualblocks visualchars", + // The imports above apply the skins; don't try to dynamically load the + // skin's CSS. + skin: false, + // Enable the [browser-supplied + // spellchecker](https://www.tiny.cloud/docs/tinymce/6/spelling/#browser_spellcheck), + // since TinyMCE's spellchecker is a premium feature. + browser_spellcheck: true, + // Place the Tiny MCE menu bar at the top of the screen; otherwise, it + // floats in front of text, sometimes obscuring what the user wants to + // edit. See the + // [docs](https://www.tiny.cloud/docs/configure/editor-appearance/#fixed_toolbar_container). + fixed_toolbar_container: "#CodeChat-menu", + inline: true, + // When true, this still prevents hyperlinks to anchors on the current + // page from working correctly. There's an onClick handler that prevents + // links in the current page from working -- need to look into this. See + // also [a related GitHub + // issue](https://github.com/tinymce/tinymce/issues/3836). + //readonly: true // Per the comment above, this is commented out. + // Use relative URLs in hyperlinks. + relative_urls: true, + // Disable the [TinyMCE toolbar + // buttons](https://www.tiny.cloud/blog/tinymce-toolbar/) to provide + // more real estate on the screen. + toolbar: false, + // Don't show the file option on the + // [menu](https://www.tiny.cloud/docs/tinymce/6/menus-configuration-options/#menubar), + // which is useless. + menubar: "edit insert view format table tools help", + // See [License + // key](https://www.tiny.cloud/docs/tinymce/latest/license-key). + license_key: "gpl", - // Settings for plugins - // - // [Image](https://www.tiny.cloud/docs/plugins/opensource/image/) - image_caption: true, - image_advtab: true, - image_title: true, - // Needed to allow custom elements. - extended_valid_elements: - "graphviz-graph[graph|scale],graphviz-script-editor[value|tab],graphviz-combined[graph|scale],wc-mermaid", - custom_elements: - "graphviz-graph,graphviz-script-editor,graphviz-combined,wc-mermaid", - }), - ); + // ### Settings for plugins + // + // [Image](https://www.tiny.cloud/docs/plugins/opensource/image/) + image_caption: true, + image_advtab: true, + image_title: true, + + // Quickbar config: disable the insert toolbar (which doesn't seem + // useful, and also has the image insert, which is problematic + // currently). + quickbars_insert_toolbar: false, + // Put more buttons on the [quick + // toolbar](https://www.tiny.cloud/docs/tinymce/6/quickbars/) that + // appears when text is selected. TODO: add a button for code format + // (can't find this one -- it's only on the [list of menu + // items](https://www.tiny.cloud/docs/tinymce/6/available-menu-items/#the-core-menu-items) + // as `codeformat`). + quickbars_selection_toolbar: + "bold italic underline codeformat | quicklink h2 h3", + + // Needed to allow custom elements. + extended_valid_elements: + "graphviz-graph[graph|scale],graphviz-script-editor[value|tab],graphviz-combined[graph|scale],wc-mermaid", + custom_elements: + "graphviz-graph,graphviz-script-editor,graphviz-combined,wc-mermaid", + }); + + // Merge in additional setup code. + const oldSetup = combinedOptions.setup; + combinedOptions.setup = + // Add a "Format as code" button (generated by Gemini). + (editor: Editor) => { + oldSetup?.(editor); + editor.ui.registry.addToggleButton("codeformat", { + text: "<>", + tooltip: "Format as code", + onAction: (_) => + editor.execCommand("mceToggleFormat", false, "code"), + onSetup: (api) => { + const changed = editor.formatter.formatChanged( + "code", + (state) => api.setActive(state), + ); + return () => changed.unbind(); + }, + }); + }; + + // Use these combiend options to + // [init](https://www.tiny.cloud/docs/tinymce/6/apis/tinymce.root/#init) + // TinyMCE. + return tinymce.init(combinedOptions); +}; diff --git a/extensions/VSCode/Cargo.lock b/extensions/VSCode/Cargo.lock index 130f4044..f50c407b 100644 --- a/extensions/VSCode/Cargo.lock +++ b/extensions/VSCode/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-files" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22c8b5536deb14cd9c3e505bd0e3366e1a12383b659c92f2b4fa4d323d583599" +checksum = "6c0d87f10d70e2948ad40e8edea79c8e77c6c66e0250a4c1f09b690465199576" dependencies = [ "actix-http", "actix-service", @@ -451,9 +451,9 @@ dependencies = [ [[package]] name = "bytestring" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" dependencies = [ "bytes", ] @@ -537,7 +537,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "codechat-editor-server" -version = "0.1.35" +version = "0.1.36" dependencies = [ "actix-files", "actix-http", @@ -580,14 +580,17 @@ dependencies = [ [[package]] name = "codechat-editor-vscode-extension" -version = "0.1.35" +version = "0.1.36" dependencies = [ "actix-server", + "actix-web", "codechat-editor-server", "log", "napi", "napi-build", "napi-derive", + "rand", + "serde_json", "tokio", ] @@ -921,7 +924,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.5+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -1157,9 +1160,9 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.11.1" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" dependencies = [ "equivalent", "hashbrown", @@ -1248,9 +1251,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -1306,9 +1309,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.9.4", "libc", @@ -1964,16 +1967,17 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ + "serde_core", "serde_derive", ] @@ -1987,11 +1991,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", @@ -2000,14 +2013,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2551,18 +2565,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.5+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ "wasip2", ] [[package]] name = "wasip2" -version = "1.0.0+wasi-0.2.4" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] @@ -2575,9 +2589,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -2588,9 +2602,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -2602,9 +2616,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2612,9 +2626,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -2625,18 +2639,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", @@ -3034,9 +3048,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" diff --git a/extensions/VSCode/Cargo.toml b/extensions/VSCode/Cargo.toml index 92e4f116..64251679 100644 --- a/extensions/VSCode/Cargo.toml +++ b/extensions/VSCode/Cargo.toml @@ -32,17 +32,20 @@ license = "GPL-3.0-only" name = "codechat-editor-vscode-extension" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.35" +version = "0.1.36" [lib] crate-type = ["cdylib"] [dependencies] actix-server = "2.6.0" +actix-web = "4.11.0" codechat-editor-server = { path = "../../server" } log = "0.4.28" napi = { version = "3.0.0", features = ["tokio_rt"] } napi-derive = "3.0.0" +rand = "0.9.2" +serde_json = "1.0.145" tokio = "1.47.1" [build-dependencies] diff --git a/extensions/VSCode/package.json b/extensions/VSCode/package.json index 0bbae4e1..b6c02cd1 100644 --- a/extensions/VSCode/package.json +++ b/extensions/VSCode/package.json @@ -39,7 +39,7 @@ "type": "git", "url": "https://github.com/bjones1/CodeChat_Editor" }, - "version": "0.1.35", + "version": "0.1.36", "activationEvents": [ "onCommand:extension.codeChatEditorActivate", "onCommand:extension.codeChatEditorDeactivate" @@ -87,8 +87,7 @@ ] }, "dependencies": { - "escape-html": "^1.0.3", - "ws": "^8.18.3" + "escape-html": "^1.0.3" }, "devDependencies": { "@emnapi/core": "^1.5.0", @@ -96,13 +95,13 @@ "@napi-rs/cli": "^3.2.0", "@tybys/wasm-util": "^0.10.1", "@types/escape-html": "^1.0.4", + "@types/node": "^24.5.1", "@types/vscode": "1.61.0", - "@types/ws": "^8.18.1", - "@typescript-eslint/eslint-plugin": "^8.43.0", - "@typescript-eslint/parser": "^8.43.0", + "@typescript-eslint/eslint-plugin": "^8.44.0", + "@typescript-eslint/parser": "^8.44.0", "@vscode/vsce": "^3.6.0", "chalk": "^5.6.2", - "esbuild": "^0.25.9", + "esbuild": "^0.25.10", "eslint": "^9.35.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.32.0", diff --git a/extensions/VSCode/pnpm-lock.yaml b/extensions/VSCode/pnpm-lock.yaml index d57fe6eb..b780ca00 100644 --- a/extensions/VSCode/pnpm-lock.yaml +++ b/extensions/VSCode/pnpm-lock.yaml @@ -11,9 +11,6 @@ importers: escape-html: specifier: ^1.0.3 version: 1.0.3 - ws: - specifier: ^8.18.3 - version: 8.18.3(bufferutil@4.0.9) devDependencies: '@emnapi/core': specifier: ^1.5.0 @@ -23,25 +20,25 @@ importers: version: 1.5.0 '@napi-rs/cli': specifier: ^3.2.0 - version: 3.2.0(@emnapi/runtime@1.5.0)(@types/node@24.3.3) + version: 3.2.0(@emnapi/runtime@1.5.0)(@types/node@24.5.1) '@tybys/wasm-util': specifier: ^0.10.1 version: 0.10.1 '@types/escape-html': specifier: ^1.0.4 version: 1.0.4 + '@types/node': + specifier: ^24.5.1 + version: 24.5.1 '@types/vscode': specifier: 1.61.0 version: 1.61.0 - '@types/ws': - specifier: ^8.18.1 - version: 8.18.1 '@typescript-eslint/eslint-plugin': - specifier: ^8.43.0 - version: 8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2) + specifier: ^8.44.0 + version: 8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2) '@typescript-eslint/parser': - specifier: ^8.43.0 - version: 8.43.0(eslint@9.35.0)(typescript@5.9.2) + specifier: ^8.44.0 + version: 8.44.0(eslint@9.35.0)(typescript@5.9.2) '@vscode/vsce': specifier: ^3.6.0 version: 3.6.0 @@ -49,8 +46,8 @@ importers: specifier: ^5.6.2 version: 5.6.2 esbuild: - specifier: ^0.25.9 - version: 0.25.9 + specifier: ^0.25.10 + version: 0.25.10 eslint: specifier: ^9.35.0 version: 9.35.0 @@ -59,7 +56,7 @@ importers: version: 10.1.8(eslint@9.35.0) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0) + version: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0) eslint-plugin-node: specifier: ^11.1.0 version: 11.1.0(eslint@9.35.0) @@ -120,16 +117,16 @@ packages: resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} engines: {node: '>=20.0.0'} - '@azure/msal-browser@4.22.1': - resolution: {integrity: sha512-/I76rBJpt5ZVfFXk+GkKxD4w1DZEbVpNn0aQjvRgnDnTYo3L/f8Oeo3R1O9eL/ccg5j1537iRLr7UwVhwnHtyg==} + '@azure/msal-browser@4.23.0': + resolution: {integrity: sha512-uHnfRwGAEHaYVXzpCtYsruy6PQxL2v76+MJ3+n/c/3PaTiTIa5ch7VofTUNoA39nHyjJbdiqTwFZK40OOTOkjw==} engines: {node: '>=0.8.0'} '@azure/msal-common@15.12.0': resolution: {integrity: sha512-4ucXbjVw8KJ5QBgnGJUeA07c8iznwlk5ioHIhI4ASXcXgcf2yRFhWzYOyWg/cI49LC9ekpFJeQtO3zjDTbl6TQ==} engines: {node: '>=0.8.0'} - '@azure/msal-node@3.7.3': - resolution: {integrity: sha512-MoJxkKM/YpChfq4g2o36tElyzNUMG8mfD6u8NbuaPAsqfGpaw249khAcJYNoIOigUzRw45OjXCOrexE6ImdUxg==} + '@azure/msal-node@3.7.4': + resolution: {integrity: sha512-fjqvhrThwzzPvqhFOdkkGRJCHPQZTNijpceVy8QjcfQuH482tOVEjHyamZaioOhVtx+FK1u+eMpJA2Zz4U9LVg==} engines: {node: '>=16'} '@babel/code-frame@7.27.1': @@ -149,158 +146,158 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + '@esbuild/aix-ppc64@0.25.10': + resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + '@esbuild/android-arm64@0.25.10': + resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + '@esbuild/android-arm@0.25.10': + resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + '@esbuild/android-x64@0.25.10': + resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + '@esbuild/darwin-arm64@0.25.10': + resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + '@esbuild/darwin-x64@0.25.10': + resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + '@esbuild/freebsd-arm64@0.25.10': + resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + '@esbuild/freebsd-x64@0.25.10': + resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + '@esbuild/linux-arm64@0.25.10': + resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + '@esbuild/linux-arm@0.25.10': + resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + '@esbuild/linux-ia32@0.25.10': + resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + '@esbuild/linux-loong64@0.25.10': + resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + '@esbuild/linux-mips64el@0.25.10': + resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + '@esbuild/linux-ppc64@0.25.10': + resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + '@esbuild/linux-riscv64@0.25.10': + resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + '@esbuild/linux-s390x@0.25.10': + resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + '@esbuild/linux-x64@0.25.10': + resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + '@esbuild/netbsd-arm64@0.25.10': + resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + '@esbuild/netbsd-x64@0.25.10': + resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + '@esbuild/openbsd-arm64@0.25.10': + resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + '@esbuild/openbsd-x64@0.25.10': + resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + '@esbuild/openharmony-arm64@0.25.10': + resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + '@esbuild/sunos-x64@0.25.10': + resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + '@esbuild/win32-arm64@0.25.10': + resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + '@esbuild/win32-ia32@0.25.10': + resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + '@esbuild/win32-x64@0.25.10': + resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -359,8 +356,12 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@inquirer/checkbox@4.2.2': - resolution: {integrity: sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==} + '@inquirer/ansi@1.0.0': + resolution: {integrity: sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==} + engines: {node: '>=18'} + + '@inquirer/checkbox@4.2.4': + resolution: {integrity: sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -368,8 +369,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.16': - resolution: {integrity: sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==} + '@inquirer/confirm@5.1.18': + resolution: {integrity: sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -377,8 +378,8 @@ packages: '@types/node': optional: true - '@inquirer/core@10.2.0': - resolution: {integrity: sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==} + '@inquirer/core@10.2.2': + resolution: {integrity: sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -386,8 +387,8 @@ packages: '@types/node': optional: true - '@inquirer/editor@4.2.18': - resolution: {integrity: sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==} + '@inquirer/editor@4.2.20': + resolution: {integrity: sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -395,8 +396,8 @@ packages: '@types/node': optional: true - '@inquirer/expand@4.0.18': - resolution: {integrity: sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==} + '@inquirer/expand@4.0.20': + resolution: {integrity: sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -404,8 +405,8 @@ packages: '@types/node': optional: true - '@inquirer/external-editor@1.0.1': - resolution: {integrity: sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==} + '@inquirer/external-editor@1.0.2': + resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -417,8 +418,8 @@ packages: resolution: {integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==} engines: {node: '>=18'} - '@inquirer/input@4.2.2': - resolution: {integrity: sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==} + '@inquirer/input@4.2.4': + resolution: {integrity: sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -426,8 +427,8 @@ packages: '@types/node': optional: true - '@inquirer/number@3.0.18': - resolution: {integrity: sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==} + '@inquirer/number@3.0.20': + resolution: {integrity: sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -435,8 +436,8 @@ packages: '@types/node': optional: true - '@inquirer/password@4.0.18': - resolution: {integrity: sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==} + '@inquirer/password@4.0.20': + resolution: {integrity: sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -444,8 +445,8 @@ packages: '@types/node': optional: true - '@inquirer/prompts@7.8.4': - resolution: {integrity: sha512-MuxVZ1en1g5oGamXV3DWP89GEkdD54alcfhHd7InUW5BifAdKQEK9SLFa/5hlWbvuhMPlobF0WAx7Okq988Jxg==} + '@inquirer/prompts@7.8.6': + resolution: {integrity: sha512-68JhkiojicX9SBUD8FE/pSKbOKtwoyaVj1kwqLfvjlVXZvOy3iaSWX4dCLsZyYx/5Ur07Fq+yuDNOen+5ce6ig==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -453,8 +454,8 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@4.1.6': - resolution: {integrity: sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==} + '@inquirer/rawlist@4.1.8': + resolution: {integrity: sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -462,8 +463,8 @@ packages: '@types/node': optional: true - '@inquirer/search@3.1.1': - resolution: {integrity: sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==} + '@inquirer/search@3.1.3': + resolution: {integrity: sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -471,8 +472,8 @@ packages: '@types/node': optional: true - '@inquirer/select@4.3.2': - resolution: {integrity: sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==} + '@inquirer/select@4.3.4': + resolution: {integrity: sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -756,8 +757,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@napi-rs/wasm-runtime@1.0.4': - resolution: {integrity: sha512-+ZEtJPp8EF8h4kN6rLQECRor00H7jtDgBVtttIUoxuDkXLiQMaSBqju3LV/IEsMvqVG5pviUvR4jYhIA1xNm8w==} + '@napi-rs/wasm-runtime@1.0.5': + resolution: {integrity: sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==} '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==} @@ -943,8 +944,8 @@ packages: resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} - '@octokit/core@7.0.3': - resolution: {integrity: sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ==} + '@octokit/core@7.0.4': + resolution: {integrity: sha512-jOT8V1Ba5BdC79sKrRWDdMT5l1R+XNHTPR6CPWzUP2EcfAcvIHZWF0eAbmRcpOOP5gVIwnqNg0C4nvh6Abc3OA==} engines: {node: '>= 20'} '@octokit/endpoint@11.0.0': @@ -958,6 +959,9 @@ packages: '@octokit/openapi-types@25.1.0': resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==} + '@octokit/openapi-types@26.0.0': + resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} + '@octokit/plugin-paginate-rest@13.1.1': resolution: {integrity: sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw==} engines: {node: '>= 20'} @@ -970,8 +974,8 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@16.0.0': - resolution: {integrity: sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g==} + '@octokit/plugin-rest-endpoint-methods@16.1.0': + resolution: {integrity: sha512-nCsyiKoGRnhH5LkH8hJEZb9swpqOcsW+VXv1QoyUNQXJeVODG4+xM6UICEqyqe9XFr6LkL8BIiFCPev8zMDXPw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -991,6 +995,9 @@ packages: '@octokit/types@14.1.0': resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} + '@octokit/types@15.0.0': + resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -1073,8 +1080,8 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/node@24.3.3': - resolution: {integrity: sha512-GKBNHjoNw3Kra1Qg5UXttsY5kiWMEfoHq2TmXb+b1rcm6N7B3wTrFYIf/oSZ1xNQ+hVVijgLkiDZh7jRRsh+Gw==} + '@types/node@24.5.1': + resolution: {integrity: sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1085,66 +1092,63 @@ packages: '@types/vscode@1.61.0': resolution: {integrity: sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - - '@typescript-eslint/eslint-plugin@8.43.0': - resolution: {integrity: sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==} + '@typescript-eslint/eslint-plugin@8.44.0': + resolution: {integrity: sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.43.0 + '@typescript-eslint/parser': ^8.44.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.43.0': - resolution: {integrity: sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==} + '@typescript-eslint/parser@8.44.0': + resolution: {integrity: sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.43.0': - resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==} + '@typescript-eslint/project-service@8.44.0': + resolution: {integrity: sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.43.0': - resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==} + '@typescript-eslint/scope-manager@8.44.0': + resolution: {integrity: sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.43.0': - resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==} + '@typescript-eslint/tsconfig-utils@8.44.0': + resolution: {integrity: sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.43.0': - resolution: {integrity: sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==} + '@typescript-eslint/type-utils@8.44.0': + resolution: {integrity: sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.43.0': - resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==} + '@typescript-eslint/types@8.44.0': + resolution: {integrity: sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.43.0': - resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==} + '@typescript-eslint/typescript-estree@8.44.0': + resolution: {integrity: sha512-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.43.0': - resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==} + '@typescript-eslint/utils@8.44.0': + resolution: {integrity: sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.43.0': - resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==} + '@typescript-eslint/visitor-keys@8.44.0': + resolution: {integrity: sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typespec/ts-http-runtime@0.3.1': @@ -1224,10 +1228,6 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - ansi-escapes@7.1.0: resolution: {integrity: sha512-YdhtCd19sKRKfAAUsrcC1wzm4JuzJoiX4pOJqIoW2qmKj5WzG/dL8uUJ0361zaXtHqK7gEhOwtAtz7t3Yq3X5g==} engines: {node: '>=18'} @@ -1454,8 +1454,8 @@ packages: supports-color: optional: true - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1498,8 +1498,8 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.0: + resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==} engines: {node: '>=8'} doctrine@2.1.0: @@ -1588,8 +1588,8 @@ packages: es-toolkit@1.39.10: resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==} - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + esbuild@0.25.10: + resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} engines: {node: '>=18'} hasBin: true @@ -1783,8 +1783,8 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@11.3.1: - resolution: {integrity: sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==} + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} engines: {node: '>=14.14'} function-bind@1.1.2: @@ -1897,6 +1897,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2713,8 +2717,8 @@ packages: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} - tar-fs@2.1.3: - resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -2765,10 +2769,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -2807,8 +2807,8 @@ packages: underscore@1.13.7: resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + undici-types@7.12.0: + resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} undici@7.16.0: resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} @@ -2902,18 +2902,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - wsl-utils@0.1.0: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} @@ -3016,8 +3004,8 @@ snapshots: '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 - '@azure/msal-browser': 4.22.1 - '@azure/msal-node': 3.7.3 + '@azure/msal-browser': 4.23.0 + '@azure/msal-node': 3.7.4 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -3030,13 +3018,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/msal-browser@4.22.1': + '@azure/msal-browser@4.23.0': dependencies: '@azure/msal-common': 15.12.0 '@azure/msal-common@15.12.0': {} - '@azure/msal-node@3.7.3': + '@azure/msal-node@3.7.4': dependencies: '@azure/msal-common': 15.12.0 jsonwebtoken: 9.0.2 @@ -3063,82 +3051,82 @@ snapshots: dependencies: tslib: 2.8.1 - '@esbuild/aix-ppc64@0.25.9': + '@esbuild/aix-ppc64@0.25.10': optional: true - '@esbuild/android-arm64@0.25.9': + '@esbuild/android-arm64@0.25.10': optional: true - '@esbuild/android-arm@0.25.9': + '@esbuild/android-arm@0.25.10': optional: true - '@esbuild/android-x64@0.25.9': + '@esbuild/android-x64@0.25.10': optional: true - '@esbuild/darwin-arm64@0.25.9': + '@esbuild/darwin-arm64@0.25.10': optional: true - '@esbuild/darwin-x64@0.25.9': + '@esbuild/darwin-x64@0.25.10': optional: true - '@esbuild/freebsd-arm64@0.25.9': + '@esbuild/freebsd-arm64@0.25.10': optional: true - '@esbuild/freebsd-x64@0.25.9': + '@esbuild/freebsd-x64@0.25.10': optional: true - '@esbuild/linux-arm64@0.25.9': + '@esbuild/linux-arm64@0.25.10': optional: true - '@esbuild/linux-arm@0.25.9': + '@esbuild/linux-arm@0.25.10': optional: true - '@esbuild/linux-ia32@0.25.9': + '@esbuild/linux-ia32@0.25.10': optional: true - '@esbuild/linux-loong64@0.25.9': + '@esbuild/linux-loong64@0.25.10': optional: true - '@esbuild/linux-mips64el@0.25.9': + '@esbuild/linux-mips64el@0.25.10': optional: true - '@esbuild/linux-ppc64@0.25.9': + '@esbuild/linux-ppc64@0.25.10': optional: true - '@esbuild/linux-riscv64@0.25.9': + '@esbuild/linux-riscv64@0.25.10': optional: true - '@esbuild/linux-s390x@0.25.9': + '@esbuild/linux-s390x@0.25.10': optional: true - '@esbuild/linux-x64@0.25.9': + '@esbuild/linux-x64@0.25.10': optional: true - '@esbuild/netbsd-arm64@0.25.9': + '@esbuild/netbsd-arm64@0.25.10': optional: true - '@esbuild/netbsd-x64@0.25.9': + '@esbuild/netbsd-x64@0.25.10': optional: true - '@esbuild/openbsd-arm64@0.25.9': + '@esbuild/openbsd-arm64@0.25.10': optional: true - '@esbuild/openbsd-x64@0.25.9': + '@esbuild/openbsd-x64@0.25.10': optional: true - '@esbuild/openharmony-arm64@0.25.9': + '@esbuild/openharmony-arm64@0.25.10': optional: true - '@esbuild/sunos-x64@0.25.9': + '@esbuild/sunos-x64@0.25.10': optional: true - '@esbuild/win32-arm64@0.25.9': + '@esbuild/win32-arm64@0.25.10': optional: true - '@esbuild/win32-ia32@0.25.9': + '@esbuild/win32-ia32@0.25.10': optional: true - '@esbuild/win32-x64@0.25.9': + '@esbuild/win32-x64@0.25.10': optional: true '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0)': @@ -3151,7 +3139,7 @@ snapshots: '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.1 + debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3165,7 +3153,7 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -3196,128 +3184,130 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/checkbox@4.2.2(@types/node@24.3.3)': + '@inquirer/ansi@1.0.0': {} + + '@inquirer/checkbox@4.2.4(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) + '@inquirer/ansi': 1.0.0 + '@inquirer/core': 10.2.2(@types/node@24.5.1) '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.3.3) - ansi-escapes: 4.3.2 + '@inquirer/type': 3.0.8(@types/node@24.5.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/confirm@5.1.16(@types/node@24.3.3)': + '@inquirer/confirm@5.1.18(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/core@10.2.0(@types/node@24.3.3)': + '@inquirer/core@10.2.2(@types/node@24.5.1)': dependencies: + '@inquirer/ansi': 1.0.0 '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.3.3) - ansi-escapes: 4.3.2 + '@inquirer/type': 3.0.8(@types/node@24.5.1) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/editor@4.2.18(@types/node@24.3.3)': + '@inquirer/editor@4.2.20(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/external-editor': 1.0.1(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/external-editor': 1.0.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/expand@4.0.18(@types/node@24.3.3)': + '@inquirer/expand@4.0.20(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/external-editor@1.0.1(@types/node@24.3.3)': + '@inquirer/external-editor@1.0.2(@types/node@24.5.1)': dependencies: chardet: 2.1.0 - iconv-lite: 0.6.3 + iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 '@inquirer/figures@1.0.13': {} - '@inquirer/input@4.2.2(@types/node@24.3.3)': + '@inquirer/input@4.2.4(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/number@3.0.18(@types/node@24.3.3)': + '@inquirer/number@3.0.20(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/password@4.0.18(@types/node@24.3.3)': + '@inquirer/password@4.0.20(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) - ansi-escapes: 4.3.2 + '@inquirer/ansi': 1.0.0 + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) optionalDependencies: - '@types/node': 24.3.3 - - '@inquirer/prompts@7.8.4(@types/node@24.3.3)': - dependencies: - '@inquirer/checkbox': 4.2.2(@types/node@24.3.3) - '@inquirer/confirm': 5.1.16(@types/node@24.3.3) - '@inquirer/editor': 4.2.18(@types/node@24.3.3) - '@inquirer/expand': 4.0.18(@types/node@24.3.3) - '@inquirer/input': 4.2.2(@types/node@24.3.3) - '@inquirer/number': 3.0.18(@types/node@24.3.3) - '@inquirer/password': 4.0.18(@types/node@24.3.3) - '@inquirer/rawlist': 4.1.6(@types/node@24.3.3) - '@inquirer/search': 3.1.1(@types/node@24.3.3) - '@inquirer/select': 4.3.2(@types/node@24.3.3) + '@types/node': 24.5.1 + + '@inquirer/prompts@7.8.6(@types/node@24.5.1)': + dependencies: + '@inquirer/checkbox': 4.2.4(@types/node@24.5.1) + '@inquirer/confirm': 5.1.18(@types/node@24.5.1) + '@inquirer/editor': 4.2.20(@types/node@24.5.1) + '@inquirer/expand': 4.0.20(@types/node@24.5.1) + '@inquirer/input': 4.2.4(@types/node@24.5.1) + '@inquirer/number': 3.0.20(@types/node@24.5.1) + '@inquirer/password': 4.0.20(@types/node@24.5.1) + '@inquirer/rawlist': 4.1.8(@types/node@24.5.1) + '@inquirer/search': 3.1.3(@types/node@24.5.1) + '@inquirer/select': 4.3.4(@types/node@24.5.1) optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/rawlist@4.1.6(@types/node@24.3.3)': + '@inquirer/rawlist@4.1.8(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) + '@inquirer/type': 3.0.8(@types/node@24.5.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/search@3.1.1(@types/node@24.3.3)': + '@inquirer/search@3.1.3(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) + '@inquirer/core': 10.2.2(@types/node@24.5.1) '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.3.3) + '@inquirer/type': 3.0.8(@types/node@24.5.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/select@4.3.2(@types/node@24.3.3)': + '@inquirer/select@4.3.4(@types/node@24.5.1)': dependencies: - '@inquirer/core': 10.2.0(@types/node@24.3.3) + '@inquirer/ansi': 1.0.0 + '@inquirer/core': 10.2.2(@types/node@24.5.1) '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@24.3.3) - ansi-escapes: 4.3.2 + '@inquirer/type': 3.0.8(@types/node@24.5.1) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 - '@inquirer/type@3.0.8(@types/node@24.3.3)': + '@inquirer/type@3.0.8(@types/node@24.5.1)': optionalDependencies: - '@types/node': 24.3.3 + '@types/node': 24.5.1 '@isaacs/balanced-match@4.0.1': {} @@ -3334,15 +3324,15 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@napi-rs/cli@3.2.0(@emnapi/runtime@1.5.0)(@types/node@24.3.3)': + '@napi-rs/cli@3.2.0(@emnapi/runtime@1.5.0)(@types/node@24.5.1)': dependencies: - '@inquirer/prompts': 7.8.4(@types/node@24.3.3) + '@inquirer/prompts': 7.8.6(@types/node@24.5.1) '@napi-rs/cross-toolchain': 1.0.3 '@napi-rs/wasm-tools': 1.0.1 '@octokit/rest': 22.0.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - debug: 4.4.1 + debug: 4.4.3 es-toolkit: 1.39.10 find-up: 7.0.0 js-yaml: 4.1.0 @@ -3368,7 +3358,7 @@ snapshots: dependencies: '@napi-rs/lzma': 1.4.5 '@napi-rs/tar': 1.1.0 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -3413,7 +3403,7 @@ snapshots: '@napi-rs/lzma-wasm32-wasi@1.4.5': dependencies: - '@napi-rs/wasm-runtime': 1.0.4 + '@napi-rs/wasm-runtime': 1.0.5 optional: true '@napi-rs/lzma-win32-arm64-msvc@1.4.5': @@ -3483,7 +3473,7 @@ snapshots: '@napi-rs/tar-wasm32-wasi@1.1.0': dependencies: - '@napi-rs/wasm-runtime': 1.0.4 + '@napi-rs/wasm-runtime': 1.0.5 optional: true '@napi-rs/tar-win32-arm64-msvc@1.1.0': @@ -3521,7 +3511,7 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@napi-rs/wasm-runtime@1.0.4': + '@napi-rs/wasm-runtime@1.0.5': dependencies: '@emnapi/core': 1.5.0 '@emnapi/runtime': 1.5.0 @@ -3557,7 +3547,7 @@ snapshots: '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': dependencies: - '@napi-rs/wasm-runtime': 1.0.4 + '@napi-rs/wasm-runtime': 1.0.5 optional: true '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': @@ -3660,13 +3650,13 @@ snapshots: '@octokit/auth-token@6.0.0': {} - '@octokit/core@7.0.3': + '@octokit/core@7.0.4': dependencies: '@octokit/auth-token': 6.0.0 '@octokit/graphql': 9.0.1 '@octokit/request': 10.0.3 '@octokit/request-error': 7.0.0 - '@octokit/types': 14.1.0 + '@octokit/types': 15.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 @@ -3683,19 +3673,21 @@ snapshots: '@octokit/openapi-types@25.1.0': {} - '@octokit/plugin-paginate-rest@13.1.1(@octokit/core@7.0.3)': + '@octokit/openapi-types@26.0.0': {} + + '@octokit/plugin-paginate-rest@13.1.1(@octokit/core@7.0.4)': dependencies: - '@octokit/core': 7.0.3 + '@octokit/core': 7.0.4 '@octokit/types': 14.1.0 - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.3)': + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.4)': dependencies: - '@octokit/core': 7.0.3 + '@octokit/core': 7.0.4 - '@octokit/plugin-rest-endpoint-methods@16.0.0(@octokit/core@7.0.3)': + '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.4)': dependencies: - '@octokit/core': 7.0.3 - '@octokit/types': 14.1.0 + '@octokit/core': 7.0.4 + '@octokit/types': 15.0.0 '@octokit/request-error@7.0.0': dependencies: @@ -3711,15 +3703,19 @@ snapshots: '@octokit/rest@22.0.0': dependencies: - '@octokit/core': 7.0.3 - '@octokit/plugin-paginate-rest': 13.1.1(@octokit/core@7.0.3) - '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.3) - '@octokit/plugin-rest-endpoint-methods': 16.0.0(@octokit/core@7.0.3) + '@octokit/core': 7.0.4 + '@octokit/plugin-paginate-rest': 13.1.1(@octokit/core@7.0.4) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.4) + '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.4) '@octokit/types@14.1.0': dependencies: '@octokit/openapi-types': 25.1.0 + '@octokit/types@15.0.0': + dependencies: + '@octokit/openapi-types': 26.0.0 + '@rtsao/scc@1.1.0': {} '@secretlint/config-creator@10.2.2': @@ -3732,7 +3728,7 @@ snapshots: '@secretlint/resolver': 10.2.2 '@secretlint/types': 10.2.2 ajv: 8.17.1 - debug: 4.4.1 + debug: 4.4.3 rc-config-loader: 4.1.3 transitivePeerDependencies: - supports-color @@ -3741,7 +3737,7 @@ snapshots: dependencies: '@secretlint/profiler': 10.2.2 '@secretlint/types': 10.2.2 - debug: 4.4.1 + debug: 4.4.3 structured-source: 4.0.0 transitivePeerDependencies: - supports-color @@ -3754,7 +3750,7 @@ snapshots: '@textlint/module-interop': 15.2.2 '@textlint/types': 15.2.2 chalk: 5.6.2 - debug: 4.4.1 + debug: 4.4.3 pluralize: 8.0.0 strip-ansi: 7.1.2 table: 6.9.0 @@ -3770,7 +3766,7 @@ snapshots: '@secretlint/profiler': 10.2.2 '@secretlint/source-creator': 10.2.2 '@secretlint/types': 10.2.2 - debug: 4.4.1 + debug: 4.4.3 p-map: 7.0.3 transitivePeerDependencies: - supports-color @@ -3808,7 +3804,7 @@ snapshots: '@textlint/resolver': 15.2.2 '@textlint/types': 15.2.2 chalk: 4.1.2 - debug: 4.4.1 + debug: 4.4.3 js-yaml: 3.14.1 lodash: 4.17.21 pluralize: 2.0.0 @@ -3839,9 +3835,9 @@ snapshots: '@types/json5@0.0.29': {} - '@types/node@24.3.3': + '@types/node@24.5.1': dependencies: - undici-types: 7.10.0 + undici-types: 7.12.0 '@types/normalize-package-data@2.4.4': {} @@ -3849,18 +3845,14 @@ snapshots: '@types/vscode@1.61.0': {} - '@types/ws@8.18.1': - dependencies: - '@types/node': 24.3.3 - - '@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/type-utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.43.0 + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.0 eslint: 9.35.0 graphemer: 1.4.0 ignore: 7.0.5 @@ -3870,57 +3862,57 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.43.0 - debug: 4.4.1 + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.0 + debug: 4.4.3 eslint: 9.35.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.43.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.44.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) - '@typescript-eslint/types': 8.43.0 - debug: 4.4.1 + '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + debug: 4.4.3 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.43.0': + '@typescript-eslint/scope-manager@8.44.0': dependencies: - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/visitor-keys': 8.44.0 - '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.44.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.43.0(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.44.0(eslint@9.35.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2) - debug: 4.4.1 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0)(typescript@5.9.2) + debug: 4.4.3 eslint: 9.35.0 ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.43.0': {} + '@typescript-eslint/types@8.44.0': {} - '@typescript-eslint/typescript-estree@8.43.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.44.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.43.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/visitor-keys': 8.43.0 - debug: 4.4.1 + '@typescript-eslint/project-service': 8.44.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/visitor-keys': 8.44.0 + debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -3930,20 +3922,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.43.0(eslint@9.35.0)(typescript@5.9.2)': + '@typescript-eslint/utils@8.44.0(eslint@9.35.0)(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0) - '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/types': 8.43.0 - '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) eslint: 9.35.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.43.0': + '@typescript-eslint/visitor-keys@8.44.0': dependencies: - '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/types': 8.44.0 eslint-visitor-keys: 4.2.1 '@typespec/ts-http-runtime@0.3.1': @@ -4051,10 +4043,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - ansi-escapes@7.1.0: dependencies: environment: 1.1.0 @@ -4314,7 +4302,7 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.1: + debug@4.4.3: dependencies: ms: 2.1.3 @@ -4351,7 +4339,7 @@ snapshots: delayed-stream@1.0.0: {} - detect-libc@2.0.4: + detect-libc@2.1.0: optional: true doctrine@2.1.0: @@ -4496,34 +4484,34 @@ snapshots: es-toolkit@1.39.10: {} - esbuild@0.25.9: + esbuild@0.25.10: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.9 - '@esbuild/android-arm': 0.25.9 - '@esbuild/android-arm64': 0.25.9 - '@esbuild/android-x64': 0.25.9 - '@esbuild/darwin-arm64': 0.25.9 - '@esbuild/darwin-x64': 0.25.9 - '@esbuild/freebsd-arm64': 0.25.9 - '@esbuild/freebsd-x64': 0.25.9 - '@esbuild/linux-arm': 0.25.9 - '@esbuild/linux-arm64': 0.25.9 - '@esbuild/linux-ia32': 0.25.9 - '@esbuild/linux-loong64': 0.25.9 - '@esbuild/linux-mips64el': 0.25.9 - '@esbuild/linux-ppc64': 0.25.9 - '@esbuild/linux-riscv64': 0.25.9 - '@esbuild/linux-s390x': 0.25.9 - '@esbuild/linux-x64': 0.25.9 - '@esbuild/netbsd-arm64': 0.25.9 - '@esbuild/netbsd-x64': 0.25.9 - '@esbuild/openbsd-arm64': 0.25.9 - '@esbuild/openbsd-x64': 0.25.9 - '@esbuild/openharmony-arm64': 0.25.9 - '@esbuild/sunos-x64': 0.25.9 - '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 escape-html@1.0.3: {} @@ -4541,11 +4529,11 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0)(typescript@5.9.2) eslint: 9.35.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: @@ -4557,7 +4545,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint@9.35.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -4568,7 +4556,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.35.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4580,7 +4568,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.43.0(eslint@9.35.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0)(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -4629,7 +4617,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -4748,7 +4736,7 @@ snapshots: fs-constants@1.0.0: optional: true - fs-extra@11.3.1: + fs-extra@11.3.2: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 @@ -4873,14 +4861,14 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -4888,6 +4876,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: optional: true @@ -5252,7 +5244,7 @@ snapshots: node-sarif-builder@3.2.0: dependencies: '@types/sarif': 2.1.7 - fs-extra: 11.3.1 + fs-extra: 11.3.2 normalize-package-data@6.0.2: dependencies: @@ -5431,7 +5423,7 @@ snapshots: prebuild-install@7.1.3: dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.0 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 @@ -5441,7 +5433,7 @@ snapshots: pump: 3.0.3 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.3 + tar-fs: 2.1.4 tunnel-agent: 0.6.0 optional: true @@ -5467,7 +5459,7 @@ snapshots: rc-config-loader@4.1.3: dependencies: - debug: 4.4.1 + debug: 4.4.3 js-yaml: 4.1.0 json5: 2.2.3 require-from-string: 2.0.2 @@ -5577,7 +5569,7 @@ snapshots: '@secretlint/formatter': 10.2.2 '@secretlint/node': 10.2.2 '@secretlint/profiler': 10.2.2 - debug: 4.4.1 + debug: 4.4.3 globby: 14.1.0 read-pkg: 9.0.1 transitivePeerDependencies: @@ -5768,7 +5760,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tar-fs@2.1.3: + tar-fs@2.1.4: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 @@ -5828,8 +5820,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@0.21.3: {} - type-fest@4.41.0: {} typed-array-buffer@1.0.3: @@ -5884,7 +5874,7 @@ snapshots: underscore@1.13.7: {} - undici-types@7.10.0: {} + undici-types@7.12.0: {} undici@7.16.0: {} @@ -5992,10 +5982,6 @@ snapshots: wrappy@1.0.2: optional: true - ws@8.18.3(bufferutil@4.0.9): - optionalDependencies: - bufferutil: 4.0.9 - wsl-utils@0.1.0: dependencies: is-wsl: 3.1.0 diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts index 4cf420d6..eace1641 100644 --- a/extensions/VSCode/src/extension.ts +++ b/extensions/VSCode/src/extension.ts @@ -30,7 +30,6 @@ import process from "node:process"; // ### Third-party packages import escape from "escape-html"; import vscode, { commands, Range, TextDocument, TextEditor } from "vscode"; -import { WebSocket } from "ws"; import { CodeChatEditorServer, initServer } from "./index"; // ### Local packages @@ -58,7 +57,7 @@ const DEBUG_ENABLED = false; const is_windows = process.platform === "win32"; // These globals are truly global: only one is needed for this entire plugin. -let websocket: WebSocket | undefined; +// // Where the webclient resides: `html` for a webview panel embedded in VSCode; // `browser` to use an external browser. let codechat_client_location: CodeChatEditorClientLocation = @@ -104,7 +103,7 @@ let quiet_next_error = false; let is_dirty = false; // An object to start/stop the CodeChat Editor Server. -let codeChatEditorServer: CodeChatEditorServer; +let codeChatEditorServer: CodeChatEditorServer | undefined; // Before using `CodeChatEditorServer`, we must initialize it. { const ext = vscode.extensions.getExtension( @@ -283,323 +282,262 @@ export const activate = (context: vscode.ExtensionContext) => { } // Start the server. - try { - console_log("CodeChat Editor extension: starting server."); - codeChatEditorServer = new CodeChatEditorServer(get_port()); - codeChatEditorServer.startServer(); - } catch (err) { - assert(err instanceof Error); - show_error(err.message); - return; + console_log("CodeChat Editor extension: starting server."); + codeChatEditorServer = new CodeChatEditorServer(get_port()); + + console_log("CodeChat Editor extension: connected to server."); + await send_message({ + Opened: { + VSCode: + codechat_client_location === + CodeChatEditorClientLocation.html, + }, + }); + // For the external browser, we can immediately send the + // `CurrentFile` message. For the WebView, we must first wait to + // receive the HTML for the WebView (the `ClientHtml` message). + if ( + codechat_client_location === + CodeChatEditorClientLocation.browser + ) { + send_update(false); } - if (websocket === undefined) { + while (codeChatEditorServer) { + const message_raw = await codeChatEditorServer.getMessage(); + if (message_raw === null) { + console_log("CodeChat Editor extension: queue closed."); + break; + } + // Parse the data into a message. + const { id, message } = JSON.parse( + message_raw, + ) as EditorMessage; console_log( - "CodeChat Editor extension: opening websocket.", + `CodeChat Editor extension: Received data id = ${id}, message = ${format_struct( + message, + )}.`, ); - - // Connect to the CodeChat Editor Server. - websocket = new WebSocket( - `ws://localhost:${get_port()}/vsc/ws-ide/${Math.random()}`, - ); - - let was_error: boolean = false; - - websocket.on("error", (err: ErrorEvent) => { - was_error = true; - show_error( - `Error communicating with the CodeChat Editor Server: ${err.message}. Re-run the CodeChat Editor extension to restart it.`, - ); - // The close event will be [emitted - // next](https://nodejs.org/api/net.html#net_event_error_1); - // that will handle cleanup. - }); - - websocket.on("close", (hadError: CloseEvent) => { - console_log( - "CodeChat Editor extension: closing websocket connection.", - ); - // If there was an error, the event handler above - // already provided the message. Note: the [parameter - // hadError](https://nodejs.org/api/net.html#net_event_close_1) - // only applies to transmission errors, not to any other - // errors which trigger the error callback. Therefore, - // I'm using the `was_error` flag instead to catch - // non-transmission errors. - if (!was_error && hadError) { - show_error( - "The connection to the CodeChat Editor Server was closed due to a transmission error. Re-run the CodeChat Editor extension to restart it.", - ); - } - websocket = undefined; - idle_timer = undefined; - }); - - websocket.on("open", () => { - console_log( - "CodeChat Editor extension: connected to server.", - ); - assert(websocket !== undefined); - send_message({ - Opened: { - VSCode: - codechat_client_location === - CodeChatEditorClientLocation.html, - }, - }); - // For the external browser, we can immediately send the - // `CurrentFile` message. For the WebView, we must first - // wait to receive the HTML for the WebView (the - // `ClientHtml` message). - if ( - codechat_client_location === - CodeChatEditorClientLocation.browser - ) { - send_update(false); - } - }); - - websocket.on("message", (data) => { - // Parse the data into a message. - const { id, message } = JSON.parse( - data.toString(), - ) as EditorMessage; - console_log( - `CodeChat Editor extension: Received data id = ${id}, message = ${format_struct( - message, - )}.`, - ); - assert(id !== undefined); - assert(message !== undefined); - const keys = Object.keys(message); - assert(keys.length === 1); - const key = keys[0]; - const value = Object.values(message)[0]; - - // Process this message. - switch (key) { - case "Update": { - const current_update = - value as UpdateMessageContents; - const doc = get_document( - current_update.file_path, + assert(id !== undefined); + assert(message !== undefined); + if (message === "Closed") { + break; + } + const keys = Object.keys(message); + assert(keys.length === 1); + const key = keys[0]; + const value = Object.values(message)[0]; + + // Process this message. + switch (key) { + case "Update": { + const current_update = + value as UpdateMessageContents; + const doc = get_document(current_update.file_path); + if (doc === undefined) { + sendResult( + id, + `No open document for ${current_update.file_path}`, ); - if (doc === undefined) { - send_result(id, { - Err: `No open document for ${current_update.file_path}`, - }); - break; - } - if (current_update.contents !== undefined) { - const source = - current_update.contents.source; - // Is this plain text, or a diff? This will - // produce a change event, which we'll - // ignore. - ignore_text_document_change = true; - // Use a workspace edit, since calls to - // `TextEditor.edit` must be made to the - // active editor only. - const wse = new vscode.WorkspaceEdit(); - if ("Plain" in source) { - wse.replace( - doc.uri, - doc.validateRange( - new vscode.Range( - 0, - 0, - doc.lineCount, - 0, - ), + break; + } + if (current_update.contents !== undefined) { + const source = current_update.contents.source; + // Is this plain text, or a diff? This will + // produce a change event, which we'll ignore. + ignore_text_document_change = true; + // Use a workspace edit, since calls to + // `TextEditor.edit` must be made to the active + // editor only. + const wse = new vscode.WorkspaceEdit(); + if ("Plain" in source) { + wse.replace( + doc.uri, + doc.validateRange( + new vscode.Range( + 0, + 0, + doc.lineCount, + 0, ), - source.Plain.doc, - ); - } else { - assert("Diff" in source); - const diffs = source.Diff.doc; - for (const diff of diffs) { - // Convert from character offsets from the - // beginning of the document to a - // `Position` (line, then offset on that - // line) needed by VSCode. - const from = doc.positionAt( - diff.from, + ), + source.Plain.doc, + ); + } else { + assert("Diff" in source); + const diffs = source.Diff.doc; + for (const diff of diffs) { + // Convert from character offsets from the + // beginning of the document to a + // `Position` (line, then offset on that + // line) needed by VSCode. + const from = doc.positionAt(diff.from); + if (diff.to === undefined) { + // This is an insert. + wse.insert( + doc.uri, + from, + diff.insert, + ); + } else { + // This is a replace or delete. + const to = doc.positionAt(diff.to); + wse.replace( + doc.uri, + new Range(from, to), + diff.insert, ); - if (diff.to === undefined) { - // This is an insert. - wse.insert( - doc.uri, - from, - diff.insert, - ); - } else { - // This is a replace or delete. - const to = doc.positionAt( - diff.to, - ); - wse.replace( - doc.uri, - new Range(from, to), - diff.insert, - ); - } } } - vscode.workspace - .applyEdit(wse) - .then( - () => - (ignore_text_document_change = false), - ); } - // Update the cursor position if provided. - let line = current_update.cursor_position; - if (line !== undefined) { - const editor = get_text_editor(doc); - if (editor) { - ignore_selection_change = true; - // The VSCode line is zero-based; the - // CodeMirror line is one-based. - line -= 1; - console_log(`Moving to line ${line}.`); - const position = new vscode.Position( - line, - line, - ); - editor.selections = [ - new vscode.Selection( - position, - position, - ), - ]; - editor.revealRange( - new vscode.Range( - position, - position, - ), - ); - } + vscode.workspace + .applyEdit(wse) + .then( + () => + (ignore_text_document_change = false), + ); + } + // Update the cursor position if provided. + let line = current_update.cursor_position; + if (line !== undefined) { + const editor = get_text_editor(doc); + if (editor) { + ignore_selection_change = true; + // The VSCode line is zero-based; the + // CodeMirror line is one-based. + line -= 1; + console_log(`Moving to line ${line}.`); + const position = new vscode.Position( + line, + line, + ); + editor.selections = [ + new vscode.Selection( + position, + position, + ), + ]; + editor.revealRange( + new vscode.Range(position, position), + ); } - send_result(id); - break; } + sendResult(id); + break; + } - case "CurrentFile": { - const current_file = value[0] as string; - const is_text = value[1] as boolean | undefined; - if (is_text) { - vscode.workspace - .openTextDocument(current_file) - .then( - (document) => { - ignore_active_editor_change = true; - vscode.window.showTextDocument( - document, + case "CurrentFile": { + const current_file = value[0] as string; + const is_text = value[1] as boolean | undefined; + if (is_text) { + vscode.workspace + .openTextDocument(current_file) + .then( + (document) => { + ignore_active_editor_change = true; + vscode.window.showTextDocument( + document, + current_editor?.viewColumn, + ); + sendResult(id); + }, + (reason) => + sendResult( + id, + `Error: unable to open file ${current_file}: ${reason}`, + ), + ); + } else { + // TODO: open using a custom document editor. + // See + // [openCustomDocument](https://code.visualstudio.com/api/references/vscode-api#CustomEditorProvider.openCustomDocument), + // which can evidently be called + // [indirectly](https://stackoverflow.com/a/65101181/4374935). + // See also [Built-in + // Commands](https://code.visualstudio.com/api/references/commands). + // For now, simply respond with an OK, since the + // following doesn't work. + if (false) { + commands + .executeCommand( + "vscode.open", + vscode.Uri.file(current_file), + { + viewColumn: current_editor?.viewColumn, - ); - send_result(id); }, + ) + .then( + () => sendResult(id), (reason) => - send_result(id, { - Err: `Error: unable to open file ${current_file}: ${reason}`, - }), + sendResult( + id, + `Error: unable to open file ${current_file}: ${reason}`, + ), ); - } else { - // TODO: open using a custom document - // editor. See - // [openCustomDocument](https://code.visualstudio.com/api/references/vscode-api#CustomEditorProvider.openCustomDocument), - // which can evidently be called - // [indirectly](https://stackoverflow.com/a/65101181/4374935). - // See also [Built-in - // Commands](https://code.visualstudio.com/api/references/commands). - // For now, simply respond with an OK, since - // the following doesn't work. - if (false) { - commands - .executeCommand( - "vscode.open", - vscode.Uri.file(current_file), - { - viewColumn: - current_editor?.viewColumn, - }, - ) - .then( - () => send_result(id), - (reason) => - send_result(id, { - Err: `Error: unable to open file ${current_file}: ${reason}`, - }), - ); - } - send_result(id); } - break; + sendResult(id); } + break; + } - case "Result": { - // Cancel the timer for this message and remove - // it from `pending_messages`. - const pending_message = pending_messages[id]; - if (pending_message !== undefined) { - const { timer_id, callback } = - pending_messages[id]; - clearTimeout(timer_id); - // eslint-disable-next-line - // n/no-callback-literal - callback(true); - delete pending_messages[id]; - } - - // Report if this was an error. - const result_contents = value as MessageResult; - if ("Err" in result_contents) { - show_error( - `Error in message ${id}: ${result_contents.Err}`, - ); - } - break; + case "Result": { + // Cancel the timer for this message and remove it + // from `pending_messages`. + const pending_message = pending_messages[id]; + if (pending_message !== undefined) { + const { timer_id, callback } = + pending_messages[id]; + clearTimeout(timer_id); + // eslint-disable-next-line + // n/no-callback-literal + callback(true); + delete pending_messages[id]; } - case "LoadFile": { - const load_file = value as string; - // Look through all open documents to see if we - // have the requested file. - const doc = get_document(load_file); - const load_file_result = - doc === undefined ? null : doc.getText(); - send_result(id, { - Ok: { - LoadFile: load_file_result, - }, - }); - break; + // Report if this was an error. + const result_contents = value as MessageResult; + if ("Err" in result_contents) { + show_error( + `Error in message ${id}: ${result_contents.Err}`, + ); } + break; + } - case "ClientHtml": { - const client_html = value as string; - assert(webview_panel !== undefined); - webview_panel.webview.html = client_html; - send_result(id); - // Now that the Client is loaded, send the - // editor's current file to the server. - send_update(false); - break; - } + case "LoadFile": { + const load_file = value as string; + // Look through all open documents to see if we have + // the requested file. + const doc = get_document(load_file); + const load_file_result = + doc === undefined ? null : doc.getText(); + codeChatEditorServer.sendResultLoadfile( + id, + load_file_result, + ); + break; + } - default: - console.error( - `Unhandled message ${key}(${format_struct( - value, - )}`, - ); - break; + case "ClientHtml": { + const client_html = value as string; + assert(webview_panel !== undefined); + webview_panel.webview.html = client_html; + sendResult(id); + // Now that the Client is loaded, send the editor's + // current file to the server. + send_update(false); + break; } - }); - } else { - console_log( - "CodeChat Editor extension: connection already pending, so a new client wasn't created.", - ); + + default: + console.error( + `Unhandled message ${key}(${format_struct( + value, + )}`, + ); + break; + } } }, ), @@ -618,7 +556,7 @@ export const deactivate = async () => { // -------------------- // // Send a message expecting a result to the server. -const send_message = ( +const send_message = async ( message: EditorMessageContents, callback: (succeeded: boolean) => void = (_) => 0, ) => { @@ -628,11 +566,15 @@ const send_message = ( id, message, }; - assert(websocket); + assert(codeChatEditorServer); console_log( `CodeChat Editor extension: sending message ${format_struct(jm)}.`, ); - websocket.send(JSON.stringify(jm)); + try { + await codeChatEditorServer.sendMessage(JSON.stringify(jm)); + } catch (e) { + console.error(`send_message: ${e}`); + } pending_messages[id] = { timer_id: setTimeout(report_server_timeout, RESPONSE_TIMEOUT_MS, id), callback, @@ -659,22 +601,12 @@ const report_server_timeout = (message_id: number) => { }; // Send a result (a response to a message from the server) back to the server. -const send_result = (id: number, result: MessageResult = { Ok: "Void" }) => { - // We can't simply call `send_message` because that function expects a - // result message back from the server. - const jm: EditorMessage = { - id, - message: { - Result: result, - }, - }; - assert(websocket); +const sendResult = (id: number, result: string | null = null) => { + assert(codeChatEditorServer); console_log( - `CodeChat Editor extension: sending result ${JSON.stringify( - jm, - ).substring(0, MAX_MESSAGE_LENGTH)}.`, + `CodeChat Editor extension: sending result ${format_struct(result)}.`, ); - websocket.send(JSON.stringify(jm)); + codeChatEditorServer.sendResult(id, result); }; // This is called after an event such as an edit, when the CodeChat panel @@ -688,7 +620,7 @@ const send_update = (this_is_dirty: boolean) => { clearTimeout(idle_timer); } // ... schedule a render after 300 ms. - idle_timer = setTimeout(() => { + idle_timer = setTimeout(async () => { if (can_render()) { const ate = vscode.window.activeTextEditor!; if (ate !== current_editor) { @@ -696,7 +628,7 @@ const send_update = (this_is_dirty: boolean) => { // the user to rapidly cycle through several editors without // needing to reload the Client with each cycle. current_editor = ate; - send_message({ + await send_message({ CurrentFile: [ate!.document.fileName, null], }); // Since we just requested a new file, the contents are @@ -731,7 +663,7 @@ const send_update = (this_is_dirty: boolean) => { }; is_dirty = false; } - send_message({ + await send_message({ Update, }); } @@ -743,10 +675,10 @@ const send_update = (this_is_dirty: boolean) => { // well. const stop_client = async () => { console_log("CodeChat Editor extension: stopping client."); - if (websocket !== undefined) { + if (codeChatEditorServer !== undefined) { console_log("CodeChat Editor extension: ending connection."); - websocket?.close(); - websocket = undefined; + await codeChatEditorServer.stopServer(); + codeChatEditorServer = undefined; } // Shut the timer down after the client is undefined, to ensure it can't be @@ -756,15 +688,6 @@ const stop_client = async () => { idle_timer = undefined; } - // Shut down the server. - try { - await codeChatEditorServer.stopServer(); - } catch (err) { - assert(err instanceof Error); - console.error( - `CodeChat Editor Client: error on server shutdown - ${err.message}`, - ); - } current_editor = undefined; }; @@ -797,7 +720,7 @@ const show_error = (message: string) => { const can_render = () => { return ( vscode.window.activeTextEditor !== undefined && - websocket !== undefined && + codeChatEditorServer !== undefined && (codechat_client_location === CodeChatEditorClientLocation.browser || webview_panel !== undefined) ); diff --git a/extensions/VSCode/src/lib.rs b/extensions/VSCode/src/lib.rs index 95f6d653..e32ae908 100644 --- a/extensions/VSCode/src/lib.rs +++ b/extensions/VSCode/src/lib.rs @@ -21,18 +21,30 @@ // ------- // // ### Standard library -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use std::ops::DerefMut; -use std::path::PathBuf; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + path::PathBuf, + sync::Arc, + thread, +}; // ### Third-party use actix_server::{Server, ServerHandle}; -use code_chat_editor::webserver::{self, WebAppState, setup_server}; use log::LevelFilter; use napi::{Error, Status}; use napi_derive::napi; -use std::sync::Arc; -use tokio::sync::Mutex; +use rand::random; +use tokio::sync::{ + Mutex, + mpsc::{Receiver, Sender}, +}; + +// ### Local +use code_chat_editor::{ + ide::vscode::{connection_id_raw_to_str, vscode_ide_core}, + translation::{CreatedTranslationQueues, create_translation_queues}, + webserver::{self, EditorMessage, ResultOkTypes, WebAppState, setup_server}, +}; // Code // ---- @@ -40,7 +52,11 @@ use tokio::sync::Mutex; // This must be called only once, before constructing the `CodeChatEditorServer` // class. #[napi] -pub fn init_server(extension_base_path: String) -> Result<(), Error> { +pub fn init_server( + // The path to the location of this extension's files. This is used to + // locate static files for the webserver, etc. + extension_base_path: String, +) -> Result<(), Error> { webserver::init_server( Some(&PathBuf::from(extension_base_path)), LevelFilter::Debug, @@ -48,12 +64,26 @@ pub fn init_server(extension_base_path: String) -> Result<(), Error> { .map_err(|err| Error::new(Status::GenericFailure, err.to_string())) } -// Provide a class to start and stop the server. +// Using this macro is critical -- otherwise, the Actix system doesn't get +// correctly initialized, which makes calls to `actix_rt::spawn` fail. +#[actix_web::main] +async fn start_server( + connection_id_raw: String, + app_state_task: WebAppState, + translation_queues: CreatedTranslationQueues, + server: Server, +) -> std::io::Result<()> { + vscode_ide_core(connection_id_raw, app_state_task, translation_queues); + server.await +} + +// Provide a class to start and stop the server. All its fields are opaque, +// since only Rust should use them. #[napi] struct CodeChatEditorServer { - server: Arc>, server_handle: ServerHandle, - _app_state: WebAppState, + from_ide_tx: Sender, + to_ide_rx: Arc>>, } #[napi] @@ -61,25 +91,137 @@ struct CodeChatEditorServer { #[allow(dead_code)] impl CodeChatEditorServer { #[napi(constructor)] - pub fn new(port: u16) -> Result { - let (server, _app_state) = setup_server( + pub fn new( + // The port the webserver should use for the Client. + port: u16, + ) -> Result { + // Start the server. + let (server, app_state) = setup_server( &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port), None, + )?; + let server_handle = server.handle(); + + // Start a thread to translate between this IDE and a Client. + let connection_id_raw = random::().to_string(); + let connection_id = connection_id_raw_to_str(&connection_id_raw); + let app_state_task = app_state.clone(); + let translation_queues = create_translation_queues( + connection_id_raw_to_str(connection_id_raw.as_str()), + &app_state, ) .map_err(|err| Error::new(Status::GenericFailure, err.to_string()))?; + thread::spawn(move || { + start_server( + connection_id_raw, + app_state_task, + translation_queues, + server, + ) + }); + + // Get the IDE queues created by this task for use with the `get`/`put` + // methods. + let websocket_queues = app_state + .ide_queues + .lock() + .map_err(|e| std::io::Error::other(format!("Unable to lock queue: {e}")))? + .remove(&connection_id) + .ok_or_else(|| { + std::io::Error::other(format!("Unable to find queue named {connection_id}")) + })?; + Ok(CodeChatEditorServer { - server_handle: server.handle(), - server: Arc::new(Mutex::new(server)), - _app_state, + server_handle, + from_ide_tx: websocket_queues.from_websocket_tx, + to_ide_rx: Arc::new(Mutex::new(websocket_queues.to_websocket_rx)), }) } + // This returns an error if the conversion to JSON fails, `None` if the + // queue is closed, or a JSON-encoded string containing the message + // otherwise. + #[napi] + pub async fn get_message(&self) -> Result, Error> { + match self.to_ide_rx.lock().await.recv().await { + Some(editor_message) => match serde_json::to_string(&editor_message) { + Ok(v) => Ok(Some(v)), + Err(err) => Err(Error::new(Status::GenericFailure, err.to_string())), + }, + None => Ok(None), + } + } + + // TODO: wait for a response; produce an error if no response after a timeout. + // Automatically generate an ID for each message. + async fn send_editor_message(&self, editor_message: EditorMessage) -> std::io::Result<()> { + self.from_ide_tx + .send(editor_message) + .await + .map_err(|e| std::io::Error::other(e.to_string())) + } + + // Given a JSON-encoded message, send it to the Client. This returns an + // error if string's contents can't be JSON decoded to an `EditorMessage`. + #[napi] + pub async fn send_message( + &self, + // The `EditorMessage` to send, as a JSON-encoded string. + message: String, + ) -> std::io::Result<()> { + let editor_message = serde_json::from_str::(&message)?; + self.send_editor_message(editor_message).await + } + + // TODO: not used yet; need to integrate in auto-result tracking, auto ID + // generation. + #[napi] + pub async fn send_message_opened(&self, id: f64, hosted_in_ide: bool) -> std::io::Result<()> { + let editor_message = EditorMessage { + id, + message: webserver::EditorMessageContents::Opened(webserver::IdeType::VSCode( + hosted_in_ide, + )), + }; + self.send_editor_message(editor_message).await + } + + // Send either an Ok(Void) or an Error result to the Client. + #[napi] + pub async fn send_result( + &self, + id: f64, + message_result: Option, + ) -> std::io::Result<()> { + let editor_message = EditorMessage { + id, + message: webserver::EditorMessageContents::Result( + if let Some(message_result) = message_result { + Err(message_result) + } else { + Ok(ResultOkTypes::Void) + }, + ), + }; + self.send_editor_message(editor_message).await + } + #[napi] - pub async fn start_server(&self) -> std::io::Result<()> { - let mut server_guard = self.server.lock().await; - server_guard.deref_mut().await + pub async fn send_result_loadfile( + &self, + id: f64, + load_file: Option, + ) -> std::io::Result<()> { + let editor_message = EditorMessage { + id, + message: webserver::EditorMessageContents::Result(Ok(ResultOkTypes::LoadFile( + load_file, + ))), + }; + self.send_editor_message(editor_message).await } + // This returns after the server shuts down. #[napi] pub async fn stop_server(&self) { self.server_handle.stop(true).await; diff --git a/server/Cargo.lock b/server/Cargo.lock index 293f5d2d..2fafadc7 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-files" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22c8b5536deb14cd9c3e505bd0e3366e1a12383b659c92f2b4fa4d323d583599" +checksum = "6c0d87f10d70e2948ad40e8edea79c8e77c6c66e0250a4c1f09b690465199576" dependencies = [ "actix-http", "actix-service", @@ -499,9 +499,9 @@ dependencies = [ [[package]] name = "bytestring" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" dependencies = [ "bytes", ] @@ -585,7 +585,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "codechat-editor-server" -version = "0.1.35" +version = "0.1.36" dependencies = [ "actix-files", "actix-http", @@ -996,7 +996,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.5+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -1283,9 +1283,9 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.11.1" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" dependencies = [ "equivalent", "hashbrown", @@ -1374,9 +1374,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -1422,9 +1422,9 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.9.4", "libc", @@ -2070,10 +2070,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ + "serde_core", "serde_derive", ] @@ -2087,11 +2088,20 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", @@ -2100,14 +2110,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2714,18 +2725,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.5+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ "wasip2", ] [[package]] name = "wasip2" -version = "1.0.0+wasi-0.2.4" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] @@ -2738,9 +2749,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -2751,9 +2762,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -2765,9 +2776,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2775,9 +2786,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -2788,18 +2799,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", @@ -3197,9 +3208,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" diff --git a/server/Cargo.toml b/server/Cargo.toml index 6f0b473f..d429ee81 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -32,7 +32,7 @@ license = "GPL-3.0-only" name = "codechat-editor-server" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.35" +version = "0.1.36" # This library allows other packages to use core CodeChat Editor features. [lib] diff --git a/server/src/ide/filewatcher.rs b/server/src/ide/filewatcher.rs index d12878a9..4a8a34ca 100644 --- a/server/src/ide/filewatcher.rs +++ b/server/src/ide/filewatcher.rs @@ -353,7 +353,7 @@ async fn processing_task( let connection_id = format!("{FW}{connection_id_raw}"); let created_translation_queues_result = - create_translation_queues(connection_id.clone(), app_state.clone()); + create_translation_queues(connection_id.clone(), &app_state); let (from_ide_rx, to_ide_tx, from_client_rx, to_client_tx) = match created_translation_queues_result { Err(err) => { @@ -440,21 +440,18 @@ async fn processing_task( // Now that the filewatcher is started, start the translation task then // proceed to the filewatcher main loop. - actix_rt::spawn(async move { - translation_task( - FW.to_string(), - connection_id_raw_task, - FILEWATCHER_PATH_PREFIX, - app_state, - shutdown_only, - false, - to_ide_tx, - from_ide_rx, - to_client_tx, - from_client_rx, - ) - .await; - }); + actix_rt::spawn(translation_task( + FW.to_string(), + connection_id_raw_task, + FILEWATCHER_PATH_PREFIX, + app_state, + shutdown_only, + false, + to_ide_tx, + from_ide_rx, + to_client_tx, + from_client_rx, + )); let mut is_closed = false; 'task: loop { @@ -654,7 +651,8 @@ async fn processing_task( } EditorMessageContents::LoadFile(_) => { - // We never have the requested file loaded in this "IDE". Intead, it's always on disk. + // We never have the requested file loaded in this + // "IDE". Intead, it's always on disk. send_response(&from_ide_tx, m.id, Ok(ResultOkTypes::LoadFile(None))).await; } @@ -706,7 +704,6 @@ pub async fn filewatcher_websocket( body, app_state.client_queues.clone(), ) - .await } /// Return a unique ID for an IDE websocket connection. @@ -857,9 +854,9 @@ mod tests { let url_path = url_path.canonicalize().unwrap(); assert_eq!(url_path, test_path); - // 2. After fetching the file, we should get an update. The Server sends - // a `LoadFile` to the IDE using message id 4; therefore, the `Update` - // is ID 7, and the next message is ID 10. + // 2. After fetching the file, we should get an update. The Server + // sends a `LoadFile` to the IDE using message id 4; therefore, the + // `Update` is ID 7, and the next message is ID 10. // // Message ids: IDE - 6, Server - 4->10, Client - 2. let uri = format!( @@ -891,8 +888,8 @@ mod tests { let from_client_tx = wq.from_websocket_tx; let mut to_client_rx = wq.to_websocket_rx; - // 1. The initial web request for the Client framework produces a - // `CurrentFile`. + // 1. The initial web request for the Client framework produces a + // `CurrentFile`. // // Message ids: IDE - 3->6, Server - 4, Client - 2. let (id, (..)) = get_message_as!( @@ -904,9 +901,9 @@ mod tests { assert_eq!(id, 3.0); send_response(&from_client_tx, id, Ok(ResultOkTypes::Void)).await; - // 2. After fetching the file, we should get an update. The Server sends - // a `LoadFile` to the IDE using message id 4; therefore, the `Update` - // is ID 7, and the next message is ID 10. + // 2. After fetching the file, we should get an update. The Server + // sends a `LoadFile` to the IDE using message id 4; therefore, the + // `Update` is ID 7, and the next message is ID 10. // // Message ids: IDE - 6, Server - 4->10, Client - 2. let mut file_path = test_dir.clone(); @@ -926,7 +923,7 @@ mod tests { assert_eq!(id, 7.0); send_response(&from_client_tx, id, Ok(ResultOkTypes::Void)).await; - // 3. Send an update message with no contents. + // 3. Send an update message with no contents. // // Message ids: IDE - 6, Server - 10, Client - 2->5. from_client_tx diff --git a/server/src/ide/vscode.rs b/server/src/ide/vscode.rs index 4d5b240d..19f23259 100644 --- a/server/src/ide/vscode.rs +++ b/server/src/ide/vscode.rs @@ -40,7 +40,10 @@ use log::{debug, error}; // ### Local use crate::{ queue_send, - translation::{CreateTranslationQueuesError, create_translation_queues, translation_task}, + translation::{ + CreateTranslationQueuesError, CreatedTranslationQueues, create_translation_queues, + translation_task, + }, webserver::{ EditorMessage, EditorMessageContents, IdeType, ResultOkTypes, WebAppState, client_websocket, escape_html, filesystem_endpoint, get_client_framework, get_server_url, @@ -62,8 +65,11 @@ pub async fn vscode_ide_websocket( body: web::Payload, app_state: WebAppState, ) -> Result { - let connection_id_str = match vscode_ide_core(connection_id_raw, app_state.clone()).await { - Ok(s) => s, + let connection_id_raw = connection_id_raw.to_string(); + let connection_id = format!("{VSC}{connection_id_raw}"); + + let translation_queues = match create_translation_queues(connection_id.clone(), &app_state) { + Ok(tq) => tq, Err(err) => match err { CreateTranslationQueuesError::IdInUse(_) => { return Err(ErrorBadRequest(err.to_string())); @@ -74,42 +80,40 @@ pub async fn vscode_ide_websocket( req, body, app_state.ide_queues.clone(), - ) - .await; + ); } }, }; + vscode_ide_core(connection_id_raw, app_state.clone(), translation_queues); // Move data between the IDE and the processing task via queues. The // websocket connection between the client and the IDE will run in the // endpoint for that connection. - client_websocket(connection_id_str, req, body, app_state.ide_queues.clone()).await + client_websocket(connection_id, req, body, app_state.ide_queues.clone()) +} + +// Given a (random) connection ID produced by the IDE, return a string that +// gives a VSCode-specific ID. +pub fn connection_id_raw_to_str(connection_id_raw: &str) -> String { + format!("{VSC}{connection_id_raw}") } // Create queues, perform the IDE startup sequence, then enter a loop // translating between the IDE and Client. The caller must provide a task to // move data to/from the IDE queues. -pub async fn vscode_ide_core( - connection_id_raw: web::Path, +pub fn vscode_ide_core( + connection_id_raw: String, app_state: WebAppState, -) -> Result { - let connection_id_raw = connection_id_raw.to_string(); - let connection_id_str = format!("{VSC}{connection_id_raw}"); + translation_queues: CreatedTranslationQueues, +) { + let (mut from_ide_rx, to_ide_tx, from_client_rx, to_client_tx) = ( + translation_queues.from_ide_rx, + translation_queues.to_ide_tx, + translation_queues.from_client_rx, + translation_queues.to_client_tx, + ); - let created_translation_queues_result = - create_translation_queues(connection_id_str.clone(), app_state.clone()); - let (mut from_ide_rx, to_ide_tx, from_client_rx, to_client_tx) = - match created_translation_queues_result { - Err(err) => return Err(err), - Ok(tqr) => ( - tqr.from_ide_rx, - tqr.to_ide_tx, - tqr.from_client_rx, - tqr.to_client_tx, - ), - }; - - let app_state_task = app_state.clone(); actix_rt::spawn(async move { + let app_state_task = app_state.clone(); let mut shutdown_only = true; 'task: { // Get the first message sent by the IDE. @@ -252,8 +256,6 @@ pub async fn vscode_ide_core( ) .await; }); - - Ok(connection_id_str) } /// Serve the Client Framework. @@ -285,7 +287,6 @@ pub async fn vscode_client_websocket( body, app_state.client_queues.clone(), ) - .await } // Respond to requests for the filesystem. diff --git a/server/src/translation.rs b/server/src/translation.rs index 35107840..4e69b388 100644 --- a/server/src/translation.rs +++ b/server/src/translation.rs @@ -294,7 +294,7 @@ pub struct CreatedTranslationQueues { pub fn create_translation_queues( connection_id: String, - app_state: WebAppState, + app_state: &WebAppState, ) -> Result { // There are three cases for this `connection_id`: // @@ -391,606 +391,593 @@ pub async fn translation_task( mut from_client_rx: Receiver, ) { // Start the processing task. - actix_rt::spawn(async move { - let connection_id = format!("{connection_id_prefix}{connection_id_raw}"); - if !shutdown_only { - // Use a [labeled block - // expression](https://doc.rust-lang.org/reference/expressions/loop-expr.html#labelled-block-expressions) - // to provide a way to exit the current task. - 'task: { - let mut current_file = PathBuf::new(); - let mut load_file_requests: HashMap = - HashMap::new(); - debug!("VSCode processing task started."); - - // Create a queue for HTTP requests fo communicate with this - // task. - let (from_http_tx, mut from_http_rx) = mpsc::channel(10); - app_state_task - .processing_task_queue_tx - .lock() - .unwrap() - .insert(connection_id.to_string(), from_http_tx); - - // Leave space for a server message during the init phase. - let mut id: f64 = INITIAL_MESSAGE_ID + MESSAGE_ID_INCREMENT; - // The source code, provided by the IDE. It will use whatever - // the IDE provides for EOLs, which is stored in `eol` below. - let mut source_code = String::new(); - let mut code_mirror_doc = String::new(); - // The initial state will be overwritten by the first `Update` - // or `LoadFile`, so this value doesn't matter. - let mut eol = EolType::Lf; - // Some means this contains valid HTML; None means don't use it - // (since it would have contained Markdown). - let mut code_mirror_doc_blocks = Some(Vec::new()); - let prefix_str = "/".to_string() + &prefix.join("/"); - // To send a diff from Server to Client or vice versa, we need - // to ensure they are in sync: - // - // 1. IDE update -> Server -> Client or Client update -> Server - // -> IDE: the Server and Client sync is pending. Client - // response -> Server -> IDE or IDE response -> Server -> - // Client: the Server and Client are synced. - // 2. IDE current file -> Server -> Client or Client current - // file -> Server -> IDE: Out of sync. - // - // It's only safe to send a diff when the most recent sync is - // achieved. So, we need to track the ID of the most recent IDE - // -> Client update or Client -> IDE update, if one is in - // flight. When complete, mark the connection as synchronized. - // Since all IDs are unique, we can use a single variable to - // store the ID. - // - // Currently, when the Client sends an update, mark the - // connection as out of sync, since the update contains not HTML - // in the doc blocks, but Markdown. When Turndown is moved from - // JavaScript to Rust, this can be changed, since both sides - // will have HTML in the doc blocks. - let mut sync_state = SyncState::OutOfSync; - loop { - select! { - // Look for messages from the IDE. - Some(ide_message) = from_ide_rx.recv() => { - debug!("Received IDE message id = {}, message = {}", ide_message.id, debug_shorten(&ide_message.message)); - match ide_message.message { - // Handle messages that the IDE must not send. - EditorMessageContents::Opened(_) | - EditorMessageContents::OpenUrl(_) | - EditorMessageContents::LoadFile(_) | - EditorMessageContents::ClientHtml(_) => { - let msg = "IDE must not send this message."; - error!("{msg}"); - send_response(&to_ide_tx, ide_message.id, Err(msg.to_string())).await; - }, - // Handle messages that are simply passed - // through. - EditorMessageContents::Closed | - EditorMessageContents::RequestClose => { + let connection_id = format!("{connection_id_prefix}{connection_id_raw}"); + if !shutdown_only { + // Use a [labeled block + // expression](https://doc.rust-lang.org/reference/expressions/loop-expr.html#labelled-block-expressions) + // to provide a way to exit the current task. + 'task: { + let mut current_file = PathBuf::new(); + let mut load_file_requests: HashMap = HashMap::new(); + debug!("VSCode processing task started."); + + // Create a queue for HTTP requests fo communicate with this task. + let (from_http_tx, mut from_http_rx) = mpsc::channel(10); + app_state_task + .processing_task_queue_tx + .lock() + .unwrap() + .insert(connection_id.to_string(), from_http_tx); + + // Leave space for a server message during the init phase. + let mut id: f64 = INITIAL_MESSAGE_ID + MESSAGE_ID_INCREMENT; + // The source code, provided by the IDE. It will use whatever the + // IDE provides for EOLs, which is stored in `eol` below. + let mut source_code = String::new(); + let mut code_mirror_doc = String::new(); + // The initial state will be overwritten by the first `Update` or + // `LoadFile`, so this value doesn't matter. + let mut eol = EolType::Lf; + // Some means this contains valid HTML; None means don't use it + // (since it would have contained Markdown). + let mut code_mirror_doc_blocks = Some(Vec::new()); + let prefix_str = "/".to_string() + &prefix.join("/"); + // To send a diff from Server to Client or vice versa, we need to + // ensure they are in sync: + // + // 1. IDE update -> Server -> Client or Client update -> Server -> + // IDE: the Server and Client sync is pending. Client response + // -> Server -> IDE or IDE response -> Server -> Client: the + // Server and Client are synced. + // 2. IDE current file -> Server -> Client or Client current file + // -> Server -> IDE: Out of sync. + // + // It's only safe to send a diff when the most recent sync is + // achieved. So, we need to track the ID of the most recent IDE -> + // Client update or Client -> IDE update, if one is in flight. When + // complete, mark the connection as synchronized. Since all IDs are + // unique, we can use a single variable to store the ID. + // + // Currently, when the Client sends an update, mark the connection + // as out of sync, since the update contains not HTML in the doc + // blocks, but Markdown. When Turndown is moved from JavaScript to + // Rust, this can be changed, since both sides will have HTML in the + // doc blocks. + let mut sync_state = SyncState::OutOfSync; + loop { + select! { + // Look for messages from the IDE. + Some(ide_message) = from_ide_rx.recv() => { + debug!("Received IDE message id = {}, message = {}", ide_message.id, debug_shorten(&ide_message.message)); + match ide_message.message { + // Handle messages that the IDE must not send. + EditorMessageContents::Opened(_) | + EditorMessageContents::OpenUrl(_) | + EditorMessageContents::LoadFile(_) | + EditorMessageContents::ClientHtml(_) => { + let msg = "IDE must not send this message."; + error!("{msg}"); + send_response(&to_ide_tx, ide_message.id, Err(msg.to_string())).await; + }, + + // Handle messages that are simply passed through. + EditorMessageContents::Closed | + EditorMessageContents::RequestClose => { + debug!("Forwarding it to the Client."); + queue_send!(to_client_tx.send(ide_message)) + }, + + // Pass a `Result` message to the Client, unless + // it's a `LoadFile` result. + EditorMessageContents::Result(ref result) => { + let is_loadfile = match result { + // See if this error was produced by a + // `LoadFile` result. + Err(_) => load_file_requests.contains_key(&ide_message.id.to_bits()), + Ok(result_ok) => match result_ok { + ResultOkTypes::Void => false, + ResultOkTypes::LoadFile(_) => true, + } + }; + // Pass the message to the client if this isn't + // a `LoadFile` result (the only type of result + // which the Server should handle). + if !is_loadfile { debug!("Forwarding it to the Client."); - queue_send!(to_client_tx.send(ide_message)) - }, - - // Pass a `Result` message to the Client, unless - // it's a `LoadFile` result. - EditorMessageContents::Result(ref result) => { - let is_loadfile = match result { - // See if this error was produced by a - // `LoadFile` result. - Err(_) => load_file_requests.contains_key(&ide_message.id.to_bits()), - Ok(result_ok) => match result_ok { - ResultOkTypes::Void => false, - ResultOkTypes::LoadFile(_) => true, - } - }; - // Pass the message to the client if this - // isn't a `LoadFile` result (the only type - // of result which the Server should - // handle). - if !is_loadfile { - debug!("Forwarding it to the Client."); - // If this was confirmation from the IDE - // that it received the latest update, then - // mark the IDE as synced. - if sync_state == SyncState::Pending(ide_message.id) { - sync_state = SyncState::InSync; - } - queue_send!(to_client_tx.send(ide_message)); - continue; + // If this was confirmation from the IDE + // that it received the latest update, then + // mark the IDE as synced. + if sync_state == SyncState::Pending(ide_message.id) { + sync_state = SyncState::InSync; } - // Ensure there's an HTTP request for this - // `LoadFile` result. - let Some(http_request) = load_file_requests.remove(&ide_message.id.to_bits()) else { - error!("Error: no HTTP request found for LoadFile result ID {}.", ide_message.id); - break 'task; - }; - - // Take ownership of the result after - // sending it above (which requires - // ownership). - let EditorMessageContents::Result(result) = ide_message.message else { - error!("{}", "Not a result."); - break; - }; - // Get the file contents from a `LoadFile` - // result; otherwise, this is None. - let file_contents_option = match result { - Err(err) => { - error!("{err}"); - None - }, - Ok(result_ok) => match result_ok { - ResultOkTypes::Void => panic!("LoadFile result should not be void."), - ResultOkTypes::LoadFile(file_contents) => file_contents, - } - }; - - // Process the file contents. Since VSCode - // doesn't have a PDF viewer, determine if - // this is a PDF file. (TODO: look at the - // magic number also -- "%PDF"). - let use_pdf_js = http_request.file_path.extension() == Some(OsStr::new("pdf")); - let ((simple_http_response, option_update), file_contents) = match file_contents_option { - Some(file_contents) => { - // If there are Windows newlines, replace - // with Unix; this is reversed when the - // file is sent back to the IDE. - (file_to_response(&http_request, ¤t_file, Some(&file_contents), use_pdf_js).await, file_contents) - }, - None => { - // The file wasn't available in the IDE. - // Look for it in the filesystem. - match File::open(&http_request.file_path).await { - Err(err) => ( - ( - SimpleHttpResponse::Err(SimpleHttpResponseError::Io(err)), - None, - ), - // There's no file, so return empty - // contents, which will be ignored. - "".to_string() + queue_send!(to_client_tx.send(ide_message)); + continue; + } + // Ensure there's an HTTP request for this + // `LoadFile` result. + let Some(http_request) = load_file_requests.remove(&ide_message.id.to_bits()) else { + error!("Error: no HTTP request found for LoadFile result ID {}.", ide_message.id); + break 'task; + }; + + // Take ownership of the result after sending it + // above (which requires ownership). + let EditorMessageContents::Result(result) = ide_message.message else { + error!("{}", "Not a result."); + break; + }; + // Get the file contents from a `LoadFile` + // result; otherwise, this is None. + let file_contents_option = match result { + Err(err) => { + error!("{err}"); + None + }, + Ok(result_ok) => match result_ok { + ResultOkTypes::Void => panic!("LoadFile result should not be void."), + ResultOkTypes::LoadFile(file_contents) => file_contents, + } + }; + + // Process the file contents. Since VSCode + // doesn't have a PDF viewer, determine if this + // is a PDF file. (TODO: look at the magic + // number also -- "%PDF"). + let use_pdf_js = http_request.file_path.extension() == Some(OsStr::new("pdf")); + let ((simple_http_response, option_update), file_contents) = match file_contents_option { + Some(file_contents) => { + // If there are Windows newlines, replace + // with Unix; this is reversed when the + // file is sent back to the IDE. + (file_to_response(&http_request, ¤t_file, Some(&file_contents), use_pdf_js).await, file_contents) + }, + None => { + // The file wasn't available in the IDE. + // Look for it in the filesystem. + match File::open(&http_request.file_path).await { + Err(err) => ( + ( + SimpleHttpResponse::Err(SimpleHttpResponseError::Io(err)), + None, ), - Ok(mut fc) => { - let option_file_contents = try_read_as_text(&mut fc).await; - ( - file_to_response( - &http_request, - ¤t_file, - option_file_contents.as_ref(), - use_pdf_js, - ) - .await, - // If the file is binary, return empty - // contents, which will be ignored. - option_file_contents.unwrap_or("".to_string()) + // There's no file, so return empty + // contents, which will be ignored. + "".to_string() + ), + Ok(mut fc) => { + let option_file_contents = try_read_as_text(&mut fc).await; + ( + file_to_response( + &http_request, + ¤t_file, + option_file_contents.as_ref(), + use_pdf_js, ) - } + .await, + // If the file is binary, return empty + // contents, which will be ignored. + option_file_contents.unwrap_or("".to_string()) + ) } } - }; - if let Some(update) = option_update { - let Some(ref tmp) = update.contents else { - error!("None."); - break; - }; - let CodeMirrorDiffable::Plain(ref plain) = tmp.source else { - error!("Not plain!"); - break; - }; - source_code = file_contents; - eol = find_eol_type(&source_code); - // We must clone here, since the original - // is placed in the TX queue. - code_mirror_doc = plain.doc.clone(); - code_mirror_doc_blocks = Some(plain.doc_blocks.clone()); - sync_state = SyncState::Pending(id); - - debug!("Sending Update to Client, id = {id}."); - queue_send!(to_client_tx.send(EditorMessage { - id, - message: EditorMessageContents::Update(update) - })); - id += MESSAGE_ID_INCREMENT; } - debug!("Sending HTTP response."); - oneshot_send!(http_request.response_queue.send(simple_http_response)); + }; + if let Some(update) = option_update { + let Some(ref tmp) = update.contents else { + error!("None."); + break; + }; + let CodeMirrorDiffable::Plain(ref plain) = tmp.source else { + error!("Not plain!"); + break; + }; + source_code = file_contents; + eol = find_eol_type(&source_code); + // We must clone here, since the original is + // placed in the TX queue. + code_mirror_doc = plain.doc.clone(); + code_mirror_doc_blocks = Some(plain.doc_blocks.clone()); + sync_state = SyncState::Pending(id); + + debug!("Sending Update to Client, id = {id}."); + queue_send!(to_client_tx.send(EditorMessage { + id, + message: EditorMessageContents::Update(update) + })); + id += MESSAGE_ID_INCREMENT; } + debug!("Sending HTTP response."); + oneshot_send!(http_request.response_queue.send(simple_http_response)); + } - // Handle the `Update` message. - EditorMessageContents::Update(update) => { - // Normalize the provided file name. - let result = match try_canonicalize(&update.file_path) { - Err(err) => Err(err), - Ok(clean_file_path) => { - match update.contents { - None => { - queue_send!(to_client_tx.send(EditorMessage { - id: ide_message.id, - message: EditorMessageContents::Update(UpdateMessageContents { - file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), - contents: None, - cursor_position: update.cursor_position, - scroll_position: update.scroll_position, - }), - })); - Ok(ResultOkTypes::Void) - } + // Handle the `Update` message. + EditorMessageContents::Update(update) => { + // Normalize the provided file name. + let result = match try_canonicalize(&update.file_path) { + Err(err) => Err(err), + Ok(clean_file_path) => { + match update.contents { + None => { + queue_send!(to_client_tx.send(EditorMessage { + id: ide_message.id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), + contents: None, + cursor_position: update.cursor_position, + scroll_position: update.scroll_position, + }), + })); + Ok(ResultOkTypes::Void) + } - Some(contents) => { - match contents.source { - CodeMirrorDiffable::Diff(_diff) => Err("TODO: support for updates with diffable sources.".to_string()), - CodeMirrorDiffable::Plain(code_mirror) => { - // If there are Windows newlines, replace - // with Unix; this is reversed when the - // file is sent back to the IDE. - eol = find_eol_type(&code_mirror.doc); - let doc_normalized_eols = code_mirror.doc.replace("\r\n", "\n"); - // Translate the file. - let (translation_results_string, _path_to_toc) = - source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, false); - match translation_results_string { - TranslationResultsString::CodeChat(ccfw) => { - // Send the new translated contents. - debug!("Sending translated contents to Client."); - let CodeMirrorDiffable::Plain(ref ccfw_source_plain) = ccfw.source else { - error!("{}", "Unexpected diff value."); - break; - }; - // Send a diff if possible (only when the - // Client's contents are synced with the - // IDE). - let contents = Some( - if let Some(cmdb) = code_mirror_doc_blocks && - sync_state == SyncState::InSync { - let doc_diff = diff_str(&code_mirror_doc, &ccfw_source_plain.doc); - let code_mirror_diff = diff_code_mirror_doc_blocks(&cmdb, &ccfw_source_plain.doc_blocks); - CodeChatForWeb { - // Clone needed here, so we can copy it - // later. - metadata: ccfw.metadata.clone(), - source: CodeMirrorDiffable::Diff(CodeMirrorDiff { - doc: doc_diff, - doc_blocks: code_mirror_diff - }) - } - } else { - // We must make a clone to put in the TX - // queue; this allows us to keep the - // original below to use with the next - // diff. - ccfw.clone() + Some(contents) => { + match contents.source { + CodeMirrorDiffable::Diff(_diff) => Err("TODO: support for updates with diffable sources.".to_string()), + CodeMirrorDiffable::Plain(code_mirror) => { + // If there are Windows newlines, replace + // with Unix; this is reversed when the + // file is sent back to the IDE. + eol = find_eol_type(&code_mirror.doc); + let doc_normalized_eols = code_mirror.doc.replace("\r\n", "\n"); + // Translate the file. + let (translation_results_string, _path_to_toc) = + source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, false); + match translation_results_string { + TranslationResultsString::CodeChat(ccfw) => { + // Send the new translated contents. + debug!("Sending translated contents to Client."); + let CodeMirrorDiffable::Plain(ref ccfw_source_plain) = ccfw.source else { + error!("{}", "Unexpected diff value."); + break; + }; + // Send a diff if possible (only when the + // Client's contents are synced with the + // IDE). + let contents = Some( + if let Some(cmdb) = code_mirror_doc_blocks && + sync_state == SyncState::InSync { + let doc_diff = diff_str(&code_mirror_doc, &ccfw_source_plain.doc); + let code_mirror_diff = diff_code_mirror_doc_blocks(&cmdb, &ccfw_source_plain.doc_blocks); + CodeChatForWeb { + // Clone needed here, so we can copy it + // later. + metadata: ccfw.metadata.clone(), + source: CodeMirrorDiffable::Diff(CodeMirrorDiff { + doc: doc_diff, + doc_blocks: code_mirror_diff + }) } - ); - queue_send!(to_client_tx.send(EditorMessage { - id: ide_message.id, - message: EditorMessageContents::Update(UpdateMessageContents { - file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), - contents, - cursor_position: update.cursor_position, - scroll_position: update.scroll_position, - }), - })); - // Update to the latest code after - // computing diffs. To avoid ownership - // problems, re-define `ccfw_source_plain`. - let CodeMirrorDiffable::Plain(ccfw_source_plain) = ccfw.source else { - error!("{}", "Unexpected diff value."); - break; - }; - source_code = code_mirror.doc; - code_mirror_doc = ccfw_source_plain.doc; - code_mirror_doc_blocks = Some(ccfw_source_plain.doc_blocks); - // Mark the Client as unsynced until this - // is acknowledged. - sync_state = SyncState::Pending(ide_message.id); - Ok(ResultOkTypes::Void) - } - // TODO - TranslationResultsString::Binary => Err("TODO".to_string()), - TranslationResultsString::Err(err) => Err(format!("Error translating source to CodeChat: {err}").to_string()), - TranslationResultsString::Unknown => { - // Send the new raw contents. - debug!("Sending translated contents to Client."); - queue_send!(to_client_tx.send(EditorMessage { - id: ide_message.id, - message: EditorMessageContents::Update(UpdateMessageContents { - file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), - contents: Some(CodeChatForWeb { - metadata: SourceFileMetadata { - // Since this is raw data, `mode` doesn't - // matter. - mode: "".to_string(), - }, - source: CodeMirrorDiffable::Plain(CodeMirror { - doc: code_mirror.doc, - doc_blocks: vec![] - }) - }), - cursor_position: update.cursor_position, - scroll_position: update.scroll_position, + } else { + // We must make a clone to put in the TX + // queue; this allows us to keep the + // original below to use with the next + // diff. + ccfw.clone() + } + ); + queue_send!(to_client_tx.send(EditorMessage { + id: ide_message.id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), + contents, + cursor_position: update.cursor_position, + scroll_position: update.scroll_position, + }), + })); + // Update to the latest code after + // computing diffs. To avoid ownership + // problems, re-define `ccfw_source_plain`. + let CodeMirrorDiffable::Plain(ccfw_source_plain) = ccfw.source else { + error!("{}", "Unexpected diff value."); + break; + }; + source_code = code_mirror.doc; + code_mirror_doc = ccfw_source_plain.doc; + code_mirror_doc_blocks = Some(ccfw_source_plain.doc_blocks); + // Mark the Client as unsynced until this + // is acknowledged. + sync_state = SyncState::Pending(ide_message.id); + Ok(ResultOkTypes::Void) + } + // TODO + TranslationResultsString::Binary => Err("TODO".to_string()), + TranslationResultsString::Err(err) => Err(format!("Error translating source to CodeChat: {err}").to_string()), + TranslationResultsString::Unknown => { + // Send the new raw contents. + debug!("Sending translated contents to Client."); + queue_send!(to_client_tx.send(EditorMessage { + id: ide_message.id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), + contents: Some(CodeChatForWeb { + metadata: SourceFileMetadata { + // Since this is raw data, `mode` doesn't + // matter. + mode: "".to_string(), + }, + source: CodeMirrorDiffable::Plain(CodeMirror { + doc: code_mirror.doc, + doc_blocks: vec![] + }) }), - })); - Ok(ResultOkTypes::Void) - }, - TranslationResultsString::Toc(_) => { - Err("Error: source incorrectly recognized as a TOC.".to_string()) - } + cursor_position: update.cursor_position, + scroll_position: update.scroll_position, + }), + })); + Ok(ResultOkTypes::Void) + }, + TranslationResultsString::Toc(_) => { + Err("Error: source incorrectly recognized as a TOC.".to_string()) } } } } } } - }; - // If there's an error, then report it; - // otherwise, the message is passed to the - // Client, which will provide the result. - if let Err(err) = &result { - error!("{err}"); - send_response(&to_ide_tx, ide_message.id, result).await; } + }; + // If there's an error, then report it; + // otherwise, the message is passed to the + // Client, which will provide the result. + if let Err(err) = &result { + error!("{err}"); + send_response(&to_ide_tx, ide_message.id, result).await; } + } - // Update the current file; translate it to a - // URL then pass it to the Client. - EditorMessageContents::CurrentFile(file_path, _is_text) => { - debug!("Translating and forwarding it to the Client."); - match try_canonicalize(&file_path) { - Ok(clean_file_path) => { - queue_send!(to_client_tx.send(EditorMessage { - id: ide_message.id, - message: EditorMessageContents::CurrentFile( - path_to_url(&prefix_str, Some(&connection_id_raw), &clean_file_path), Some(true) - ) - })); - current_file = file_path.into(); - // Since this is a new file, mark it as - // unsynced. - sync_state = SyncState::OutOfSync; - } - Err(err) => { - let msg = format!( - "Unable to canonicalize file name {}: {err}", &file_path - ); - error!("{msg}"); - send_response(&to_client_tx, ide_message.id, Err(msg)).await; - } + // Update the current file; translate it to a URL + // then pass it to the Client. + EditorMessageContents::CurrentFile(file_path, _is_text) => { + debug!("Translating and forwarding it to the Client."); + match try_canonicalize(&file_path) { + Ok(clean_file_path) => { + queue_send!(to_client_tx.send(EditorMessage { + id: ide_message.id, + message: EditorMessageContents::CurrentFile( + path_to_url(&prefix_str, Some(&connection_id_raw), &clean_file_path), Some(true) + ) + })); + current_file = file_path.into(); + // Since this is a new file, mark it as + // unsynced. + sync_state = SyncState::OutOfSync; + } + Err(err) => { + let msg = format!( + "Unable to canonicalize file name {}: {err}", &file_path + ); + error!("{msg}"); + send_response(&to_client_tx, ide_message.id, Err(msg)).await; } } } - }, - - // Handle HTTP requests. - Some(http_request) = from_http_rx.recv() => { - debug!("Received HTTP request for {:?} and sending LoadFile to IDE, id = {id}.", http_request.file_path); - // Convert the request into a `LoadFile` message. - queue_send!(to_ide_tx.send(EditorMessage { - id, - message: EditorMessageContents::LoadFile(http_request.file_path.clone()) - })); - // Store the ID and request, which are needed to - // send a response when the `LoadFile` result is - // received. - load_file_requests.insert(id.to_bits(), http_request); - id += MESSAGE_ID_INCREMENT; } + }, + + // Handle HTTP requests. + Some(http_request) = from_http_rx.recv() => { + debug!("Received HTTP request for {:?} and sending LoadFile to IDE, id = {id}.", http_request.file_path); + // Convert the request into a `LoadFile` message. + queue_send!(to_ide_tx.send(EditorMessage { + id, + message: EditorMessageContents::LoadFile(http_request.file_path.clone()) + })); + // Store the ID and request, which are needed to send a + // response when the `LoadFile` result is received. + load_file_requests.insert(id.to_bits(), http_request); + id += MESSAGE_ID_INCREMENT; + } - // Handle messages from the client. - Some(client_message) = from_client_rx.recv() => { - debug!("Received Client message id = {}, message = {}", client_message.id, debug_shorten(&client_message.message)); - match client_message.message { - // Handle messages that the client must not - // send. - EditorMessageContents::Opened(_) | - EditorMessageContents::LoadFile(_) | - EditorMessageContents::RequestClose | - EditorMessageContents::ClientHtml(_) => { - let msg = "Client must not send this message."; + // Handle messages from the client. + Some(client_message) = from_client_rx.recv() => { + debug!("Received Client message id = {}, message = {}", client_message.id, debug_shorten(&client_message.message)); + match client_message.message { + // Handle messages that the client must not send. + EditorMessageContents::Opened(_) | + EditorMessageContents::LoadFile(_) | + EditorMessageContents::RequestClose | + EditorMessageContents::ClientHtml(_) => { + let msg = "Client must not send this message."; + error!("{msg}"); + send_response(&to_client_tx, client_message.id, Err(msg.to_string())).await; + }, + + // Handle messages that are simply passed through. + EditorMessageContents::Closed | + EditorMessageContents::Result(_) => { + debug!("Forwarding it to the IDE."); + // If this result confirms that the Client + // received the most recent IDE update, then + // mark the documents as synced. + if sync_state == SyncState::Pending(client_message.id) { + sync_state = SyncState::InSync; + } + queue_send!(to_ide_tx.send(client_message)) + }, + + // Open a web browser when requested. + EditorMessageContents::OpenUrl(url) => { + // This doesn't work in Codespaces. TODO: send + // this back to the VSCode window, then call + // `vscode.env.openExternal(vscode.Uri.parse(url))`. + if let Err(err) = webbrowser::open(&url) { + let msg = format!("Unable to open web browser to URL {url}: {err}"); error!("{msg}"); - send_response(&to_client_tx, client_message.id, Err(msg.to_string())).await; - }, - - // Handle messages that are simply passed - // through. - EditorMessageContents::Closed | - EditorMessageContents::Result(_) => { - debug!("Forwarding it to the IDE."); - // If this result confirms that the Client - // received the most recent IDE update, then - // mark the documents as synced. - if sync_state == SyncState::Pending(client_message.id) { - sync_state = SyncState::InSync; - } - queue_send!(to_ide_tx.send(client_message)) - }, - - // Open a web browser when requested. - EditorMessageContents::OpenUrl(url) => { - // This doesn't work in Codespaces. TODO: - // send this back to the VSCode window, then - // call - // `vscode.env.openExternal(vscode.Uri.parse(url))`. - if let Err(err) = webbrowser::open(&url) { - let msg = format!("Unable to open web browser to URL {url}: {err}"); + send_response(&to_client_tx, client_message.id, Err(msg)).await; + } else { + send_response(&to_client_tx, client_message.id, Ok(ResultOkTypes::Void)).await; + } + }, + + // Handle the `Update` message. + EditorMessageContents::Update(update_message_contents) => { + debug!("Forwarding translation of it to the IDE."); + match try_canonicalize(&update_message_contents.file_path) { + Err(err) => { + let msg = format!( + "Unable to canonicalize file name {}: {err}", &update_message_contents.file_path + ); error!("{msg}"); send_response(&to_client_tx, client_message.id, Err(msg)).await; - } else { - send_response(&to_client_tx, client_message.id, Ok(ResultOkTypes::Void)).await; - } - }, - - // Handle the `Update` message. - EditorMessageContents::Update(update_message_contents) => { - debug!("Forwarding translation of it to the IDE."); - match try_canonicalize(&update_message_contents.file_path) { - Err(err) => { - let msg = format!( - "Unable to canonicalize file name {}: {err}", &update_message_contents.file_path - ); - error!("{msg}"); - send_response(&to_client_tx, client_message.id, Err(msg)).await; - continue; - } - Ok(clean_file_path) => { - let codechat_for_web = match update_message_contents.contents { - None => None, - Some(cfw) => match codechat_for_web_to_source( - &cfw) - { - Ok(new_source_code) => { - // Correct EOL endings for use with the - // IDE. - let new_source_code_eol = eol_convert(new_source_code, &eol); - let ccfw = if sync_state == SyncState::InSync && allow_source_diffs { - Some(CodeChatForWeb { - metadata: cfw.metadata, - source: CodeMirrorDiffable::Diff(CodeMirrorDiff { - // Diff with correct EOLs, so that (for - // CRLF files as well as LF files) offsets - // are correct. - doc: diff_str(&source_code, &new_source_code_eol), - doc_blocks: vec![], - }), - }) - } else { - Some(CodeChatForWeb { - metadata: cfw.metadata, - source: CodeMirrorDiffable::Plain(CodeMirror { - // We must clone here, so that it can be - // placed in the TX queue. - doc: new_source_code_eol.clone(), - doc_blocks: vec![], - }), - }) - }; - source_code = new_source_code_eol; - let CodeMirrorDiffable::Plain(cmd) = cfw.source else { - // TODO: support diffable! - error!("No diff!"); - break; - }; - code_mirror_doc = cmd.doc; - // TODO: instead of `cmd.doc_blocks`, use - // `None` to indicate that the doc blocks - // contain Markdown instead of HTML. - code_mirror_doc_blocks = None; - ccfw - }, - Err(message) => { - let msg = format!( - "Unable to translate to source: {message}" - ); - error!("{msg}"); - send_response(&to_client_tx, client_message.id, Err(msg)).await; - continue; - } - }, - }; - queue_send!(to_ide_tx.send(EditorMessage { - id: client_message.id, - message: EditorMessageContents::Update(UpdateMessageContents { - file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), - contents: codechat_for_web, - cursor_position: update_message_contents.cursor_position, - scroll_position: update_message_contents.scroll_position, - }) - })); - // Mark the IDE contents as out of sync - // until this message is received. - sync_state = SyncState::Pending(client_message.id); - } + continue; } - }, - - // Update the current file; translate it to a - // URL then pass it to the IDE. - EditorMessageContents::CurrentFile(url_string, _is_text) => { - debug!("Forwarding translated path to IDE."); - let result = match url_to_path(&url_string, prefix) { - Err(err) => Err(format!("Unable to convert URL to path: {err}")), - Ok(file_path) => { - match file_path.to_str() { - None => Err("Unable to convert path to string.".to_string()), - Some(file_path_string) => { - // Use a [binary file - // sniffer](#binary-file-sniffer) to - // determine if the file is text or binary. - let is_text = if let Ok(mut fc) = File::open(&file_path).await { - try_read_as_text(&mut fc).await.is_some() + Ok(clean_file_path) => { + let codechat_for_web = match update_message_contents.contents { + None => None, + Some(cfw) => match codechat_for_web_to_source( + &cfw) + { + Ok(new_source_code) => { + // Correct EOL endings for use with the + // IDE. + let new_source_code_eol = eol_convert(new_source_code, &eol); + let ccfw = if sync_state == SyncState::InSync && allow_source_diffs { + Some(CodeChatForWeb { + metadata: cfw.metadata, + source: CodeMirrorDiffable::Diff(CodeMirrorDiff { + // Diff with correct EOLs, so that (for + // CRLF files as well as LF files) offsets + // are correct. + doc: diff_str(&source_code, &new_source_code_eol), + doc_blocks: vec![], + }), + }) } else { - false + Some(CodeChatForWeb { + metadata: cfw.metadata, + source: CodeMirrorDiffable::Plain(CodeMirror { + // We must clone here, so that it can be + // placed in the TX queue. + doc: new_source_code_eol.clone(), + doc_blocks: vec![], + }), + }) }; - queue_send!(to_ide_tx.send(EditorMessage { - id: client_message.id, - message: EditorMessageContents::CurrentFile(file_path_string.to_string(), Some(is_text)) - })); - current_file = file_path; - // Mark the IDE as out of sync, since this - // is a new file. - sync_state = SyncState::OutOfSync; - Ok(()) + source_code = new_source_code_eol; + let CodeMirrorDiffable::Plain(cmd) = cfw.source else { + // TODO: support diffable! + error!("No diff!"); + break; + }; + code_mirror_doc = cmd.doc; + // TODO: instead of `cmd.doc_blocks`, use + // `None` to indicate that the doc blocks + // contain Markdown instead of HTML. + code_mirror_doc_blocks = None; + ccfw + }, + Err(message) => { + let msg = format!( + "Unable to translate to source: {message}" + ); + error!("{msg}"); + send_response(&to_client_tx, client_message.id, Err(msg)).await; + continue; } + }, + }; + queue_send!(to_ide_tx.send(EditorMessage { + id: client_message.id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(), + contents: codechat_for_web, + cursor_position: update_message_contents.cursor_position, + scroll_position: update_message_contents.scroll_position, + }) + })); + // Mark the IDE contents as out of sync + // until this message is received. + sync_state = SyncState::Pending(client_message.id); + } + } + }, + + // Update the current file; translate it to a URL + // then pass it to the IDE. + EditorMessageContents::CurrentFile(url_string, _is_text) => { + debug!("Forwarding translated path to IDE."); + let result = match url_to_path(&url_string, prefix) { + Err(err) => Err(format!("Unable to convert URL to path: {err}")), + Ok(file_path) => { + match file_path.to_str() { + None => Err("Unable to convert path to string.".to_string()), + Some(file_path_string) => { + // Use a [binary file + // sniffer](#binary-file-sniffer) to + // determine if the file is text or binary. + let is_text = if let Ok(mut fc) = File::open(&file_path).await { + try_read_as_text(&mut fc).await.is_some() + } else { + false + }; + queue_send!(to_ide_tx.send(EditorMessage { + id: client_message.id, + message: EditorMessageContents::CurrentFile(file_path_string.to_string(), Some(is_text)) + })); + current_file = file_path; + // Mark the IDE as out of sync, since this + // is a new file. + sync_state = SyncState::OutOfSync; + Ok(()) } } - }; - if let Err(msg) = result { - error!("{msg}"); - send_response(&to_client_tx, client_message.id, Err(msg)).await; } + }; + if let Err(msg) = result { + error!("{msg}"); + send_response(&to_client_tx, client_message.id, Err(msg)).await; } } - }, + } + }, - else => break - } + else => break } } + } - debug!("VSCode processing task shutting down."); - if app_state_task - .processing_task_queue_tx - .lock() - .unwrap() - .remove(&connection_id) - .is_none() - { - error!( - "Unable to remove connection ID {connection_id} from processing task queue." - ); - } - if app_state_task - .client_queues - .lock() - .unwrap() - .remove(&connection_id) - .is_none() - { - error!("Unable to remove connection ID {connection_id} from client queues."); - } - if app_state_task - .ide_queues - .lock() - .unwrap() - .remove(&connection_id) - .is_none() - { - error!("Unable to remove connection ID {connection_id} from IDE queues."); - } + debug!("VSCode processing task shutting down."); + if app_state_task + .processing_task_queue_tx + .lock() + .unwrap() + .remove(&connection_id) + .is_none() + { + error!("Unable to remove connection ID {connection_id} from processing task queue."); + } + if app_state_task + .client_queues + .lock() + .unwrap() + .remove(&connection_id) + .is_none() + { + error!("Unable to remove connection ID {connection_id} from client queues."); + } + if app_state_task + .ide_queues + .lock() + .unwrap() + .remove(&connection_id) + .is_none() + { + error!("Unable to remove connection ID {connection_id} from IDE queues."); + } - from_ide_rx.close(); - from_ide_rx.close(); + from_ide_rx.close(); + from_ide_rx.close(); - // Drain any remaining messages after closing the queue. - while let Some(m) = from_ide_rx.recv().await { - warn!("Dropped queued message {m:?}"); - } - while let Some(m) = from_client_rx.recv().await { - warn!("Dropped queued message {m:?}"); - } - debug!("VSCode processing task exited."); + // Drain any remaining messages after closing the queue. + while let Some(m) = from_ide_rx.recv().await { + warn!("Dropped queued message {m:?}"); + } + while let Some(m) = from_client_rx.recv().await { + warn!("Dropped queued message {m:?}"); } - }); + debug!("VSCode processing task exited."); + } } // If a string is encoded using CRLFs (Windows style), convert it to LFs only diff --git a/server/src/webserver.rs b/server/src/webserver.rs index 9fa6e959..ec8fa664 100644 --- a/server/src/webserver.rs +++ b/server/src/webserver.rs @@ -1037,7 +1037,7 @@ fn make_simple_viewer(http_request: &ProcessingTaskHttpRequest, html: &str) -> S /// allowing the user to edit the plain text of the source code in the IDE, or /// make GUI-enhanced edits of the source code rendered by the CodeChat Editor /// Client. -pub async fn client_websocket( +pub fn client_websocket( connection_id: String, req: HttpRequest, body: web::Payload,