feat: add mobile virtual keyboard
This commit is contained in:
@@ -5,8 +5,8 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "webterm-frontend",
|
"name": "webterm-frontend",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@moonshine-ai/moonshine-js": "^0.1.29",
|
|
||||||
"ghostty-web": "github:rcarmo/ghostty-web#fcc47d423a7fce1c02c702b6464d0b1ab89175f1",
|
"ghostty-web": "github:rcarmo/ghostty-web#fcc47d423a7fce1c02c702b6464d0b1ab89175f1",
|
||||||
|
"simple-keyboard": "^3.8.141",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.7.0",
|
"typescript": "^5.7.0",
|
||||||
@@ -14,176 +14,10 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
|
||||||
|
|
||||||
"@huggingface/jinja": ["@huggingface/jinja@0.5.9", "", {}, "sha512-uWTG+l3VJRsl7EXxYizuL3P+cCPoc3cRqbWWRcQN0FhejRfbdq0RNhCmbY/YDtnTcz9icdLYuLDjsnz4d8JMuw=="],
|
|
||||||
|
|
||||||
"@huggingface/transformers": ["@huggingface/transformers@3.8.1", "", { "dependencies": { "@huggingface/jinja": "^0.5.3", "onnxruntime-node": "1.21.0", "onnxruntime-web": "1.22.0-dev.20250409-89f8206ba4", "sharp": "^0.34.1" } }, "sha512-tsTk4zVjImqdqjS8/AOZg2yNLd1z9S5v+7oUPpXaasDRwEDhB+xnglK1k5cad26lL5/ZIaeREgWWy0bs9y9pPA=="],
|
|
||||||
|
|
||||||
"@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
|
|
||||||
|
|
||||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
|
|
||||||
|
|
||||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="],
|
|
||||||
|
|
||||||
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="],
|
|
||||||
|
|
||||||
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="],
|
|
||||||
|
|
||||||
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="],
|
|
||||||
|
|
||||||
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="],
|
|
||||||
|
|
||||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
|
||||||
|
|
||||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
|
||||||
|
|
||||||
"@moonshine-ai/moonshine-js": ["@moonshine-ai/moonshine-js@0.1.29", "", { "dependencies": { "@huggingface/transformers": "^3.3.3", "@ricky0123/vad-web": "file:../vad-moonshine/packages/web", "llama-tokenizer-js": "^1.2.2", "onnxruntime-web": "^1.22.0" } }, "sha512-Gx1B3mJcbM68ihSy/LyJEuEkGq7sYMqTb04zNdcIeidU0URVlSmXP0GyiQOTTAqDZQXlIC7k+bky+FdXk0UPlg=="],
|
|
||||||
|
|
||||||
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
|
||||||
|
|
||||||
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
|
||||||
|
|
||||||
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="],
|
|
||||||
|
|
||||||
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
|
|
||||||
|
|
||||||
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
|
|
||||||
|
|
||||||
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
|
|
||||||
|
|
||||||
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.1", "", {}, "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew=="],
|
|
||||||
|
|
||||||
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
|
|
||||||
|
|
||||||
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
|
|
||||||
|
|
||||||
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.1", "", {}, "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg=="],
|
|
||||||
|
|
||||||
"@types/node": ["@types/node@25.7.0", "", { "dependencies": { "undici-types": "~7.21.0" } }, "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg=="],
|
|
||||||
|
|
||||||
"boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="],
|
|
||||||
|
|
||||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
|
||||||
|
|
||||||
"define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
|
|
||||||
|
|
||||||
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
|
||||||
|
|
||||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
|
||||||
|
|
||||||
"detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="],
|
|
||||||
|
|
||||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
|
||||||
|
|
||||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
|
||||||
|
|
||||||
"es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="],
|
|
||||||
|
|
||||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
|
||||||
|
|
||||||
"flatbuffers": ["flatbuffers@25.9.23", "", {}, "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ=="],
|
|
||||||
|
|
||||||
"ghostty-web": ["ghostty-web@github:rcarmo/ghostty-web#fcc47d4", {}, "rcarmo-ghostty-web-fcc47d4", "sha512-tq0cFciI32VTyOXDoLHQQDndeA6jhFuZ/3TWYx3VlYDzRhYkWAtTBi6t29isYPzdiKNIWggjkn3Ve/+Qub/wBg=="],
|
"ghostty-web": ["ghostty-web@github:rcarmo/ghostty-web#fcc47d4", {}, "rcarmo-ghostty-web-fcc47d4", "sha512-tq0cFciI32VTyOXDoLHQQDndeA6jhFuZ/3TWYx3VlYDzRhYkWAtTBi6t29isYPzdiKNIWggjkn3Ve/+Qub/wBg=="],
|
||||||
|
|
||||||
"global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="],
|
"simple-keyboard": ["simple-keyboard@3.8.141", "", {}, "sha512-5kS9RUYk89alam3XsLzOeLHtPMO0km3Lt1d92+Z4P/mhBqomXanFkMDnb6A4EUHA+v3/dbH/IcBT/85l1rnTiA=="],
|
||||||
|
|
||||||
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
|
|
||||||
|
|
||||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
|
||||||
|
|
||||||
"guid-typescript": ["guid-typescript@1.0.9", "", {}, "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="],
|
|
||||||
|
|
||||||
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
|
|
||||||
|
|
||||||
"json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="],
|
|
||||||
|
|
||||||
"llama-tokenizer-js": ["llama-tokenizer-js@1.2.2", "", {}, "sha512-Wmth393dc3odWU3IzARJ3r2oIfWgw9GdJ5Gm+hGhfECNO18UHLRqEFSf511jn4E9KcQGzuuKw4Wl08pHAemLAw=="],
|
|
||||||
|
|
||||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
|
||||||
|
|
||||||
"matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="],
|
|
||||||
|
|
||||||
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
|
||||||
|
|
||||||
"minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
|
|
||||||
|
|
||||||
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
|
|
||||||
|
|
||||||
"onnxruntime-common": ["onnxruntime-common@1.26.0", "", {}, "sha512-qVyMR4lcWgbkc4getFV+GQijsTnbg/siteoqcDwa3sI/LxbrMSNw4ePyvCq/ymdQaRomCA7YuWmhzsswxvymdw=="],
|
|
||||||
|
|
||||||
"onnxruntime-node": ["onnxruntime-node@1.21.0", "", { "dependencies": { "global-agent": "^3.0.0", "onnxruntime-common": "1.21.0", "tar": "^7.0.1" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw=="],
|
|
||||||
|
|
||||||
"onnxruntime-web": ["onnxruntime-web@1.26.0", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.26.0", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-LbRr/8zZt2xilI2smrVQGGKINo0U46i8qJp+UXyMBGfqN7KjnH1BiwCwLwyNIVV4i9CKFv7Sf4PwLKWnT8/bEA=="],
|
|
||||||
|
|
||||||
"platform": ["platform@1.3.6", "", {}, "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="],
|
|
||||||
|
|
||||||
"protobufjs": ["protobufjs@7.5.7", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.1", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-NGnrxS/nLKUo5nkbVQxlC71sB4hdfImdYIbFeSCidxtwATx0AHRPcANSLd0q5Bb2BkoSWo2iisQhGg5/r+ihbA=="],
|
|
||||||
|
|
||||||
"roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
|
|
||||||
|
|
||||||
"semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="],
|
|
||||||
|
|
||||||
"semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="],
|
|
||||||
|
|
||||||
"serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="],
|
|
||||||
|
|
||||||
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
|
|
||||||
|
|
||||||
"sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
|
|
||||||
|
|
||||||
"tar": ["tar@7.5.15", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="],
|
|
||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
|
||||||
|
|
||||||
"type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
|
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.21.0", "", {}, "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ=="],
|
|
||||||
|
|
||||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
|
||||||
|
|
||||||
"@huggingface/transformers/onnxruntime-web": ["onnxruntime-web@1.22.0-dev.20250409-89f8206ba4", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.22.0-dev.20250409-89f8206ba4", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-0uS76OPgH0hWCPrFKlL8kYVV7ckM7t/36HfbgoFw6Nd0CZVVbQC4PkrR8mBX8LtNUFZO25IQBqV2Hx2ho3FlbQ=="],
|
|
||||||
|
|
||||||
"@moonshine-ai/moonshine-js/@ricky0123/vad-web": ["@ricky0123/vad-web@file:../vad-moonshine/packages/web", {}],
|
|
||||||
|
|
||||||
"onnxruntime-node/onnxruntime-common": ["onnxruntime-common@1.21.0", "", {}, "sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ=="],
|
|
||||||
|
|
||||||
"@huggingface/transformers/onnxruntime-web/onnxruntime-common": ["onnxruntime-common@1.22.0-dev.20250409-89f8206ba4", "", {}, "sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ=="],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2
-1119
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,6 @@
|
|||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@moonshine-ai/moonshine-js": "^0.1.29",
|
|
||||||
"ghostty-web": "github:rcarmo/ghostty-web#fcc47d423a7fce1c02c702b6464d0b1ab89175f1"
|
"ghostty-web": "github:rcarmo/ghostty-web#fcc47d423a7fce1c02c702b6464d0b1ab89175f1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+119
-2
@@ -172,6 +172,7 @@ type LocalServer struct {
|
|||||||
fontFamily string
|
fontFamily string
|
||||||
fontSize int
|
fontSize int
|
||||||
screenshotMode string
|
screenshotMode string
|
||||||
|
staticAssetCacheBust string
|
||||||
|
|
||||||
sessionManager *SessionManager
|
sessionManager *SessionManager
|
||||||
landingApps []App
|
landingApps []App
|
||||||
@@ -179,6 +180,7 @@ type LocalServer struct {
|
|||||||
composeProject string
|
composeProject string
|
||||||
dockerWatch bool
|
dockerWatch bool
|
||||||
staticPath string
|
staticPath string
|
||||||
|
auth *authConfig
|
||||||
|
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
|
|
||||||
@@ -262,6 +264,7 @@ func NewLocalServer(config Config, options ServerOptions) *LocalServer {
|
|||||||
composeProject: options.ComposeProject,
|
composeProject: options.ComposeProject,
|
||||||
dockerWatch: options.DockerWatch,
|
dockerWatch: options.DockerWatch,
|
||||||
staticPath: options.StaticPath,
|
staticPath: options.StaticPath,
|
||||||
|
auth: newAuthConfig(),
|
||||||
upgrader: websocket.Upgrader{
|
upgrader: websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool { return true },
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
},
|
},
|
||||||
@@ -277,9 +280,28 @@ func NewLocalServer(config Config, options ServerOptions) *LocalServer {
|
|||||||
if server.staticPath == "" {
|
if server.staticPath == "" {
|
||||||
server.staticPath = findStaticPath()
|
server.staticPath = findStaticPath()
|
||||||
}
|
}
|
||||||
|
server.staticAssetCacheBust = server.computeStaticAssetCacheBust()
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *LocalServer) computeStaticAssetCacheBust() string {
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if s.staticPath != "" {
|
||||||
|
data, err = os.ReadFile(filepath.Join(s.staticPath, "js", "terminal.js"))
|
||||||
|
} else {
|
||||||
|
data, err = embeddedStaticAssets.ReadFile("static/js/terminal.js")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil || len(data) == 0 {
|
||||||
|
return Version
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := sha1.Sum(data)
|
||||||
|
return fmt.Sprintf("%s-%x", Version, hash[:6])
|
||||||
|
}
|
||||||
|
|
||||||
func findStaticPath() string {
|
func findStaticPath() string {
|
||||||
if p := strings.TrimSpace(os.Getenv("WEBTERM_STATIC_PATH")); p != "" {
|
if p := strings.TrimSpace(os.Getenv("WEBTERM_STATIC_PATH")); p != "" {
|
||||||
if stat, err := os.Stat(p); err == nil && stat.IsDir() {
|
if stat, err := os.Stat(p); err == nil && stat.IsDir() {
|
||||||
@@ -439,6 +461,14 @@ func parseResizePayload(value any) (int, int) {
|
|||||||
return clampInt(width, 1, 500), clampInt(height, 1, 500)
|
return clampInt(width, 1, 500), clampInt(height, 1, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isSecureRequest(r *http.Request) bool {
|
||||||
|
if r.TLS != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
value := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-Proto"), ",")[0])
|
||||||
|
return strings.EqualFold(value, "https") || strings.EqualFold(value, "wss")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *LocalServer) loggingMiddleware(next http.Handler) http.Handler {
|
func (s *LocalServer) loggingMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
@@ -452,6 +482,91 @@ func (s *LocalServer) loggingMiddleware(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *LocalServer) isAuthenticated(r *http.Request) bool {
|
||||||
|
if s.auth == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
cookie, err := r.Cookie(authCookieName)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s.auth.validCookieValue(cookie.Value, time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LocalServer) handleAuthLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if s.auth == nil {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
http.Error(w, "invalid form", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !s.auth.usernameMatches(strings.TrimSpace(r.Form.Get("username"))) || !s.auth.passwordMatches(r.Form.Get("password")) {
|
||||||
|
http.Redirect(w, r, "/?auth_error=1", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.SetCookie(w, s.auth.sessionCookie(s.auth.cookieValue(time.Now()), r))
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LocalServer) handleAuthLogout(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if s.auth == nil {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.SetCookie(w, s.auth.clearCookie(r))
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LocalServer) renderLoginPage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
errorBanner := ""
|
||||||
|
if r.URL.Query().Get("auth_error") == "1" {
|
||||||
|
errorBanner = `<p style="margin:0 0 14px;color:#ffb4a8;font:600 14px var(--webterm-sans)">Wrong username or password</p>`
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
w.Header().Set("Cache-Control", "no-store")
|
||||||
|
_, _ = io.WriteString(w, `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Webterm Login</title><style>:root{--webterm-bg:#0d1117;--webterm-card:#161b22;--webterm-border:#30363d;--webterm-text:#e6edf3;--webterm-muted:#9da7b3;--webterm-accent:#2f81f7;--webterm-sans:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}*{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;background:radial-gradient(circle at top,#1b2533 0,#0d1117 58%);color:var(--webterm-text);font-family:var(--webterm-sans)}main{width:min(92vw,380px);padding:28px;border:1px solid var(--webterm-border);border-radius:18px;background:rgba(22,27,34,.96);box-shadow:0 28px 80px rgba(0,0,0,.45)}h1{margin:0 0 8px;font-size:22px}p{margin:0 0 18px;color:var(--webterm-muted);font-size:14px;line-height:1.5}label{display:block;margin:0 0 8px;font-size:13px;color:var(--webterm-muted)}input{width:100%;padding:12px 14px;border:1px solid var(--webterm-border);border-radius:12px;background:#0d1117;color:var(--webterm-text);font:500 16px var(--webterm-sans)}button{width:100%;margin-top:14px;padding:12px 14px;border:0;border-radius:12px;background:var(--webterm-accent);color:white;font:700 15px var(--webterm-sans);cursor:pointer}</style></head><body><main><h1>Webterm</h1><p>Sign in to open terminal.</p>`+errorBanner+`<form method="post" action="/auth/login"><label for="username">Username</label><input id="username" name="username" type="text" autocomplete="username" required><label for="password" style="margin-top:14px">Password</label><input id="password" name="password" type="password" autocomplete="current-password" autofocus required><button type="submit">Open</button></form></main></body></html>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *LocalServer) authMiddleware(next http.Handler) http.Handler {
|
||||||
|
if s.auth == nil {
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/health", "/auth/login", "/auth/logout":
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(r.URL.Path, "/static/") {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.isAuthenticated(r) {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(r.URL.Path, "/ws/") {
|
||||||
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.URL.Path == "/" {
|
||||||
|
s.renderLoginPage(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *LocalServer) gzipMiddleware(next http.Handler) http.Handler {
|
func (s *LocalServer) gzipMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/events" {
|
if r.URL.Path == "/events" {
|
||||||
@@ -1774,7 +1889,7 @@ func (s *LocalServer) handleRoot(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
escapedFont := strings.ReplaceAll(fontFamily, `"`, """)
|
escapedFont := strings.ReplaceAll(fontFamily, `"`, """)
|
||||||
dataAttrs := fmt.Sprintf(`data-session-websocket-url="%s" data-session-route-key="%s" data-session-name="%s" data-font-size="%d" data-scrollback="1000" data-theme="%s" data-font-family="%s"`, htmlAttrEscape(wsURL), htmlAttrEscape(routeKey), htmlAttrEscape(app.Name), s.fontSize, htmlAttrEscape(theme), escapedFont)
|
dataAttrs := fmt.Sprintf(`data-session-websocket-url="%s" data-session-route-key="%s" data-session-name="%s" data-font-size="%d" data-scrollback="1000" data-theme="%s" data-font-family="%s"`, htmlAttrEscape(wsURL), htmlAttrEscape(routeKey), htmlAttrEscape(app.Name), s.fontSize, htmlAttrEscape(theme), escapedFont)
|
||||||
cacheBust := "?v=" + Version
|
cacheBust := "?v=" + s.staticAssetCacheBust
|
||||||
page := fmt.Sprintf(`<!DOCTYPE html><html><head><meta charset="utf-8"><title>%s</title><link rel="stylesheet" href="/static/monospace.css%s"><style>html,body{width:100%%;height:100%%}body{background:%s;margin:0;padding:0;overflow:hidden;font-family:var(--webterm-mono);display:flex;flex-direction:column;height:100vh;height:100dvh}.webterm-terminal{width:100%%;flex:1;min-height:0;display:block;overflow:hidden}</style></head><body><div id="terminal" class="webterm-terminal" %s></div><script type="module" src="/static/js/terminal.js%s"></script></body></html>`, htmlEscape(app.Name), cacheBust, themeBG, dataAttrs, cacheBust)
|
page := fmt.Sprintf(`<!DOCTYPE html><html><head><meta charset="utf-8"><title>%s</title><link rel="stylesheet" href="/static/monospace.css%s"><style>html,body{width:100%%;height:100%%}body{background:%s;margin:0;padding:0;overflow:hidden;font-family:var(--webterm-mono);display:flex;flex-direction:column;height:100vh;height:100dvh}.webterm-terminal{width:100%%;flex:1;min-height:0;display:block;overflow:hidden}</style></head><body><div id="terminal" class="webterm-terminal" %s></div><script type="module" src="/static/js/terminal.js%s"></script></body></html>`, htmlEscape(app.Name), cacheBust, themeBG, dataAttrs, cacheBust)
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
w.Header().Set("Cache-Control", "no-cache")
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
@@ -1865,6 +1980,8 @@ func (s *LocalServer) shutdown() {
|
|||||||
|
|
||||||
func (s *LocalServer) Handler() http.Handler {
|
func (s *LocalServer) Handler() http.Handler {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/auth/login", s.handleAuthLogin)
|
||||||
|
mux.HandleFunc("/auth/logout", s.handleAuthLogout)
|
||||||
mux.HandleFunc("/ws/", s.handleWebSocket)
|
mux.HandleFunc("/ws/", s.handleWebSocket)
|
||||||
mux.HandleFunc("/screenshot.svg", s.handleScreenshot)
|
mux.HandleFunc("/screenshot.svg", s.handleScreenshot)
|
||||||
mux.HandleFunc("/screenshot.png", s.handleScreenshotPNG)
|
mux.HandleFunc("/screenshot.png", s.handleScreenshotPNG)
|
||||||
@@ -1878,7 +1995,7 @@ func (s *LocalServer) Handler() http.Handler {
|
|||||||
} else if staticFS, ok := embeddedStaticFS(); ok {
|
} else if staticFS, ok := embeddedStaticFS(); ok {
|
||||||
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(staticFS)))
|
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(staticFS)))
|
||||||
}
|
}
|
||||||
return s.loggingMiddleware(s.gzipMiddleware(mux))
|
return s.loggingMiddleware(s.gzipMiddleware(s.authMiddleware(mux)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// evictStaleScreenshots periodically removes screenshot cache entries
|
// evictStaleScreenshots periodically removes screenshot cache entries
|
||||||
|
|||||||
Vendored
-35
@@ -1,35 +0,0 @@
|
|||||||
declare module "@moonshine-ai/moonshine-js" {
|
|
||||||
export interface TranscriberCallbacks {
|
|
||||||
onPermissionsRequested: () => unknown;
|
|
||||||
onError: (error: unknown) => unknown;
|
|
||||||
onModelLoadStarted: () => unknown;
|
|
||||||
onModelLoaded: () => unknown;
|
|
||||||
onTranscribeStarted: () => unknown;
|
|
||||||
onTranscribeStopped: () => unknown;
|
|
||||||
onTranscriptionUpdated: (text: string) => unknown;
|
|
||||||
onTranscriptionCommitted: (text: string, buffer?: AudioBuffer) => unknown;
|
|
||||||
onFrame: (probs: unknown, frame: unknown, ema: unknown) => unknown;
|
|
||||||
onSpeechStart: () => unknown;
|
|
||||||
onSpeechEnd: () => unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MicrophoneTranscriber {
|
|
||||||
constructor(
|
|
||||||
modelURL: string,
|
|
||||||
callbacks?: Partial<TranscriberCallbacks>,
|
|
||||||
useVAD?: boolean,
|
|
||||||
precision?: string
|
|
||||||
);
|
|
||||||
isActive: boolean;
|
|
||||||
start(): Promise<void>;
|
|
||||||
stop(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Settings: {
|
|
||||||
BASE_ASSET_PATH: {
|
|
||||||
MOONSHINE: string;
|
|
||||||
ONNX_RUNTIME: string;
|
|
||||||
SILERO_VAD: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,336 @@
|
|||||||
|
function freeConfig(config, Module) {
|
||||||
|
if ('buffer' in config) {
|
||||||
|
Module._free(config.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('sileroVad' in config) {
|
||||||
|
freeConfig(config.sileroVad, Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('tenVad' in config) {
|
||||||
|
freeConfig(config.tenVad, Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Module._free(config.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user should free the returned pointers
|
||||||
|
function initSherpaOnnxSileroVadModelConfig(config, Module) {
|
||||||
|
const modelLen = Module.lengthBytesUTF8(config.model || '') + 1;
|
||||||
|
|
||||||
|
const n = modelLen;
|
||||||
|
|
||||||
|
const buffer = Module._malloc(n);
|
||||||
|
|
||||||
|
const len = 6 * 4;
|
||||||
|
const ptr = Module._malloc(len);
|
||||||
|
|
||||||
|
Module.stringToUTF8(config.model || '', buffer, modelLen);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
Module.setValue(ptr, buffer, 'i8*');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.threshold || 0.5, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.minSilenceDuration || 0.5, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.minSpeechDuration || 0.25, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.windowSize || 512, 'i32');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.maxSpeechDuration || 20, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
return {
|
||||||
|
buffer: buffer,
|
||||||
|
ptr: ptr,
|
||||||
|
len: len,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSherpaOnnxTenVadModelConfig(config, Module) {
|
||||||
|
const modelLen = Module.lengthBytesUTF8(config.model || '') + 1;
|
||||||
|
|
||||||
|
const n = modelLen;
|
||||||
|
|
||||||
|
const buffer = Module._malloc(n);
|
||||||
|
|
||||||
|
const len = 6 * 4;
|
||||||
|
const ptr = Module._malloc(len);
|
||||||
|
|
||||||
|
Module.stringToUTF8(config.model || '', buffer, modelLen);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
Module.setValue(ptr, buffer, 'i8*');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.threshold || 0.5, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.minSilenceDuration || 0.5, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.minSpeechDuration || 0.25, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.windowSize || 256, 'i32');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.maxSpeechDuration || 20, 'float');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
return {
|
||||||
|
buffer: buffer,
|
||||||
|
ptr: ptr,
|
||||||
|
len: len,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSherpaOnnxVadModelConfig(config, Module) {
|
||||||
|
if (!('sileroVad' in config)) {
|
||||||
|
config.sileroVad = {
|
||||||
|
model: '',
|
||||||
|
threshold: 0.50,
|
||||||
|
minSilenceDuration: 0.50,
|
||||||
|
minSpeechDuration: 0.25,
|
||||||
|
windowSize: 512,
|
||||||
|
maxSpeechDuration: 20,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!('tenVad' in config)) {
|
||||||
|
config.tenVad = {
|
||||||
|
model: '',
|
||||||
|
threshold: 0.50,
|
||||||
|
minSilenceDuration: 0.50,
|
||||||
|
minSpeechDuration: 0.25,
|
||||||
|
windowSize: 256,
|
||||||
|
maxSpeechDuration: 20,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const sileroVad =
|
||||||
|
initSherpaOnnxSileroVadModelConfig(config.sileroVad, Module);
|
||||||
|
|
||||||
|
const tenVad = initSherpaOnnxTenVadModelConfig(config.tenVad, Module);
|
||||||
|
|
||||||
|
const len = sileroVad.len + 4 * 4 + tenVad.len;
|
||||||
|
const ptr = Module._malloc(len);
|
||||||
|
|
||||||
|
const providerLen = Module.lengthBytesUTF8(config.provider || 'cpu') + 1;
|
||||||
|
const buffer = Module._malloc(providerLen);
|
||||||
|
Module.stringToUTF8(config.provider || 'cpu', buffer, providerLen);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
Module._CopyHeap(sileroVad.ptr, sileroVad.len, ptr + offset);
|
||||||
|
offset += sileroVad.len;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.sampleRate || 16000, 'i32');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.numThreads || 1, 'i32');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, buffer, 'i8*'); // provider
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module.setValue(ptr + offset, config.debug || 0, 'i32');
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
Module._CopyHeap(tenVad.ptr, tenVad.len, ptr + offset);
|
||||||
|
offset += tenVad.len;
|
||||||
|
|
||||||
|
return {
|
||||||
|
buffer: buffer,
|
||||||
|
ptr: ptr,
|
||||||
|
len: len,
|
||||||
|
sileroVad: sileroVad,
|
||||||
|
tenVad: tenVad
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createVad(Module, myConfig) {
|
||||||
|
const sileroVad = {
|
||||||
|
model: './silero_vad.onnx',
|
||||||
|
threshold: 0.50,
|
||||||
|
minSilenceDuration: 0.50,
|
||||||
|
minSpeechDuration: 0.25,
|
||||||
|
maxSpeechDuration: 20,
|
||||||
|
windowSize: 512,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tenVad = {
|
||||||
|
model: '',
|
||||||
|
threshold: 0.50,
|
||||||
|
minSilenceDuration: 0.50,
|
||||||
|
minSpeechDuration: 0.25,
|
||||||
|
maxSpeechDuration: 20,
|
||||||
|
windowSize: 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
sileroVad: sileroVad,
|
||||||
|
tenVad: tenVad,
|
||||||
|
sampleRate: 16000,
|
||||||
|
numThreads: 1,
|
||||||
|
provider: 'cpu',
|
||||||
|
debug: 1,
|
||||||
|
bufferSizeInSeconds: 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (myConfig) {
|
||||||
|
config = myConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vad(config, Module);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CircularBuffer {
|
||||||
|
constructor(capacity, Module) {
|
||||||
|
this.handle = Module._SherpaOnnxCreateCircularBuffer(capacity);
|
||||||
|
this.Module = Module;
|
||||||
|
}
|
||||||
|
|
||||||
|
free() {
|
||||||
|
this.Module._SherpaOnnxDestroyCircularBuffer(this.handle);
|
||||||
|
this.handle = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param samples {Float32Array}
|
||||||
|
*/
|
||||||
|
push(samples) {
|
||||||
|
const pointer =
|
||||||
|
this.Module._malloc(samples.length * samples.BYTES_PER_ELEMENT);
|
||||||
|
this.Module.HEAPF32.set(samples, pointer / samples.BYTES_PER_ELEMENT);
|
||||||
|
this.Module._SherpaOnnxCircularBufferPush(
|
||||||
|
this.handle, pointer, samples.length);
|
||||||
|
this.Module._free(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(startIndex, n) {
|
||||||
|
const p =
|
||||||
|
this.Module._SherpaOnnxCircularBufferGet(this.handle, startIndex, n);
|
||||||
|
|
||||||
|
const samplesPtr = p / 4;
|
||||||
|
const samples = new Float32Array(n);
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
samples[i] = this.Module.HEAPF32[samplesPtr + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Module._SherpaOnnxCircularBufferFree(p);
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(n) {
|
||||||
|
this.Module._SherpaOnnxCircularBufferPop(this.handle, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size() {
|
||||||
|
return this.Module._SherpaOnnxCircularBufferSize(this.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
head() {
|
||||||
|
return this.Module._SherpaOnnxCircularBufferHead(this.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.Module._SherpaOnnxCircularBufferReset(this.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Vad {
|
||||||
|
constructor(configObj, Module) {
|
||||||
|
this.config = configObj;
|
||||||
|
const config = initSherpaOnnxVadModelConfig(configObj, Module);
|
||||||
|
const handle = Module._SherpaOnnxCreateVoiceActivityDetector(
|
||||||
|
config.ptr, configObj.bufferSizeInSeconds || 30);
|
||||||
|
freeConfig(config, Module);
|
||||||
|
|
||||||
|
this.handle = handle;
|
||||||
|
this.Module = Module;
|
||||||
|
}
|
||||||
|
|
||||||
|
free() {
|
||||||
|
this.Module._SherpaOnnxDestroyVoiceActivityDetector(this.handle);
|
||||||
|
this.handle = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// samples is a float32 array
|
||||||
|
acceptWaveform(samples) {
|
||||||
|
const pointer =
|
||||||
|
this.Module._malloc(samples.length * samples.BYTES_PER_ELEMENT);
|
||||||
|
this.Module.HEAPF32.set(samples, pointer / samples.BYTES_PER_ELEMENT);
|
||||||
|
this.Module._SherpaOnnxVoiceActivityDetectorAcceptWaveform(
|
||||||
|
this.handle, pointer, samples.length);
|
||||||
|
this.Module._free(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
return this.Module._SherpaOnnxVoiceActivityDetectorEmpty(this.handle) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDetected() {
|
||||||
|
return this.Module._SherpaOnnxVoiceActivityDetectorDetected(this.handle) ==
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop() {
|
||||||
|
this.Module._SherpaOnnxVoiceActivityDetectorPop(this.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.Module._SherpaOnnxVoiceActivityDetectorClear(this.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
samples: a 1-d float32 array,
|
||||||
|
start: an int32
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
front() {
|
||||||
|
const h = this.Module._SherpaOnnxVoiceActivityDetectorFront(this.handle);
|
||||||
|
|
||||||
|
const start = this.Module.HEAP32[h / 4];
|
||||||
|
const samplesPtr = this.Module.HEAP32[h / 4 + 1] / 4;
|
||||||
|
const numSamples = this.Module.HEAP32[h / 4 + 2];
|
||||||
|
|
||||||
|
const samples = new Float32Array(numSamples);
|
||||||
|
for (let i = 0; i < numSamples; i++) {
|
||||||
|
samples[i] = this.Module.HEAPF32[samplesPtr + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Module._SherpaOnnxDestroySpeechSegment(h);
|
||||||
|
return {samples: samples, start: start};
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.Module._SherpaOnnxVoiceActivityDetectorReset(this.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
flush() {
|
||||||
|
this.Module._SherpaOnnxVoiceActivityDetectorFlush(this.handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof process == 'object' && typeof process.versions == 'object' &&
|
||||||
|
typeof process.versions.node == 'string') {
|
||||||
|
module.exports = {
|
||||||
|
createVad,
|
||||||
|
CircularBuffer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.createVad = createVad;
|
||||||
|
window.CircularBuffer = CircularBuffer;
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
+109
-8696
File diff suppressed because one or more lines are too long
+1085
-166
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user