Merge branch 'sweet-lander' into smart-lander
15
.gitignore
vendored
@@ -7,11 +7,20 @@
|
|||||||
**/.idea/
|
**/.idea/
|
||||||
**/html/
|
**/html/
|
||||||
**/.env
|
**/.env
|
||||||
packages/client/public/static/fonts/*
|
|
||||||
|
|
||||||
**/secrets.json
|
**/secrets.json
|
||||||
**/.dev.vars
|
**/.dev.vars
|
||||||
packages/client/public/sitemap.xml
|
|
||||||
packages/client/public/robots.txt
|
|
||||||
wrangler.dev.jsonc
|
wrangler.dev.jsonc
|
||||||
/packages/client/public/static/fonts/
|
/packages/client/public/static/fonts/
|
||||||
|
/packages/client/public/robots.txt
|
||||||
|
/packages/client/public/sitemap.xml
|
||||||
|
/packages/client/public/yachtpit.html
|
||||||
|
/packages/client/public/yachtpit.js
|
||||||
|
/packages/client/public/yachtpit_bg.wasm
|
||||||
|
/packages/client/public/assets/
|
||||||
|
/packages/client/public/apple-touch-icon-180x180.png
|
||||||
|
/packages/client/public/icon.ico
|
||||||
|
/packages/client/public/maskable-icon-512x512.png
|
||||||
|
/packages/client/public/pwa-64x64.png
|
||||||
|
/packages/client/public/pwa-192x192.png
|
||||||
|
/packages/client/public/pwa-512x512.png
|
||||||
|
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "crates/yachtpit"]
|
||||||
|
path = crates/yachtpit
|
||||||
|
url = https://github.com/seemueller-io/yachtpit.git
|
46
bun.lock
@@ -2,6 +2,9 @@
|
|||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/icons": "^2.2.4",
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.2.17",
|
"@types/bun": "^1.2.17",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
||||||
@@ -32,6 +35,7 @@
|
|||||||
"packages/client": {
|
"packages/client": {
|
||||||
"name": "@open-gsio/client",
|
"name": "@open-gsio/client",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@chakra-ui/icons": "^2.2.4",
|
||||||
"@chakra-ui/react": "^2.10.6",
|
"@chakra-ui/react": "^2.10.6",
|
||||||
"@cloudflare/workers-types": "^4.20241205.0",
|
"@cloudflare/workers-types": "^4.20241205.0",
|
||||||
"@emotion/react": "^11.13.5",
|
"@emotion/react": "^11.13.5",
|
||||||
@@ -43,6 +47,7 @@
|
|||||||
"@testing-library/user-event": "^14.5.2",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
"@types/bun": "^1.2.17",
|
"@types/bun": "^1.2.17",
|
||||||
"@types/marked": "^6.0.0",
|
"@types/marked": "^6.0.0",
|
||||||
|
"@vite-pwa/assets-generator": "^1.0.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"@vitest/coverage-v8": "^3.1.4",
|
"@vitest/coverage-v8": "^3.1.4",
|
||||||
"@vitest/ui": "^3.1.4",
|
"@vitest/ui": "^3.1.4",
|
||||||
@@ -61,18 +66,19 @@
|
|||||||
"mobx": "^6.13.5",
|
"mobx": "^6.13.5",
|
||||||
"mobx-react-lite": "^4.0.7",
|
"mobx-react-lite": "^4.0.7",
|
||||||
"mobx-state-tree": "^6.0.1",
|
"mobx-state-tree": "^6.0.1",
|
||||||
"moo": "^0.5.2",
|
|
||||||
"qrcode.react": "^4.1.0",
|
"qrcode.react": "^4.1.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.4.0",
|
"react-icons": "^5.4.0",
|
||||||
"react-streaming": "^0.4.2",
|
"react-streaming": "^0.4.2",
|
||||||
"react-textarea-autosize": "^8.5.5",
|
"react-textarea-autosize": "^8.5.5",
|
||||||
|
"react-use-pwa-install": "^1.0.3",
|
||||||
"shiki": "^1.24.0",
|
"shiki": "^1.24.0",
|
||||||
|
"tslog": "^4.9.3",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.2",
|
||||||
"vike": "^0.4.235",
|
"vike": "^0.4.235",
|
||||||
"vite": "^7.0.0",
|
"vite": "^7.0.0",
|
||||||
"vite-plugin-pwa": "^1.0.0",
|
"vite-plugin-pwa": "^1.0.1",
|
||||||
"vitest": "^3.1.4",
|
"vitest": "^3.1.4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -396,10 +402,14 @@
|
|||||||
|
|
||||||
"@brillout/vite-plugin-server-entry": ["@brillout/vite-plugin-server-entry@0.7.9", "", { "dependencies": { "@brillout/import": "^0.2.6", "@brillout/picocolors": "^1.0.26" } }, "sha512-mJrUakPTj8Zf3Pm4beKmHowfozHOLS/deMqheYYIlqK8FSR4Hd3vMeFQBL/rxLLd+svIlW/j2K3M2SVPDmvX7A=="],
|
"@brillout/vite-plugin-server-entry": ["@brillout/vite-plugin-server-entry@0.7.9", "", { "dependencies": { "@brillout/import": "^0.2.6", "@brillout/picocolors": "^1.0.26" } }, "sha512-mJrUakPTj8Zf3Pm4beKmHowfozHOLS/deMqheYYIlqK8FSR4Hd3vMeFQBL/rxLLd+svIlW/j2K3M2SVPDmvX7A=="],
|
||||||
|
|
||||||
|
"@canvas/image-data": ["@canvas/image-data@1.0.0", "", {}, "sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw=="],
|
||||||
|
|
||||||
"@chakra-ui/anatomy": ["@chakra-ui/anatomy@2.3.6", "", {}, "sha512-TjmjyQouIZzha/l8JxdBZN1pKZTj7sLpJ0YkFnQFyqHcbfWggW9jKWzY1E0VBnhtFz/xF3KC6UAVuZVSJx+y0g=="],
|
"@chakra-ui/anatomy": ["@chakra-ui/anatomy@2.3.6", "", {}, "sha512-TjmjyQouIZzha/l8JxdBZN1pKZTj7sLpJ0YkFnQFyqHcbfWggW9jKWzY1E0VBnhtFz/xF3KC6UAVuZVSJx+y0g=="],
|
||||||
|
|
||||||
"@chakra-ui/hooks": ["@chakra-ui/hooks@2.4.4", "", { "dependencies": { "@chakra-ui/utils": "2.2.4", "@zag-js/element-size": "0.31.1", "copy-to-clipboard": "3.3.3", "framesync": "6.1.2" }, "peerDependencies": { "react": ">=18" } }, "sha512-+gMwLIkabtddIL/GICU7JmnYtvfONP+fNiTfdYLV9/I1eyCz8igKgLmFJOGM6F+BpUev6hh+/+DX5ezGQ9VTbQ=="],
|
"@chakra-ui/hooks": ["@chakra-ui/hooks@2.4.4", "", { "dependencies": { "@chakra-ui/utils": "2.2.4", "@zag-js/element-size": "0.31.1", "copy-to-clipboard": "3.3.3", "framesync": "6.1.2" }, "peerDependencies": { "react": ">=18" } }, "sha512-+gMwLIkabtddIL/GICU7JmnYtvfONP+fNiTfdYLV9/I1eyCz8igKgLmFJOGM6F+BpUev6hh+/+DX5ezGQ9VTbQ=="],
|
||||||
|
|
||||||
|
"@chakra-ui/icons": ["@chakra-ui/icons@2.2.4", "", { "peerDependencies": { "@chakra-ui/react": ">=2.0.0", "react": ">=18" } }, "sha512-l5QdBgwrAg3Sc2BRqtNkJpfuLw/pWRDwwT58J6c4PqQT6wzXxyNa8Q0PForu1ltB5qEiFb1kxr/F/HO1EwNa6g=="],
|
||||||
|
|
||||||
"@chakra-ui/react": ["@chakra-ui/react@2.10.7", "", { "dependencies": { "@chakra-ui/hooks": "2.4.4", "@chakra-ui/styled-system": "2.12.2", "@chakra-ui/theme": "3.4.8", "@chakra-ui/utils": "2.2.4", "@popperjs/core": "^2.11.8", "@zag-js/focus-visible": "^0.31.1", "aria-hidden": "^1.2.3", "react-fast-compare": "3.2.2", "react-focus-lock": "^2.9.6", "react-remove-scroll": "^2.5.7" }, "peerDependencies": { "@emotion/react": ">=11", "@emotion/styled": ">=11", "framer-motion": ">=4.0.0", "react": ">=18", "react-dom": ">=18" } }, "sha512-GX1dCmnvrxxyZEofDX9GMAtRakZJKnUqFM9k8qhaycPaeyfkiTNNTjhPNX917hgVx1yhC3kcJOs5IeC7yW56/g=="],
|
"@chakra-ui/react": ["@chakra-ui/react@2.10.7", "", { "dependencies": { "@chakra-ui/hooks": "2.4.4", "@chakra-ui/styled-system": "2.12.2", "@chakra-ui/theme": "3.4.8", "@chakra-ui/utils": "2.2.4", "@popperjs/core": "^2.11.8", "@zag-js/focus-visible": "^0.31.1", "aria-hidden": "^1.2.3", "react-fast-compare": "3.2.2", "react-focus-lock": "^2.9.6", "react-remove-scroll": "^2.5.7" }, "peerDependencies": { "@emotion/react": ">=11", "@emotion/styled": ">=11", "framer-motion": ">=4.0.0", "react": ">=18", "react-dom": ">=18" } }, "sha512-GX1dCmnvrxxyZEofDX9GMAtRakZJKnUqFM9k8qhaycPaeyfkiTNNTjhPNX917hgVx1yhC3kcJOs5IeC7yW56/g=="],
|
||||||
|
|
||||||
"@chakra-ui/styled-system": ["@chakra-ui/styled-system@2.12.2", "", { "dependencies": { "@chakra-ui/utils": "2.2.4", "csstype": "^3.1.2" } }, "sha512-BlQ7i3+GYC0S0c72B+paa0sYo+QeNSMfz6fwQRFsc8A5Aax9i9lSdRL+vwJVC+k6r/0HWfRwk016R2RD2ihEwQ=="],
|
"@chakra-ui/styled-system": ["@chakra-ui/styled-system@2.12.2", "", { "dependencies": { "@chakra-ui/utils": "2.2.4", "csstype": "^3.1.2" } }, "sha512-BlQ7i3+GYC0S0c72B+paa0sYo+QeNSMfz6fwQRFsc8A5Aax9i9lSdRL+vwJVC+k6r/0HWfRwk016R2RD2ihEwQ=="],
|
||||||
@@ -648,6 +658,8 @@
|
|||||||
|
|
||||||
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
|
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
|
||||||
|
|
||||||
|
"@quansync/fs": ["@quansync/fs@0.1.3", "", { "dependencies": { "quansync": "^0.2.10" } }, "sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg=="],
|
||||||
|
|
||||||
"@rollup/plugin-babel": ["@rollup/plugin-babel@5.3.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.10.4", "@rollup/pluginutils": "^3.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", "rollup": "^1.20.0||^2.0.0" }, "optionalPeers": ["@types/babel__core"] }, "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q=="],
|
"@rollup/plugin-babel": ["@rollup/plugin-babel@5.3.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.10.4", "@rollup/pluginutils": "^3.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", "rollup": "^1.20.0||^2.0.0" }, "optionalPeers": ["@types/babel__core"] }, "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q=="],
|
||||||
|
|
||||||
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@15.3.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA=="],
|
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@15.3.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA=="],
|
||||||
@@ -786,6 +798,8 @@
|
|||||||
|
|
||||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||||
|
|
||||||
|
"@vite-pwa/assets-generator": ["@vite-pwa/assets-generator@1.0.0", "", { "dependencies": { "cac": "^6.7.14", "colorette": "^2.0.20", "consola": "^3.4.2", "sharp": "^0.33.5", "sharp-ico": "^0.1.5", "unconfig": "^7.3.1" }, "bin": { "pwa-assets-generator": "bin/pwa-assets-generator.mjs" } }, "sha512-tWRF/tsqGkND5+dDVnJz7DzQkIRjtTRRYvA3y6l4FwTwK47OK72p1X7ResSz6T7PimIZMuFd+arsB8NRIG+Sww=="],
|
||||||
|
|
||||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
|
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
|
||||||
|
|
||||||
"@vitest/coverage-v8": ["@vitest/coverage-v8@3.1.4", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^1.0.2", "debug": "^4.4.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magic-string": "^0.30.17", "magicast": "^0.3.5", "std-env": "^3.9.0", "test-exclude": "^7.0.1", "tinyrainbow": "^2.0.0" }, "peerDependencies": { "@vitest/browser": "3.1.4", "vitest": "3.1.4" }, "optionalPeers": ["@vitest/browser"] }, "sha512-G4p6OtioySL+hPV7Y6JHlhpsODbJzt1ndwHAFkyk6vVjpK03PFsKnauZIzcd0PrK4zAbc5lc+jeZ+eNGiMA+iw=="],
|
"@vitest/coverage-v8": ["@vitest/coverage-v8@3.1.4", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^1.0.2", "debug": "^4.4.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magic-string": "^0.30.17", "magicast": "^0.3.5", "std-env": "^3.9.0", "test-exclude": "^7.0.1", "tinyrainbow": "^2.0.0" }, "peerDependencies": { "@vitest/browser": "3.1.4", "vitest": "3.1.4" }, "optionalPeers": ["@vitest/browser"] }, "sha512-G4p6OtioySL+hPV7Y6JHlhpsODbJzt1ndwHAFkyk6vVjpK03PFsKnauZIzcd0PrK4zAbc5lc+jeZ+eNGiMA+iw=="],
|
||||||
@@ -920,6 +934,8 @@
|
|||||||
|
|
||||||
"color2k": ["color2k@2.0.3", "", {}, "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog=="],
|
"color2k": ["color2k@2.0.3", "", {}, "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog=="],
|
||||||
|
|
||||||
|
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
|
||||||
|
|
||||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||||
|
|
||||||
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
||||||
@@ -930,6 +946,8 @@
|
|||||||
|
|
||||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||||
|
|
||||||
|
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||||
|
|
||||||
"convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="],
|
"convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="],
|
||||||
|
|
||||||
"cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
|
"cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
|
||||||
@@ -964,6 +982,10 @@
|
|||||||
|
|
||||||
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
|
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
|
||||||
|
|
||||||
|
"decode-bmp": ["decode-bmp@0.2.1", "", { "dependencies": { "@canvas/image-data": "^1.0.0", "to-data-view": "^1.1.0" } }, "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA=="],
|
||||||
|
|
||||||
|
"decode-ico": ["decode-ico@0.4.1", "", { "dependencies": { "@canvas/image-data": "^1.0.0", "decode-bmp": "^0.2.0", "to-data-view": "^1.1.0" } }, "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA=="],
|
||||||
|
|
||||||
"deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
|
"deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
|
||||||
|
|
||||||
"deep-equal": ["deep-equal@2.2.3", "", { "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", "which-typed-array": "^1.1.13" } }, "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA=="],
|
"deep-equal": ["deep-equal@2.2.3", "", { "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", "which-typed-array": "^1.1.13" } }, "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA=="],
|
||||||
@@ -1190,6 +1212,8 @@
|
|||||||
|
|
||||||
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
||||||
|
|
||||||
|
"ico-endec": ["ico-endec@0.1.6", "", {}, "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ=="],
|
||||||
|
|
||||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||||
|
|
||||||
"idb": ["idb@7.1.1", "", {}, "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="],
|
"idb": ["idb@7.1.1", "", {}, "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ=="],
|
||||||
@@ -1298,6 +1322,8 @@
|
|||||||
|
|
||||||
"jake": ["jake@10.9.2", "", { "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", "filelist": "^1.0.4", "minimatch": "^3.1.2" }, "bin": { "jake": "bin/cli.js" } }, "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA=="],
|
"jake": ["jake@10.9.2", "", { "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", "filelist": "^1.0.4", "minimatch": "^3.1.2" }, "bin": { "jake": "bin/cli.js" } }, "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA=="],
|
||||||
|
|
||||||
|
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||||
|
|
||||||
"js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="],
|
"js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="],
|
||||||
|
|
||||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||||
@@ -1538,8 +1564,12 @@
|
|||||||
|
|
||||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||||
|
|
||||||
|
"pwa-install-handler": ["pwa-install-handler@2.6.2", "", {}, "sha512-9hMpqWNxGZx4ZoBe9k9gHkdZC/d/mvMJLA08FCVVMxOhwHBNuQVzb0DwH8ffEaqFvqu7GaotcvYgGNT1yVWduQ=="],
|
||||||
|
|
||||||
"qrcode.react": ["qrcode.react@4.2.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA=="],
|
"qrcode.react": ["qrcode.react@4.2.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA=="],
|
||||||
|
|
||||||
|
"quansync": ["quansync@0.2.10", "", {}, "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A=="],
|
||||||
|
|
||||||
"querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="],
|
"querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="],
|
||||||
|
|
||||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||||
@@ -1572,6 +1602,8 @@
|
|||||||
|
|
||||||
"react-textarea-autosize": ["react-textarea-autosize@8.5.9", "", { "dependencies": { "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A=="],
|
"react-textarea-autosize": ["react-textarea-autosize@8.5.9", "", { "dependencies": { "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A=="],
|
||||||
|
|
||||||
|
"react-use-pwa-install": ["react-use-pwa-install@1.0.3", "", { "dependencies": { "pwa-install-handler": "^2.6.2" }, "peerDependencies": { "react": "18 || 19" } }, "sha512-poF5teATOCblAchP61+Hx/FIQJtSkjGFcZsJjiyXmG9SfmJWkj8M890lXKlu6QPg/bmG6GE3d+KP3aEO9ehgDw=="],
|
||||||
|
|
||||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||||
|
|
||||||
"redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="],
|
"redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="],
|
||||||
@@ -1642,6 +1674,8 @@
|
|||||||
|
|
||||||
"sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
|
"sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
|
||||||
|
|
||||||
|
"sharp-ico": ["sharp-ico@0.1.5", "", { "dependencies": { "decode-ico": "*", "ico-endec": "*", "sharp": "*" } }, "sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q=="],
|
||||||
|
|
||||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
@@ -1750,6 +1784,8 @@
|
|||||||
|
|
||||||
"tldts-core": ["tldts-core@6.1.85", "", {}, "sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA=="],
|
"tldts-core": ["tldts-core@6.1.85", "", {}, "sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA=="],
|
||||||
|
|
||||||
|
"to-data-view": ["to-data-view@1.1.0", "", {}, "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ=="],
|
||||||
|
|
||||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
|
|
||||||
"toggle-selection": ["toggle-selection@1.0.6", "", {}, "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="],
|
"toggle-selection": ["toggle-selection@1.0.6", "", {}, "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="],
|
||||||
@@ -1768,6 +1804,8 @@
|
|||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"tslog": ["tslog@4.9.3", "", {}, "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw=="],
|
||||||
|
|
||||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||||
|
|
||||||
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
|
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
|
||||||
@@ -1786,6 +1824,8 @@
|
|||||||
|
|
||||||
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
||||||
|
|
||||||
|
"unconfig": ["unconfig@7.3.2", "", { "dependencies": { "@quansync/fs": "^0.1.1", "defu": "^6.1.4", "jiti": "^2.4.2", "quansync": "^0.2.8" } }, "sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg=="],
|
||||||
|
|
||||||
"undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
"undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||||
@@ -1844,7 +1884,7 @@
|
|||||||
|
|
||||||
"vite-node": ["vite-node@3.1.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA=="],
|
"vite-node": ["vite-node@3.1.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA=="],
|
||||||
|
|
||||||
"vite-plugin-pwa": ["vite-plugin-pwa@1.0.0", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.3.0", "workbox-window": "^7.3.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-X77jo0AOd5OcxmWj3WnVti8n7Kw2tBgV1c8MCXFclrSlDV23ePzv2eTDIALXI2Qo6nJ5pZJeZAuX0AawvRfoeA=="],
|
"vite-plugin-pwa": ["vite-plugin-pwa@1.0.1", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.3.0", "workbox-window": "^7.3.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-STyUomQbydj7vGamtgQYIJI0YsUZ3T4pJLGBQDQPhzMse6aGSncmEN21OV35PrFsmCvmtiH+Nu1JS1ke4RqBjQ=="],
|
||||||
|
|
||||||
"vitest": ["vitest@3.1.4", "", { "dependencies": { "@vitest/expect": "3.1.4", "@vitest/mocker": "3.1.4", "@vitest/pretty-format": "^3.1.4", "@vitest/runner": "3.1.4", "@vitest/snapshot": "3.1.4", "@vitest/spy": "3.1.4", "@vitest/utils": "3.1.4", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.13", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", "vite-node": "3.1.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.1.4", "@vitest/ui": "3.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ=="],
|
"vitest": ["vitest@3.1.4", "", { "dependencies": { "@vitest/expect": "3.1.4", "@vitest/mocker": "3.1.4", "@vitest/pretty-format": "^3.1.4", "@vitest/runner": "3.1.4", "@vitest/snapshot": "3.1.4", "@vitest/spy": "3.1.4", "@vitest/utils": "3.1.4", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.13", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", "vite-node": "3.1.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.1.4", "@vitest/ui": "3.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ=="],
|
||||||
|
|
||||||
|
1
crates/yachtpit
Submodule
@@ -10,6 +10,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "packages/scripts/cleanup.sh",
|
"clean": "packages/scripts/cleanup.sh",
|
||||||
|
"restore:submodules": "rm -rf crates/yachtpit && (git rm --cached crates/yachtpit) && git submodule add --force https://github.com/seemueller-io/yachtpit.git crates/yachtpit ",
|
||||||
"test:all": "bun run --filter='*' tests",
|
"test:all": "bun run --filter='*' tests",
|
||||||
"client:dev": "(cd packages/client && bun run dev)",
|
"client:dev": "(cd packages/client && bun run dev)",
|
||||||
"server:dev": "bun build:client && (cd packages/server && bun run dev)",
|
"server:dev": "bun build:client && (cd packages/server && bun run dev)",
|
||||||
@@ -41,5 +42,8 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/icons": "^2.2.4"
|
||||||
|
},
|
||||||
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,9 @@
|
|||||||
"tests:coverage": "vitest run --coverage.enabled=true",
|
"tests:coverage": "vitest run --coverage.enabled=true",
|
||||||
"generate:sitemap": "bun ./scripts/generate_sitemap.js open-gsio.seemueller.workers.dev",
|
"generate:sitemap": "bun ./scripts/generate_sitemap.js open-gsio.seemueller.workers.dev",
|
||||||
"generate:robotstxt": "bun ./scripts/generate_robots_txt.js open-gsio.seemueller.workers.dev",
|
"generate:robotstxt": "bun ./scripts/generate_robots_txt.js open-gsio.seemueller.workers.dev",
|
||||||
"generate:fonts": "cp -r ../../node_modules/katex/dist/fonts public/static"
|
"generate:fonts": "cp -r ../../node_modules/katex/dist/fonts public/static",
|
||||||
|
"generate:bevy:bundle": "bun scripts/generate-bevy-bundle.js",
|
||||||
|
"generate:pwa:assets": "test ! -f public/pwa-64x64.png && pwa-assets-generator --preset minimal-2023 public/logo.png || echo 'PWA assets already exist'"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./server/index.ts": {
|
"./server/index.ts": {
|
||||||
@@ -17,19 +19,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@open-gsio/env": "workspace:*",
|
"@chakra-ui/icons": "^2.2.4",
|
||||||
"@open-gsio/scripts": "workspace:*",
|
|
||||||
"@chakra-ui/react": "^2.10.6",
|
"@chakra-ui/react": "^2.10.6",
|
||||||
"@cloudflare/workers-types": "^4.20241205.0",
|
"@cloudflare/workers-types": "^4.20241205.0",
|
||||||
"@emotion/react": "^11.13.5",
|
"@emotion/react": "^11.13.5",
|
||||||
"@emotion/styled": "^11.13.5",
|
"@emotion/styled": "^11.13.5",
|
||||||
|
"@open-gsio/env": "workspace:*",
|
||||||
|
"@open-gsio/scripts": "workspace:*",
|
||||||
"@testing-library/jest-dom": "^6.4.2",
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@testing-library/user-event": "^14.5.2",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
|
"@types/bun": "^1.2.17",
|
||||||
"@types/marked": "^6.0.0",
|
"@types/marked": "^6.0.0",
|
||||||
|
"@vite-pwa/assets-generator": "^1.0.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"@vitest/coverage-v8": "^3.1.4",
|
"@vitest/coverage-v8": "^3.1.4",
|
||||||
"@vitest/ui": "^3.1.4",
|
"@vitest/ui": "^3.1.4",
|
||||||
|
"bun": "^1.2.17",
|
||||||
"chokidar": "^4.0.1",
|
"chokidar": "^4.0.1",
|
||||||
"framer-motion": "^11.13.1",
|
"framer-motion": "^11.13.1",
|
||||||
"isomorphic-dompurify": "^2.19.0",
|
"isomorphic-dompurify": "^2.19.0",
|
||||||
@@ -44,20 +50,19 @@
|
|||||||
"mobx": "^6.13.5",
|
"mobx": "^6.13.5",
|
||||||
"mobx-react-lite": "^4.0.7",
|
"mobx-react-lite": "^4.0.7",
|
||||||
"mobx-state-tree": "^6.0.1",
|
"mobx-state-tree": "^6.0.1",
|
||||||
"moo": "^0.5.2",
|
|
||||||
"qrcode.react": "^4.1.0",
|
"qrcode.react": "^4.1.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.4.0",
|
"react-icons": "^5.4.0",
|
||||||
"react-streaming": "^0.4.2",
|
"react-streaming": "^0.4.2",
|
||||||
"react-textarea-autosize": "^8.5.5",
|
"react-textarea-autosize": "^8.5.5",
|
||||||
|
"react-use-pwa-install": "^1.0.3",
|
||||||
"shiki": "^1.24.0",
|
"shiki": "^1.24.0",
|
||||||
|
"tslog": "^4.9.3",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.2",
|
||||||
"vike": "^0.4.235",
|
"vike": "^0.4.235",
|
||||||
"vite": "^7.0.0",
|
"vite": "^7.0.0",
|
||||||
"vite-plugin-pwa": "^1.0.0",
|
"vite-plugin-pwa": "^1.0.1",
|
||||||
"vitest": "^3.1.4",
|
"vitest": "^3.1.4"
|
||||||
"bun": "^1.2.17",
|
|
||||||
"@types/bun": "^1.2.17"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 638 KiB |
Before Width: | Height: | Size: 563 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 624 B |
Before Width: | Height: | Size: 534 KiB |
BIN
packages/client/public/logo.png
Normal file
After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 373 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 165 KiB |
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "",
|
|
||||||
"short_name": "",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/android-chrome-192x192.png",
|
|
||||||
"sizes": "192x192",
|
|
||||||
"type": "image/png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/android-chrome-512x512.png",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"theme_color": "#fffff0",
|
|
||||||
"background_color": "#000000",
|
|
||||||
"display": "standalone"
|
|
||||||
}
|
|
186
packages/client/scripts/generate-bevy-bundle.js
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
import {
|
||||||
|
existsSync,
|
||||||
|
readdirSync,
|
||||||
|
readFileSync,
|
||||||
|
writeFileSync,
|
||||||
|
renameSync,
|
||||||
|
rmSync,
|
||||||
|
cpSync,
|
||||||
|
statSync,
|
||||||
|
} from 'node:fs';
|
||||||
|
import { resolve, dirname, join, basename } from 'node:path';
|
||||||
|
|
||||||
|
import { Logger } from 'tslog';
|
||||||
|
const logger = new Logger({
|
||||||
|
stdio: 'inherit',
|
||||||
|
prettyLogTimeZone: 'local',
|
||||||
|
type: 'pretty',
|
||||||
|
stylePrettyLogs: true,
|
||||||
|
prefix: ['\n'],
|
||||||
|
overwrite: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
bundleCrate();
|
||||||
|
cleanup();
|
||||||
|
logger.info('🎉 yachtpit built successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRepoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
|
||||||
|
const repoRoot = resolve(getRepoRoot);
|
||||||
|
const publicDir = resolve(repoRoot, 'packages/client/public');
|
||||||
|
const indexHtml = resolve(publicDir, 'index.html');
|
||||||
|
|
||||||
|
function bundleCrate() {
|
||||||
|
// ───────────── Build yachtpit project ───────────────────────────────────
|
||||||
|
logger.info('🔨 Building yachtpit...');
|
||||||
|
|
||||||
|
logger.info(`📁 Repository root: ${repoRoot}`);
|
||||||
|
|
||||||
|
// Check if submodules need to be initialized
|
||||||
|
const yachtpitPath = resolve(repoRoot, 'crates/yachtpit');
|
||||||
|
logger.info(`📁 Yachtpit path: ${yachtpitPath}`);
|
||||||
|
|
||||||
|
if (!existsSync(yachtpitPath)) {
|
||||||
|
logger.info('📦 Initializing submodules...');
|
||||||
|
execSync('git submodule update --init --remote', { stdio: 'inherit' });
|
||||||
|
} else {
|
||||||
|
logger.info(`✅ Submodules already initialized at: ${yachtpitPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the yachtpit project
|
||||||
|
const buildCwd = resolve(repoRoot, 'crates/yachtpit/crates/yachtpit');
|
||||||
|
logger.info(`🔨 Building in directory: ${buildCwd}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
execSync('trunk build --release', {
|
||||||
|
cwd: buildCwd,
|
||||||
|
});
|
||||||
|
logger.info('✅ Yachtpit built');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Failed to build yachtpit:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────── Copy assets to public directory ──────────────────────────
|
||||||
|
const yachtpitDistDir = join(buildCwd, 'dist');
|
||||||
|
|
||||||
|
logger.info(`📋 Copying assets to public directory...`);
|
||||||
|
|
||||||
|
// Remove existing yachtpit assets from public directory
|
||||||
|
const skipRemoveOldAssets = false;
|
||||||
|
|
||||||
|
if (!skipRemoveOldAssets) {
|
||||||
|
const existingAssets = readdirSync(publicDir).filter(
|
||||||
|
file => file.startsWith('yachtpit') && (file.endsWith('.js') || file.endsWith('.wasm')),
|
||||||
|
);
|
||||||
|
|
||||||
|
existingAssets.forEach(asset => {
|
||||||
|
const assetPath = join(publicDir, asset);
|
||||||
|
rmSync(assetPath, { force: true });
|
||||||
|
logger.info(`🗑️ Removed old asset: ${assetPath}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.warn('SKIPPING REMOVING OLD ASSETS');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy new assets from yachtpit/dist to public directory
|
||||||
|
if (existsSync(yachtpitDistDir)) {
|
||||||
|
logger.info(`📍Located yachtpit build: ${yachtpitDistDir}`);
|
||||||
|
try {
|
||||||
|
cpSync(yachtpitDistDir, publicDir, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
logger.info(`✅ Assets copied from ${yachtpitDistDir} to ${publicDir}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Failed to copy assets:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(`❌ Yachtpit dist directory not found at: ${yachtpitDistDir}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────── locate targets ───────────────────────────────────────────
|
||||||
|
const dstPath = join(publicDir, 'yachtpit.html');
|
||||||
|
|
||||||
|
// Regexes for the hashed filenames produced by most bundlers
|
||||||
|
const JS_RE = /^yachtpit-[\da-f]{16}\.js$/i;
|
||||||
|
const WASM_RE = /^yachtpit-[\da-f]{16}_bg\.wasm$/i;
|
||||||
|
|
||||||
|
// Always perform renaming of bundle files
|
||||||
|
const files = readdirSync(publicDir);
|
||||||
|
|
||||||
|
// helper that doesn't explode if the target file is already present
|
||||||
|
const safeRename = (from, to) => {
|
||||||
|
if (!existsSync(from)) return;
|
||||||
|
if (existsSync(to)) {
|
||||||
|
logger.info(`ℹ️ ${to} already exists – removing and replacing.`);
|
||||||
|
rmSync(to, { force: true });
|
||||||
|
}
|
||||||
|
renameSync(from, to);
|
||||||
|
logger.info(`📝 Renamed: ${basename(from)} → ${basename(to)}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
files.forEach(f => {
|
||||||
|
const fullPath = join(publicDir, f);
|
||||||
|
if (JS_RE.test(f)) safeRename(fullPath, join(publicDir, 'yachtpit.js'));
|
||||||
|
if (WASM_RE.test(f)) safeRename(fullPath, join(publicDir, 'yachtpit_bg.wasm'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// ───────────── patch markup inside HTML ─────────────────────────────────
|
||||||
|
if (existsSync(indexHtml)) {
|
||||||
|
logger.info(`📝 Patching HTML file: ${indexHtml}`);
|
||||||
|
let html = readFileSync(indexHtml, 'utf8');
|
||||||
|
|
||||||
|
html = html
|
||||||
|
.replace(/yachtpit-[\da-f]{16}\.js/gi, 'yachtpit.js')
|
||||||
|
.replace(/yachtpit-[\da-f]{16}_bg\.wasm/gi, 'yachtpit_bg.wasm');
|
||||||
|
|
||||||
|
writeFileSync(indexHtml, html, 'utf8');
|
||||||
|
|
||||||
|
// ───────────── rename HTML entrypoint ─────────────────────────────────
|
||||||
|
if (basename(indexHtml) !== 'yachtpit.html') {
|
||||||
|
logger.info(`📝 Renaming HTML file: ${indexHtml} → ${dstPath}`);
|
||||||
|
// Remove existing yachtpit.html if it exists
|
||||||
|
if (existsSync(dstPath)) {
|
||||||
|
rmSync(dstPath, { force: true });
|
||||||
|
}
|
||||||
|
renameSync(indexHtml, dstPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info(`⚠️ ${indexHtml} not found – skipping HTML processing.`);
|
||||||
|
}
|
||||||
|
optimizeWasmSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
function optimizeWasmSize() {
|
||||||
|
logger.info('🔨 Checking WASM size...');
|
||||||
|
|
||||||
|
const wasmPath = resolve(publicDir, 'yachtpit_bg.wasm');
|
||||||
|
const fileSize = statSync(wasmPath).size;
|
||||||
|
const sizeInMb = fileSize / (1024 * 1024);
|
||||||
|
|
||||||
|
if (sizeInMb > 30) {
|
||||||
|
logger.info(`WASM size is ${sizeInMb.toFixed(2)}MB, optimizing...`);
|
||||||
|
execSync(`wasm-opt -Oz -o ${wasmPath} ${wasmPath}`, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
});
|
||||||
|
logger.info(`✅ WASM size optimized`);
|
||||||
|
} else {
|
||||||
|
logger.info(
|
||||||
|
`⏩ Skipping WASM optimization, size (${sizeInMb.toFixed(2)}MB) is under 30MB threshold`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
logger.info('Running cleanup...');
|
||||||
|
rmSync(indexHtml, { force: true });
|
||||||
|
const creditsDir = resolve(`${repoRoot}/packages/client/public`, 'credits');
|
||||||
|
rmSync(creditsDir, { force: true, recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
34
packages/client/src/components/InstallButton.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { IconButton } from '@chakra-ui/react';
|
||||||
|
import { HardDriveDownload } from 'lucide-react';
|
||||||
|
import React from 'react';
|
||||||
|
import { usePWAInstall } from 'react-use-pwa-install';
|
||||||
|
|
||||||
|
import { toolbarButtonZIndex } from './toolbar/Toolbar.tsx';
|
||||||
|
|
||||||
|
function InstallButton() {
|
||||||
|
const install = usePWAInstall();
|
||||||
|
|
||||||
|
// <button onClick={handleInstall}>Install App</button>;
|
||||||
|
return (
|
||||||
|
<IconButton
|
||||||
|
aria-label="Install App"
|
||||||
|
title="Install App"
|
||||||
|
icon={<HardDriveDownload />}
|
||||||
|
size="md"
|
||||||
|
bg="transparent"
|
||||||
|
stroke="text.accent"
|
||||||
|
color="text.accent"
|
||||||
|
onClick={() => install}
|
||||||
|
_hover={{
|
||||||
|
bg: 'transparent',
|
||||||
|
svg: {
|
||||||
|
stroke: 'accent.secondary',
|
||||||
|
transition: 'stroke 0.3s ease-in-out',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
zIndex={toolbarButtonZIndex}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InstallButton;
|
@@ -0,0 +1,50 @@
|
|||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import React, { memo, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
|
export interface BevySceneProps {
|
||||||
|
speed?: number;
|
||||||
|
intensity?: number; // 0-1 when visible
|
||||||
|
glow?: boolean;
|
||||||
|
visible?: boolean; // NEW — defaults to true
|
||||||
|
}
|
||||||
|
|
||||||
|
const BevySceneInner: React.FC<BevySceneProps> = ({
|
||||||
|
speed = 1,
|
||||||
|
intensity = 1,
|
||||||
|
glow = false,
|
||||||
|
visible,
|
||||||
|
}) => {
|
||||||
|
/* initialise once */
|
||||||
|
useEffect(() => {
|
||||||
|
let dispose: (() => void) | void;
|
||||||
|
(async () => {
|
||||||
|
const { default: init } = await import(/* webpackIgnore: true */ '/public/yachtpit.js');
|
||||||
|
dispose = await init(); // zero-arg, uses #yachtpit-canvas
|
||||||
|
})();
|
||||||
|
return () => {
|
||||||
|
if (typeof dispose === 'function') dispose();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/* memoised styles */
|
||||||
|
const wrapperStyles = useMemo(
|
||||||
|
() => ({
|
||||||
|
position: 'absolute' as const,
|
||||||
|
inset: 0,
|
||||||
|
zIndex: 0,
|
||||||
|
opacity: visible ? Math.min(Math.max(intensity, 0), 1) : 0,
|
||||||
|
filter: glow ? 'blur(1px)' : 'none',
|
||||||
|
transition: `opacity ${speed}s ease-in-out`,
|
||||||
|
display: visible ? 'block' : 'none', // optional: reclaim hit-testing entirely
|
||||||
|
}),
|
||||||
|
[visible, intensity, glow, speed],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box as="div" sx={wrapperStyles}>
|
||||||
|
<canvas id="yachtpit-canvas" width={1280} height={720} aria-hidden />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BevyScene = memo(BevySceneInner);
|
@@ -0,0 +1,102 @@
|
|||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
import { BevyScene } from './BevyScene.tsx';
|
||||||
|
import { MatrixRain } from './MatrixRain.tsx';
|
||||||
|
import Particles from './Particles.tsx';
|
||||||
|
import Tweakbox from './Tweakbox.tsx';
|
||||||
|
|
||||||
|
export const LandingComponent: React.FC = () => {
|
||||||
|
const [speed, setSpeed] = useState(0.2);
|
||||||
|
const [intensity, setIntensity] = useState(0.5);
|
||||||
|
const [particles, setParticles] = useState(false);
|
||||||
|
const [glow, setGlow] = useState(false);
|
||||||
|
const [matrixRain, setMatrixRain] = useState(false);
|
||||||
|
const [bevyScene, setBevyScene] = useState(true);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
as="section"
|
||||||
|
bg="background.primary"
|
||||||
|
w="100%"
|
||||||
|
h="100vh"
|
||||||
|
overflow="hidden"
|
||||||
|
position="relative"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
position="fixed"
|
||||||
|
bottom="24px"
|
||||||
|
right="24px"
|
||||||
|
maxWidth="300px"
|
||||||
|
minWidth="200px"
|
||||||
|
zIndex={1000}
|
||||||
|
>
|
||||||
|
<Tweakbox
|
||||||
|
sliders={{
|
||||||
|
speed: {
|
||||||
|
value: !particles ? speed : 0.99,
|
||||||
|
onChange: setSpeed,
|
||||||
|
label: 'Animation Speed',
|
||||||
|
min: 0.01,
|
||||||
|
max: 0.99,
|
||||||
|
step: 0.01,
|
||||||
|
ariaLabel: 'animation-speed',
|
||||||
|
},
|
||||||
|
intensity: {
|
||||||
|
value: !particles ? intensity : 0.99,
|
||||||
|
onChange: setIntensity,
|
||||||
|
label: 'Effect Intensity',
|
||||||
|
min: 0.01,
|
||||||
|
max: 0.99,
|
||||||
|
step: 0.01,
|
||||||
|
ariaLabel: 'effect-intensity',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
switches={{
|
||||||
|
particles: {
|
||||||
|
value: particles,
|
||||||
|
onChange(enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
setMatrixRain(!enabled);
|
||||||
|
setBevyScene(!enabled);
|
||||||
|
}
|
||||||
|
setParticles(enabled);
|
||||||
|
},
|
||||||
|
label: 'Particles',
|
||||||
|
},
|
||||||
|
matrixRain: {
|
||||||
|
value: matrixRain,
|
||||||
|
onChange(enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
setParticles(!enabled);
|
||||||
|
setBevyScene(!enabled);
|
||||||
|
}
|
||||||
|
setMatrixRain(enabled);
|
||||||
|
},
|
||||||
|
label: 'Matrix Rain',
|
||||||
|
},
|
||||||
|
bevyScene: {
|
||||||
|
value: bevyScene,
|
||||||
|
onChange(enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
setParticles(!enabled);
|
||||||
|
setMatrixRain(!enabled);
|
||||||
|
}
|
||||||
|
setBevyScene(enabled);
|
||||||
|
},
|
||||||
|
label: 'Bevy Scene',
|
||||||
|
},
|
||||||
|
glow: {
|
||||||
|
value: glow,
|
||||||
|
onChange: setGlow,
|
||||||
|
label: 'Glow Effect',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<BevyScene speed={speed} intensity={intensity} glow={glow} visible={bevyScene} />
|
||||||
|
<MatrixRain speed={speed} intensity={intensity} glow={glow} visible={matrixRain} />
|
||||||
|
<Particles glow speed={speed} intensity={intensity} visible={particles} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
124
packages/client/src/components/landing-component/MatrixRain.tsx
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import { useBreakpointValue, useTheme } from '@chakra-ui/react';
|
||||||
|
import React, { useEffect, useRef, useMemo } from 'react';
|
||||||
|
|
||||||
|
const MATRIX_CHARS =
|
||||||
|
'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
|
||||||
|
interface MatrixRainProps {
|
||||||
|
speed?: number;
|
||||||
|
glow?: boolean;
|
||||||
|
intensity?: number;
|
||||||
|
visible?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MatrixRain: React.FC<MatrixRainProps> = ({
|
||||||
|
speed = 1,
|
||||||
|
glow = false,
|
||||||
|
intensity = 1,
|
||||||
|
visible,
|
||||||
|
}) => {
|
||||||
|
const fontSize = useBreakpointValue({ base: 14, md: 18, lg: 22 }) ?? 14;
|
||||||
|
const theme = useTheme();
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
|
const animationRef = useRef<number | null>(null);
|
||||||
|
const dropsRef = useRef<number[]>([]);
|
||||||
|
const columnsRef = useRef<number>(0);
|
||||||
|
|
||||||
|
const colors = useMemo(
|
||||||
|
() => ({
|
||||||
|
background: theme.colors.background.primary,
|
||||||
|
textAccent: theme.colors.text.accent,
|
||||||
|
}),
|
||||||
|
[theme.colors.background.primary, theme.colors.text.accent],
|
||||||
|
);
|
||||||
|
|
||||||
|
const colorsRef = useRef(colors);
|
||||||
|
colorsRef.current = colors;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
if (!canvas) return;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const resize = () => {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
|
||||||
|
const newColumns = Math.floor(canvas.width / fontSize);
|
||||||
|
if (newColumns !== columnsRef.current) {
|
||||||
|
columnsRef.current = newColumns;
|
||||||
|
const newDrops: number[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < newColumns; i++) {
|
||||||
|
if (i < dropsRef.current.length) {
|
||||||
|
newDrops[i] = dropsRef.current[i];
|
||||||
|
} else {
|
||||||
|
newDrops[i] = Math.random() * (canvas.height / fontSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dropsRef.current = newDrops;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
resize();
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
|
||||||
|
if (dropsRef.current.length === 0) {
|
||||||
|
const columns = Math.floor(canvas.width / fontSize);
|
||||||
|
columnsRef.current = columns;
|
||||||
|
|
||||||
|
for (let i = 0; i < columns; i++) {
|
||||||
|
dropsRef.current[i] = Math.random() * (canvas.height / fontSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const draw = () => {
|
||||||
|
if (!ctx || !canvas) return;
|
||||||
|
|
||||||
|
const currentColors = colorsRef.current;
|
||||||
|
|
||||||
|
ctx.fillStyle = currentColors.background;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
ctx.font = `${fontSize}px monospace`;
|
||||||
|
|
||||||
|
for (let i = 0; i < dropsRef.current.length; i++) {
|
||||||
|
const text = MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)];
|
||||||
|
const x = i * fontSize;
|
||||||
|
const y = dropsRef.current[i] * fontSize;
|
||||||
|
|
||||||
|
ctx.fillStyle = currentColors.textAccent;
|
||||||
|
if (glow) {
|
||||||
|
ctx.shadowBlur = 10;
|
||||||
|
ctx.shadowColor = currentColors.textAccent;
|
||||||
|
}
|
||||||
|
ctx.fillText(text, x, y);
|
||||||
|
|
||||||
|
if (y > canvas.height) {
|
||||||
|
dropsRef.current[i] = -Math.random() * 5;
|
||||||
|
} else {
|
||||||
|
dropsRef.current[i] += (0.1 + Math.random() * 0.5) * speed * intensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animationRef.current = requestAnimationFrame(draw);
|
||||||
|
};
|
||||||
|
|
||||||
|
animationRef.current = requestAnimationFrame(draw);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', resize);
|
||||||
|
if (animationRef.current) {
|
||||||
|
cancelAnimationFrame(animationRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [fontSize, speed, glow, intensity, visible]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef}
|
||||||
|
style={{ display: visible ? 'block' : 'none', pointerEvents: 'none' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
162
packages/client/src/components/landing-component/Particles.tsx
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import { Box, useTheme } from '@chakra-ui/react';
|
||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
interface ParticlesProps {
|
||||||
|
speed: number;
|
||||||
|
intensity: number;
|
||||||
|
particles: boolean;
|
||||||
|
glow: boolean;
|
||||||
|
visible?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Particle {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
vx: number;
|
||||||
|
vy: number;
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Particles: React.FC<ParticlesProps> = ({ speed, intensity, glow, visible }) => {
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
const particlesRef = useRef<Particle[]>([]);
|
||||||
|
const animationFrameRef = useRef<number | undefined>(undefined);
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
// Helper function to create a single particle with proper canvas dimensions
|
||||||
|
const createParticle = (canvas: HTMLCanvasElement): Particle => ({
|
||||||
|
x: Math.random() * canvas.parentElement!.getBoundingClientRect().width,
|
||||||
|
y: Math.random() * canvas.parentElement!.getBoundingClientRect().height,
|
||||||
|
vx: (Math.random() - 0.5) * speed,
|
||||||
|
vy: (Math.random() - 0.5) * speed,
|
||||||
|
size: Math.random() * 3 + 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Main animation effect
|
||||||
|
useEffect(() => {
|
||||||
|
if (!visible) {
|
||||||
|
if (animationFrameRef.current) {
|
||||||
|
cancelAnimationFrame(animationFrameRef.current);
|
||||||
|
animationFrameRef.current = undefined;
|
||||||
|
}
|
||||||
|
particlesRef.current = []; // Clear particles when disabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const resizeCanvas = () => {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
|
||||||
|
// Reposition existing particles that are outside new bounds
|
||||||
|
particlesRef.current.forEach(particle => {
|
||||||
|
if (particle.x > canvas.width) particle.x = Math.random() * canvas.width;
|
||||||
|
if (particle.y > canvas.height) particle.y = Math.random() * canvas.height;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const ensureParticleCount = () => {
|
||||||
|
const targetCount = Math.floor(intensity * 100);
|
||||||
|
const currentCount = particlesRef.current.length;
|
||||||
|
|
||||||
|
if (currentCount < targetCount) {
|
||||||
|
// Add new particles
|
||||||
|
const newParticles = Array.from({ length: targetCount - currentCount }, () =>
|
||||||
|
createParticle(canvas),
|
||||||
|
);
|
||||||
|
particlesRef.current = [...particlesRef.current, ...newParticles];
|
||||||
|
} else if (currentCount > targetCount) {
|
||||||
|
// Remove excess particles
|
||||||
|
particlesRef.current = particlesRef.current.slice(0, targetCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateParticles = () => {
|
||||||
|
particlesRef.current.forEach(particle => {
|
||||||
|
particle.x += particle.vx;
|
||||||
|
particle.y += particle.vy;
|
||||||
|
|
||||||
|
if (particle.x < 0) particle.x = canvas.width;
|
||||||
|
if (particle.x > canvas.width) particle.x = 0;
|
||||||
|
if (particle.y < 0) particle.y = canvas.height;
|
||||||
|
if (particle.y > canvas.height) particle.y = 0;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const drawParticles = () => {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillStyle = theme.colors.text.accent;
|
||||||
|
ctx.globalCompositeOperation = 'lighter';
|
||||||
|
|
||||||
|
if (glow) {
|
||||||
|
ctx.shadowBlur = 10;
|
||||||
|
ctx.shadowColor = 'white';
|
||||||
|
} else {
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
particlesRef.current.forEach(particle => {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const animate = () => {
|
||||||
|
updateParticles();
|
||||||
|
drawParticles();
|
||||||
|
animationFrameRef.current = requestAnimationFrame(animate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
resizeCanvas();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
resizeCanvas(); // Set canvas size first
|
||||||
|
ensureParticleCount(); // Then create particles with proper dimensions
|
||||||
|
animate();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
if (animationFrameRef.current) {
|
||||||
|
cancelAnimationFrame(animationFrameRef.current);
|
||||||
|
animationFrameRef.current = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [visible, intensity, speed, glow, theme.colors.text.accent]);
|
||||||
|
|
||||||
|
// Separate effect for speed changes - update existing particle velocities
|
||||||
|
useEffect(() => {
|
||||||
|
if (!visible) return;
|
||||||
|
|
||||||
|
particlesRef.current.forEach(particle => {
|
||||||
|
const currentSpeed = Math.sqrt(particle.vx * particle.vx + particle.vy * particle.vy);
|
||||||
|
if (currentSpeed > 0) {
|
||||||
|
const normalizedVx = particle.vx / currentSpeed;
|
||||||
|
const normalizedVy = particle.vy / currentSpeed;
|
||||||
|
particle.vx = normalizedVx * speed;
|
||||||
|
particle.vy = normalizedVy * speed;
|
||||||
|
} else {
|
||||||
|
particle.vx = (Math.random() - 0.5) * speed;
|
||||||
|
particle.vy = (Math.random() - 0.5) * speed;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [speed, visible]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box zIndex={0} pointerEvents={'none'}>
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef}
|
||||||
|
style={{ display: visible ? 'block' : 'none', pointerEvents: 'none' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Particles;
|
111
packages/client/src/components/landing-component/Tweakbox.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Grid,
|
||||||
|
GridItem,
|
||||||
|
Heading,
|
||||||
|
Slider,
|
||||||
|
SliderTrack,
|
||||||
|
SliderFilledTrack,
|
||||||
|
SliderThumb,
|
||||||
|
Text,
|
||||||
|
Switch,
|
||||||
|
Collapse,
|
||||||
|
IconButton,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
|
||||||
|
import { observer } from 'mobx-react-lite';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
interface SliderControl {
|
||||||
|
value: number;
|
||||||
|
onChange: (value: number) => void;
|
||||||
|
label: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
step: number;
|
||||||
|
ariaLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SwitchControl {
|
||||||
|
value: boolean;
|
||||||
|
onChange: (enabled: boolean) => void;
|
||||||
|
label: string;
|
||||||
|
exclusive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TweakboxProps {
|
||||||
|
sliders: {
|
||||||
|
speed: SliderControl;
|
||||||
|
intensity: SliderControl;
|
||||||
|
};
|
||||||
|
switches: {
|
||||||
|
particles: SwitchControl;
|
||||||
|
glow: SwitchControl;
|
||||||
|
} & Record<string, SwitchControl>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tweakbox = observer(({ sliders, switches }: TweakboxProps) => {
|
||||||
|
const [isCollapsed, setIsCollapsed] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box display="flex" alignItems="flex-start">
|
||||||
|
<IconButton
|
||||||
|
aria-label="Toggle controls"
|
||||||
|
borderRadius="lg"
|
||||||
|
bg="whiteAlpha.300"
|
||||||
|
backdropFilter="blur(10px)"
|
||||||
|
boxShadow="xl"
|
||||||
|
icon={isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
||||||
|
onClick={() => setIsCollapsed(!isCollapsed)}
|
||||||
|
size="sm"
|
||||||
|
marginRight={2}
|
||||||
|
/>
|
||||||
|
<Collapse in={!isCollapsed} style={{ width: '100%' }}>
|
||||||
|
<Box p={4} borderRadius="lg" bg="whiteAlpha.100" backdropFilter="blur(10px)" boxShadow="xl">
|
||||||
|
<Grid templateColumns="1fr" gap={4}>
|
||||||
|
<GridItem>
|
||||||
|
<Heading hidden={true} size="sm" mb={4} color="text.accent">
|
||||||
|
Controls
|
||||||
|
</Heading>
|
||||||
|
</GridItem>
|
||||||
|
{Object.keys(switches).map(key => {
|
||||||
|
return (
|
||||||
|
<GridItem key={key}>
|
||||||
|
<Text mb={2} color="text.accent">
|
||||||
|
{switches[key].label}
|
||||||
|
</Text>
|
||||||
|
<Switch
|
||||||
|
isChecked={switches[key].value}
|
||||||
|
onChange={e => switches[key].onChange(e.target.checked)}
|
||||||
|
/>
|
||||||
|
</GridItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{Object.entries(sliders).map(([key, slider]) => (
|
||||||
|
<GridItem key={key}>
|
||||||
|
<Text mb={2} color="text.accent">
|
||||||
|
{slider.label}
|
||||||
|
</Text>
|
||||||
|
<Slider
|
||||||
|
aria-label={slider.ariaLabel}
|
||||||
|
value={slider.value}
|
||||||
|
min={slider.min}
|
||||||
|
step={slider.step}
|
||||||
|
max={slider.max}
|
||||||
|
onChange={slider.onChange}
|
||||||
|
>
|
||||||
|
<SliderTrack>
|
||||||
|
<SliderFilledTrack />
|
||||||
|
</SliderTrack>
|
||||||
|
<SliderThumb />
|
||||||
|
</Slider>
|
||||||
|
</GridItem>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Collapse>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Tweakbox;
|
@@ -2,6 +2,7 @@ import { Flex } from '@chakra-ui/react';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import BuiltWithButton from '../BuiltWithButton';
|
import BuiltWithButton from '../BuiltWithButton';
|
||||||
|
import InstallButton from '../InstallButton.tsx';
|
||||||
|
|
||||||
import GithubButton from './GithubButton';
|
import GithubButton from './GithubButton';
|
||||||
import SupportThisSiteButton from './SupportThisSiteButton';
|
import SupportThisSiteButton from './SupportThisSiteButton';
|
||||||
@@ -17,6 +18,7 @@ function ToolBar({ isMobile }) {
|
|||||||
alignItems={isMobile ? 'flex-start' : 'flex-end'}
|
alignItems={isMobile ? 'flex-start' : 'flex-end'}
|
||||||
pb={4}
|
pb={4}
|
||||||
>
|
>
|
||||||
|
<InstallButton />
|
||||||
<SupportThisSiteButton />
|
<SupportThisSiteButton />
|
||||||
<GithubButton />
|
<GithubButton />
|
||||||
<BuiltWithButton />
|
<BuiltWithButton />
|
||||||
|
@@ -17,9 +17,9 @@ export default function Hero() {
|
|||||||
minWidth="90px"
|
minWidth="90px"
|
||||||
maxWidth={'220px'}
|
maxWidth={'220px'}
|
||||||
color="text.accent"
|
color="text.accent"
|
||||||
as="h3"
|
// as="h3"
|
||||||
letterSpacing={'tight'}
|
letterSpacing={'tight'}
|
||||||
size="lg"
|
size="xl"
|
||||||
>
|
>
|
||||||
{Routes[normalizePath(pageContext.urlPathname)]?.heroLabel}
|
{Routes[normalizePath(pageContext.urlPathname)]?.heroLabel}
|
||||||
</Heading>
|
</Heading>
|
||||||
|
@@ -5,7 +5,7 @@ function NavItem({ path, children, color, onClick, as, cursor }) {
|
|||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
as={as ?? 'a'}
|
as={as ?? 'a'}
|
||||||
href={path}
|
href={path && path.length > 1 ? path : '/'}
|
||||||
mb={2}
|
mb={2}
|
||||||
cursor={cursor}
|
cursor={cursor}
|
||||||
// ml={5}
|
// ml={5}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Box, Collapse, Grid, GridItem, useBreakpointValue } from '@chakra-ui/react';
|
import { Box, Collapse, Grid, GridItem, useBreakpointValue, useTheme } from '@chakra-ui/react';
|
||||||
import { MenuIcon } from 'lucide-react';
|
import { MenuIcon } from 'lucide-react';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
@@ -18,6 +18,8 @@ const Navigation = observer(({ children, routeRegistry }) => {
|
|||||||
|
|
||||||
const currentPath = pageContext.urlPathname || '/';
|
const currentPath = pageContext.urlPathname || '/';
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const getTopValue = () => {
|
const getTopValue = () => {
|
||||||
if (!isMobile) return undefined;
|
if (!isMobile) return undefined;
|
||||||
if (currentPath === '/') return 12;
|
if (currentPath === '/') return 12;
|
||||||
@@ -53,9 +55,10 @@ const Navigation = observer(({ children, routeRegistry }) => {
|
|||||||
<GridItem>
|
<GridItem>
|
||||||
<MenuIcon
|
<MenuIcon
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
|
color="text.accent"
|
||||||
w={6}
|
w={6}
|
||||||
h={6}
|
h={6}
|
||||||
stroke={getTheme(userOptionsStore.theme).colors.text.accent}
|
stroke={theme.colors.text.accent}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
switch (menuState.isOpen) {
|
switch (menuState.isOpen) {
|
||||||
case true:
|
case true:
|
||||||
|
@@ -15,8 +15,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
background: {
|
background: {
|
||||||
primary: 'linear-gradient(360deg, #15171C 100%, #353A47 100%)',
|
// primary: 'linear-gradient(360deg, #15171C 100%, #353A47 100%)',
|
||||||
|
primary: '#15171C',
|
||||||
secondary: '#1B1F26',
|
secondary: '#1B1F26',
|
||||||
tertiary: '#1E1E2E',
|
tertiary: '#1E1E2E',
|
||||||
},
|
},
|
||||||
|
@@ -2,3 +2,20 @@
|
|||||||
import UserOptionsStore from '../stores/UserOptionsStore';
|
import UserOptionsStore from '../stores/UserOptionsStore';
|
||||||
|
|
||||||
UserOptionsStore.initialize();
|
UserOptionsStore.initialize();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const isLocal = window.location.hostname.includes('localhost');
|
||||||
|
if (!isLocal) {
|
||||||
|
navigator.serviceWorker.register('/service-worker.js');
|
||||||
|
} else {
|
||||||
|
(async () => {
|
||||||
|
await navigator.serviceWorker.getRegistrations().then(registrations => {
|
||||||
|
registrations.map(r => {
|
||||||
|
r.unregister();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// fail silent
|
||||||
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Stack } from '@chakra-ui/react';
|
import { Stack } from '@chakra-ui/react';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
import Chat from '../../components/chat/Chat';
|
import { LandingComponent } from '../../components/landing-component/LandingComponent.tsx';
|
||||||
import clientChatStore from '../../stores/ClientChatStore';
|
import clientChatStore from '../../stores/ClientChatStore';
|
||||||
|
|
||||||
// renders "/"
|
// renders "/"
|
||||||
@@ -18,7 +18,8 @@ export default function IndexPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack direction="column" height="100%" width="100%" spacing={0}>
|
<Stack direction="column" height="100%" width="100%" spacing={0}>
|
||||||
<Chat height="100%" width="100%" />
|
<LandingComponent />
|
||||||
|
{/*<Chat height="100%" width="100%" />*/}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -28,10 +28,9 @@ const onRenderHtml: OnRenderHtmlAsync = async (pageContext): ReturnType<OnRender
|
|||||||
<html data-theme="dark" lang="en">
|
<html data-theme="dark" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>open-gsio</title>
|
<title>open-gsio</title>
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
<link rel="icon" href="/favicon.ico" sizes="48x48">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
<link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png">
|
||||||
<link rel="manifest" href="/site.webmanifest">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="description" content="Maker Site">
|
<meta name="description" content="Maker Site">
|
||||||
|
@@ -7,20 +7,36 @@ import { VitePWA } from 'vite-plugin-pwa';
|
|||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import { configDefaults } from 'vitest/config';
|
import { configDefaults } from 'vitest/config';
|
||||||
|
|
||||||
|
import { getColorThemes } from './src/layout/theme/color-themes';
|
||||||
|
|
||||||
const prebuildPlugin = () => ({
|
const prebuildPlugin = () => ({
|
||||||
name: 'prebuild',
|
name: 'prebuild',
|
||||||
config(config, { command }) {
|
config(config, { command }) {
|
||||||
if (command === 'build') {
|
if (command === 'build') {
|
||||||
|
console.log('Generate PWA Assets -> public/');
|
||||||
|
child_process.execSync('bun generate:pwa:assets');
|
||||||
|
console.log('Generated Sitemap -> public/sitemap.xml');
|
||||||
child_process.execSync('bun generate:sitemap');
|
child_process.execSync('bun generate:sitemap');
|
||||||
console.log('Generated Sitemap -> public/sitemap.xml');
|
console.log('Generated Sitemap -> public/sitemap.xml');
|
||||||
child_process.execSync('bun run generate:robotstxt');
|
child_process.execSync('bun run generate:robotstxt');
|
||||||
console.log('Generated robots.txt -> public/robots.txt');
|
console.log('Generated robots.txt -> public/robots.txt');
|
||||||
child_process.execSync('bun run generate:fonts');
|
child_process.execSync('bun run generate:fonts');
|
||||||
console.log('Copied fonts -> public/static/fonts');
|
console.log('Copied fonts -> public/static/fonts');
|
||||||
|
child_process.execSync('bun run generate:bevy:bundle', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
console.log('Bundled bevy app -> public/yachtpit.html');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
// const PROJECT_SOURCES_HASH = sha512Dir('./src');
|
||||||
|
//
|
||||||
|
// console.log({ PROJECT_SOURCES_HASH });
|
||||||
|
|
||||||
|
const buildId = crypto.randomUUID();
|
||||||
|
|
||||||
export default defineConfig(({ command }) => {
|
export default defineConfig(({ command }) => {
|
||||||
return {
|
return {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
@@ -31,6 +47,62 @@ export default defineConfig(({ command }) => {
|
|||||||
prerender: true,
|
prerender: true,
|
||||||
disableAutoFullBuild: false,
|
disableAutoFullBuild: false,
|
||||||
}),
|
}),
|
||||||
|
VitePWA({
|
||||||
|
registerType: 'autoUpdate',
|
||||||
|
injectRegister: null,
|
||||||
|
minify: true,
|
||||||
|
disable: false,
|
||||||
|
filename: 'service-worker.js',
|
||||||
|
devOptions: {
|
||||||
|
enabled: false,
|
||||||
|
navigateFallback: 'index.html',
|
||||||
|
suppressWarnings: true,
|
||||||
|
type: 'module',
|
||||||
|
},
|
||||||
|
manifest: {
|
||||||
|
name: `open-gsio`,
|
||||||
|
short_name: 'open-gsio',
|
||||||
|
display: 'standalone',
|
||||||
|
description: `open-gsio client`,
|
||||||
|
theme_color: getColorThemes().at(0)?.colors.text.accent,
|
||||||
|
background_color: getColorThemes().at(0)?.colors.background.primary,
|
||||||
|
scope: '/',
|
||||||
|
start_url: '/',
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
src: 'pwa-64x64.png',
|
||||||
|
sizes: '64x64',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'pwa-192x192.png',
|
||||||
|
sizes: '192x192',
|
||||||
|
type: 'image/png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'pwa-512x512.png',
|
||||||
|
sizes: '512x512',
|
||||||
|
type: 'image/png',
|
||||||
|
purpose: 'any',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'maskable-icon-512x512.png',
|
||||||
|
sizes: '512x512',
|
||||||
|
type: 'image/png',
|
||||||
|
purpose: 'maskable',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
workbox: {
|
||||||
|
globPatterns: ['**/*.{js,css,html,ico,png,svg,wasm}'],
|
||||||
|
navigateFallbackDenylist: [/^\/api\//],
|
||||||
|
maximumFileSizeToCacheInBytes: 25000000,
|
||||||
|
cacheId: buildId,
|
||||||
|
cleanupOutdatedCaches: true,
|
||||||
|
clientsClaim: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
// PWA plugin saves money on data transfer by caching assets on the client
|
// PWA plugin saves money on data transfer by caching assets on the client
|
||||||
/*
|
/*
|
||||||
For safari, use this script in the console to unregister the service worker.
|
For safari, use this script in the console to unregister the service worker.
|
||||||
@@ -41,22 +113,15 @@ export default defineConfig(({ command }) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
// VitePWA({
|
|
||||||
// registerType: 'autoUpdate',
|
|
||||||
// devOptions: {
|
|
||||||
// enabled: false,
|
|
||||||
// },
|
|
||||||
// manifest: {
|
|
||||||
// name: "open-gsio",
|
|
||||||
// short_name: "open-gsio",
|
|
||||||
// description: "Assistant"
|
|
||||||
// },
|
|
||||||
// workbox: {
|
|
||||||
// globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
|
||||||
// navigateFallbackDenylist: [/^\/api\//],
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
],
|
],
|
||||||
|
workbox: {
|
||||||
|
globPatterns: ['**/*.{js,css,html,ico,png,svg,wasm}'],
|
||||||
|
navigateFallbackDenylist: [/^\/api\//],
|
||||||
|
maximumFileSizeToCacheInBytes: 25000000,
|
||||||
|
cacheId: buildId,
|
||||||
|
cleanupOutdatedCaches: true,
|
||||||
|
clientsClaim: true,
|
||||||
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { ServerCoordinator } from '@open-gsio/coordinators';
|
import { ServerCoordinator } from '@open-gsio/coordinators';
|
||||||
import Router from '@open-gsio/router';
|
import Router from '@open-gsio/router';
|
||||||
|
import { error } from 'itty-router';
|
||||||
|
|
||||||
export { ServerCoordinator };
|
export { ServerCoordinator };
|
||||||
|
|
||||||
export default Router.Router();
|
export default Router.Router().catch(error);
|
||||||
|
@@ -20,9 +20,10 @@
|
|||||||
{
|
{
|
||||||
"binding": "KV_STORAGE",
|
"binding": "KV_STORAGE",
|
||||||
// $ npx wrangler kv namespace create open-gsio
|
// $ npx wrangler kv namespace create open-gsio
|
||||||
|
// $ npx wrangler kv namespace create open-gsio
|
||||||
"id": "placeholderId",
|
"id": "placeholderId",
|
||||||
// $ npx wrangler kv namespace create open-gsio --preview
|
// $ npx wrangler kv namespace create open-gsio --preview
|
||||||
"preview_id": "placeholderIdPreview"
|
"preview_id": "placeholderId"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"migrations": [
|
"migrations": [
|
||||||
|
@@ -52,13 +52,15 @@ export function createRouter() {
|
|||||||
// })
|
// })
|
||||||
|
|
||||||
.get('/api/metrics*', async (r, e, c) => {
|
.get('/api/metrics*', async (r, e, c) => {
|
||||||
const { metricsService } = createRequestContext(e, c);
|
return new Response('ok');
|
||||||
return metricsService.handleMetricsRequest(r);
|
// const { metricsService } = createRequestContext(e, c);
|
||||||
|
// return metricsService.handleMetricsRequest(r);
|
||||||
})
|
})
|
||||||
|
|
||||||
.post('/api/metrics*', async (r, e, c) => {
|
.post('/api/metrics*', async (r, e, c) => {
|
||||||
const { metricsService } = createRequestContext(e, c);
|
return new Response('ok');
|
||||||
return metricsService.handleMetricsRequest(r);
|
// const { metricsService } = createRequestContext(e, c);
|
||||||
|
// return metricsService.handleMetricsRequest(r);
|
||||||
})
|
})
|
||||||
|
|
||||||
// renders the app
|
// renders the app
|
||||||
|
@@ -15,7 +15,12 @@ find . -name ".wrangler" -type d -prune -exec rm -rf {} \;
|
|||||||
|
|
||||||
# Remove build directories
|
# Remove build directories
|
||||||
find . -name "dist" -type d -prune -exec rm -rf {} \;
|
find . -name "dist" -type d -prune -exec rm -rf {} \;
|
||||||
find . -name "build" -type d -prune -exec rm -rf {} \;
|
|
||||||
|
|
||||||
|
#-----
|
||||||
|
# crates/yachtpit uses a directory called build for staging assets so it can't be removed
|
||||||
|
#find . -name "build" -type d -prune -exec rm -rf {} \;
|
||||||
|
#-----
|
||||||
|
|
||||||
find . -name "fonts" -type d -prune -exec rm -rf {} \;
|
find . -name "fonts" -type d -prune -exec rm -rf {} \;
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import ServerCoordinator from '@open-gsio/coordinators/src/ServerCoordinatorBun.
|
|||||||
import Router from '@open-gsio/router';
|
import Router from '@open-gsio/router';
|
||||||
import { config } from 'dotenv';
|
import { config } from 'dotenv';
|
||||||
import type { RequestLike } from 'itty-router';
|
import type { RequestLike } from 'itty-router';
|
||||||
|
import { error } from 'itty-router';
|
||||||
|
|
||||||
import { BunSqliteKVNamespace } from '../storage/BunSqliteKVNamespace.ts';
|
import { BunSqliteKVNamespace } from '../storage/BunSqliteKVNamespace.ts';
|
||||||
|
|
||||||
@@ -49,8 +50,7 @@ export default {
|
|||||||
reject(new Error('Request timeout after 5s'));
|
reject(new Error('Request timeout after 5s'));
|
||||||
}, 5000),
|
}, 5000),
|
||||||
);
|
);
|
||||||
|
return await Promise.race([router.fetch(request, env, ctx).catch(error), timeout]);
|
||||||
return await Promise.race([router.fetch(request, env, ctx), timeout]);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error handling request:', e);
|
console.error('Error handling request:', e);
|
||||||
return new Response('Server Error', { status: 500 });
|
return new Response('Server Error', { status: 500 });
|
||||||
|