feat: enhance WebSocket proxy with user connection management and status reporting

- Updated StudioOpts type to include infoList for user connection status.
- Added rendering of connection info in createStudioAppListHtml.
- Modified self-restart logic to use a specific app path.
- Improved WebSocket connection handling in wsProxyManager, including user registration and ID management.
- Implemented connection status checks and responses in UserV1Proxy.
- Introduced renderServerHtml function to inject server data into HTML responses.
- Refactored page-proxy request handling for better URL management.
This commit is contained in:
2026-03-05 03:58:46 +08:00
parent aaedcb881b
commit bbdf9f087d
9 changed files with 451 additions and 270 deletions

View File

@@ -40,7 +40,7 @@
],
"license": "UNLICENSED",
"dependencies": {
"@kevisual/ai": "^0.0.24",
"@kevisual/ai": "^0.0.26",
"@kevisual/auth": "^2.0.3",
"@kevisual/js-filter": "^0.0.5",
"@kevisual/query": "^0.0.52",
@@ -58,7 +58,7 @@
"xml2js": "^0.6.2"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.1000.0",
"@aws-sdk/client-s3": "^3.1001.0",
"@kevisual/api": "^0.0.60",
"@kevisual/cnb": "^0.0.33",
"@kevisual/context": "^0.0.8",
@@ -67,11 +67,11 @@
"@kevisual/logger": "^0.0.4",
"@kevisual/oss": "0.0.20",
"@kevisual/permission": "^0.0.4",
"@kevisual/router": "0.0.84",
"@kevisual/router": "0.0.85",
"@kevisual/types": "^0.0.12",
"@kevisual/use-config": "^1.0.30",
"@types/archiver": "^7.0.0",
"@types/bun": "^1.3.9",
"@types/bun": "^1.3.10",
"@types/crypto-js": "^4.2.2",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^25.3.3",
@@ -83,7 +83,7 @@
"crypto-js": "^4.2.0",
"dayjs": "^1.11.19",
"dotenv": "^17.3.1",
"es-toolkit": "^1.44.0",
"es-toolkit": "^1.45.1",
"ioredis": "^5.10.0",
"jsonwebtoken": "^9.0.3",
"nanoid": "^5.1.6",

422
pnpm-lock.yaml generated
View File

@@ -14,8 +14,8 @@ importers:
.:
dependencies:
'@kevisual/ai':
specifier: ^0.0.24
version: 0.0.24
specifier: ^0.0.26
version: 0.0.26
'@kevisual/auth':
specifier: ^2.0.3
version: 2.0.3
@@ -45,10 +45,10 @@ importers:
version: 0.31.9
drizzle-orm:
specifier: ^0.45.1
version: 0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.9)(pg@8.19.0)
version: 0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.10)(pg@8.19.0)
drizzle-zod:
specifier: ^0.8.3
version: 0.8.3(drizzle-orm@0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.9)(pg@8.19.0))(zod@4.3.6)
version: 0.8.3(drizzle-orm@0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.10)(pg@8.19.0))(zod@4.3.6)
eventemitter3:
specifier: ^5.0.4
version: 5.0.4
@@ -63,8 +63,8 @@ importers:
version: 0.6.2
devDependencies:
'@aws-sdk/client-s3':
specifier: ^3.1000.0
version: 3.1000.0
specifier: ^3.1001.0
version: 3.1001.0
'@kevisual/api':
specifier: ^0.0.60
version: 0.0.60(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -90,8 +90,8 @@ importers:
specifier: ^0.0.4
version: 0.0.4
'@kevisual/router':
specifier: 0.0.84
version: 0.0.84
specifier: 0.0.85
version: 0.0.85
'@kevisual/types':
specifier: ^0.0.12
version: 0.0.12
@@ -102,8 +102,8 @@ importers:
specifier: ^7.0.0
version: 7.0.0
'@types/bun':
specifier: ^1.3.9
version: 1.3.9
specifier: ^1.3.10
version: 1.3.10
'@types/crypto-js':
specifier: ^4.2.2
version: 4.2.2
@@ -138,8 +138,8 @@ importers:
specifier: ^17.3.1
version: 17.3.1
es-toolkit:
specifier: ^1.44.0
version: 1.44.0
specifier: ^1.45.1
version: 1.45.1
ioredis:
specifier: ^5.9.3
version: 5.9.3
@@ -218,48 +218,48 @@ packages:
'@aws-crypto/util@5.2.0':
resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
'@aws-sdk/client-s3@3.1000.0':
resolution: {integrity: sha512-7kPy33qNGq3NfwHC0412T6LDK1bp4+eiPzetX0sVd9cpTSXuQDKpoOFnB0Njj6uZjJDcLS3n2OeyarwwgkQ0Ow==}
'@aws-sdk/client-s3@3.1001.0':
resolution: {integrity: sha512-uKgFjQuBjMcd0iigLQwnqIp9gOy/5TGBxa42rcb6l5byDt1mrwOe6fyWTEUEJaNHG2LKYSPUibteGvM1zfm0Rw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/core@3.973.15':
resolution: {integrity: sha512-AlC0oQ1/mdJ8vCIqu524j5RB7M8i8E24bbkZmya1CuiQxkY7SdIZAyw7NDNMGaNINQFq/8oGRMX0HeOfCVsl/A==}
'@aws-sdk/core@3.973.16':
resolution: {integrity: sha512-Nasoyb5K4jfvncTKQyA13q55xHoz9as01NVYP05B0Kzux/X5UhMn3qXsZDyWOSXkfSCAIrMBKmVVWbI0vUapdQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/crc64-nvme@3.972.3':
resolution: {integrity: sha512-UExeK+EFiq5LAcbHm96CQLSia+5pvpUVSAsVApscBzayb7/6dJBJKwV4/onsk4VbWSmqxDMcfuTD+pC4RxgZHg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-env@3.972.13':
resolution: {integrity: sha512-6ljXKIQ22WFKyIs1jbORIkGanySBHaPPTOI4OxACP5WXgbcR0nDYfqNJfXEGwCK7IzHdNbCSFsNKKs0qCexR8Q==}
'@aws-sdk/credential-provider-env@3.972.14':
resolution: {integrity: sha512-PvnBY9rwBuLh9MEsAng28DG+WKl+txerKgf4BU9IPAqYI7FBIo1x6q/utLf4KLyQYgSy1TLQnbQuXx5xfBGASg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-http@3.972.15':
resolution: {integrity: sha512-dJuSTreu/T8f24SHDNTjd7eQ4rabr0TzPh2UTCwYexQtzG3nTDKm1e5eIdhiroTMDkPEJeY+WPkA6F9wod/20A==}
'@aws-sdk/credential-provider-http@3.972.16':
resolution: {integrity: sha512-m/QAcvw5OahqGPjeAnKtgfWgjLxeWOYj7JSmxKK6PLyKp2S/t2TAHI6EELEzXnIz28RMgbQLukJkVAqPASVAGQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-ini@3.972.13':
resolution: {integrity: sha512-JKSoGb7XeabZLBJptpqoZIFbROUIS65NuQnEHGOpuT9GuuZwag2qciKANiDLFiYk4u8nSrJC9JIOnWKVvPVjeA==}
'@aws-sdk/credential-provider-ini@3.972.14':
resolution: {integrity: sha512-EGA7ufqNpZKZcD0RwM6gRDEQgwAf19wQ99R1ptdWYDJAnpcMcWiFyT0RIrgiZFLD28CwJmYjnra75hChnEveWA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-login@3.972.13':
resolution: {integrity: sha512-RtYcrxdnJHKY8MFQGLltCURcjuMjnaQpAxPE6+/QEdDHHItMKZgabRe/KScX737F9vJMQsmJy9EmMOkCnoC1JQ==}
'@aws-sdk/credential-provider-login@3.972.14':
resolution: {integrity: sha512-P2kujQHAoV7irCTv6EGyReKFofkHCjIK+F0ZYf5UxeLeecrCwtrDkHoO2Vjsv/eRUumaKblD8czuk3CLlzwGDw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-node@3.972.14':
resolution: {integrity: sha512-WqoC2aliIjQM/L3oFf6j+op/enT2i9Cc4UTxxMEKrJNECkq4/PlKE5BOjSYFcq6G9mz65EFbXJh7zOU4CvjSKQ==}
'@aws-sdk/credential-provider-node@3.972.15':
resolution: {integrity: sha512-59NBJgTcQ2FC94T+SWkN5UQgViFtrLnkswSKhG5xbjPAotOXnkEF2Bf0bfUV1F3VaXzqAPZJoZ3bpg4rr8XD5Q==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-process@3.972.13':
resolution: {integrity: sha512-rsRG0LQA4VR+jnDyuqtXi2CePYSmfm5GNL9KxiW8DSe25YwJSr06W8TdUfONAC+rjsTI+aIH2rBGG5FjMeANrw==}
'@aws-sdk/credential-provider-process@3.972.14':
resolution: {integrity: sha512-KAF5LBkJInUPaR9dJDw8LqmbPDRTLyXyRoWVGcJQ+DcN9rxVKBRzAK+O4dTIvQtQ7xaIDZ2kY7zUmDlz6CCXdw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-sso@3.972.13':
resolution: {integrity: sha512-fr0UU1wx8kNHDhTQBXioc/YviSW8iXuAxHvnH7eQUtn8F8o/FU3uu6EUMvAQgyvn7Ne5QFnC0Cj0BFlwCk+RFw==}
'@aws-sdk/credential-provider-sso@3.972.14':
resolution: {integrity: sha512-LQzIYrNABnZzkyuIguFa3VVOox9UxPpRW6PL+QYtRHaGl1Ux/+Zi54tAVK31VdeBKPKU3cxqeu8dbOgNqy+naw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-web-identity@3.972.13':
resolution: {integrity: sha512-a6iFMh1pgUH0TdcouBppLJUfPM7Yd3R9S1xFodPtCRoLqCz2RQFA3qjA8x4112PVYXEd4/pHX2eihapq39w0rA==}
'@aws-sdk/credential-provider-web-identity@3.972.14':
resolution: {integrity: sha512-rOwB3vXHHHnGvAOjTgQETxVAsWjgF61XlbGd/ulvYo7EpdXs8cbIHE3PGih9tTj/65ZOegSqZGFqLaKntaI9Kw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-bucket-endpoint@3.972.6':
@@ -270,8 +270,8 @@ packages:
resolution: {integrity: sha512-QMdffpU+GkSGC+bz6WdqlclqIeCsOfgX8JFZ5xvwDtX+UTj4mIXm3uXu7Ko6dBseRcJz1FA6T9OmlAAY6JgJUg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-flexible-checksums@3.973.1':
resolution: {integrity: sha512-QLXsxsI6VW8LuGK+/yx699wzqP/NMCGk/hSGP+qtB+Lcff+23UlbahyouLlk+nfT7Iu021SkXBhnAuVd6IZcPw==}
'@aws-sdk/middleware-flexible-checksums@3.973.2':
resolution: {integrity: sha512-KM6QujWdasNjRLG+f7YEqEY5D36vR6Govm7nPIwxjILpb5rJ0pPJZpYY1nrzgtlxwJIYAznfBK5YXoLOHKHyfQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-host-header@3.972.6':
@@ -290,32 +290,32 @@ packages:
resolution: {integrity: sha512-dY4v3of5EEMvik6+UDwQ96KfUFDk8m1oZDdkSc5lwi4o7rFrjnv0A+yTV+gu230iybQZnKgDLg/rt2P3H+Vscw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-sdk-s3@3.972.15':
resolution: {integrity: sha512-WDLgssevOU5BFx1s8jA7jj6cE5HuImz28sy9jKOaVtz0AW1lYqSzotzdyiybFaBcQTs5zxXOb2pUfyMxgEKY3Q==}
'@aws-sdk/middleware-sdk-s3@3.972.16':
resolution: {integrity: sha512-U4K1rqyJYvT/zgTI3+rN+MToa51dFnnq1VSsVJuJWPNEKcEnuZVqf7yTpkJJMkYixVW5TTi1dgupd+nmJ0JyWw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-ssec@3.972.6':
resolution: {integrity: sha512-acvMUX9jF4I2Ew+Z/EA6gfaFaz9ehci5wxBmXCZeulLuv8m+iGf6pY9uKz8TPjg39bdAz3hxoE0eLP8Qz+IYlA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-user-agent@3.972.15':
resolution: {integrity: sha512-ABlFVcIMmuRAwBT+8q5abAxOr7WmaINirDJBnqGY5b5jSDo00UMlg/G4a0xoAgwm6oAECeJcwkvDlxDwKf58fQ==}
'@aws-sdk/middleware-user-agent@3.972.16':
resolution: {integrity: sha512-AmVxtxn8ZkNJbuPu3KKfW9IkJgTgcEtgSwbo0NVcAb31iGvLgHXj2nbbyrUDfh2fx8otXmqL+qw1lRaTi+V3vA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/nested-clients@3.996.3':
resolution: {integrity: sha512-AU5TY1V29xqwg/MxmA2odwysTez+ccFAhmfRJk+QZT5HNv90UTA9qKd1J9THlsQkvmH7HWTEV1lDNxkQO5PzNw==}
'@aws-sdk/nested-clients@3.996.4':
resolution: {integrity: sha512-NowB1HfOnWC4kwZOnTg8E8rSL0U+RSjSa++UtEV4ipoH6JOjMLnHyGilqwl+Pe1f0Al6v9yMkSJ/8Ot0f578CQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/region-config-resolver@3.972.6':
resolution: {integrity: sha512-Aa5PusHLXAqLTX1UKDvI3pHQJtIsF7Q+3turCHqfz/1F61/zDMWfbTC8evjhrrYVAtz9Vsv3SJ/waSUeu7B6gw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/signature-v4-multi-region@3.996.3':
resolution: {integrity: sha512-gQYI/Buwp0CAGQxY7mR5VzkP56rkWq2Y1ROkFuXh5XY94DsSjJw62B3I0N0lysQmtwiL2ht2KHI9NylM/RP4FA==}
'@aws-sdk/signature-v4-multi-region@3.996.4':
resolution: {integrity: sha512-MGa8ro0onekYIiesHX60LwKdkxK3Kd61p7TTbLwZemBqlnD9OLrk9sXZdFOIxXanJ+3AaJnV/jiX866eD/4PDg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.999.0':
resolution: {integrity: sha512-cx0hHUlgXULfykx4rdu/ciNAJaa3AL5xz3rieCz7NKJ68MJwlj3664Y8WR5MGgxfyYJBdamnkjNSx5Kekuc0cg==}
'@aws-sdk/token-providers@3.1001.0':
resolution: {integrity: sha512-09XAq/uIYgeZhohuGRrR/R+ek3+ljFNdzWCXdqb9rlIERDjSfNiLjTtpHgSK1xTPmC5G4yWoEAyMfTXiggS6wA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/types@3.973.4':
@@ -337,8 +337,8 @@ packages:
'@aws-sdk/util-user-agent-browser@3.972.6':
resolution: {integrity: sha512-Fwr/llD6GOrFgQnKaI2glhohdGuBDfHfora6iG9qsBBBR8xv1SdCSwbtf5CWlUdCw5X7g76G/9Hf0Inh0EmoxA==}
'@aws-sdk/util-user-agent-node@3.973.0':
resolution: {integrity: sha512-A9J2G4Nf236e9GpaC1JnA8wRn6u6GjnOXiTwBLA6NUJhlBTIGfrTy+K1IazmF8y+4OFdW3O5TZlhyspJMqiqjA==}
'@aws-sdk/util-user-agent-node@3.973.1':
resolution: {integrity: sha512-kmgbDqT7aCBEVrqESM2JUjbf0zhDUQ7wnt3q1RuVS+3mglrcfVb2bwkbmf38npOyyPGtQPV5dWN3m+sSFAVAgQ==}
engines: {node: '>=20.0.0'}
peerDependencies:
aws-crt: '>=1.0.0'
@@ -346,8 +346,8 @@ packages:
aws-crt:
optional: true
'@aws-sdk/xml-builder@3.972.8':
resolution: {integrity: sha512-Ql8elcUdYCha83Ol7NznBsgN5GVZnv3vUd86fEc6waU6oUdY0T1O9NODkEEOS/Uaogr87avDrUC6DSeM4oXjZg==}
'@aws-sdk/xml-builder@3.972.9':
resolution: {integrity: sha512-ItnlMgSqkPrUfJs7EsvU/01zw5UeIb2tNPhD09LBLHbg+g+HDiKibSLwpkuz/ZIlz4F2IMn+5XgE4AK/pfPuog==}
engines: {node: '>=20.0.0'}
'@aws/lambda-invoke-store@0.2.3':
@@ -816,8 +816,8 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@kevisual/ai@0.0.24':
resolution: {integrity: sha512-7jvZk1/L//VIClK7usuNgN4ZA9Etgbooka1Sj5quE/0UywR+NNnwqXVZ89Y1fBhI1TkhauDsdJBAtcQ7r/vbVw==}
'@kevisual/ai@0.0.26':
resolution: {integrity: sha512-lhaMpxi+vgqPdyBKiuNbSil4hy13tNLbDiqCtG0qUXKtvoowK6xMx269pSSYkYBivczM8g8I0XEouuJceUpJPg==}
'@kevisual/api@0.0.60':
resolution: {integrity: sha512-NTFDx1ns/iGli2fUJLJZRWu8nf5VkXV+sOQUqGGAJvrvGATvXSuITu6mD4P/aDQakx4hzQUPr9wDTZoNk7+RqQ==}
@@ -852,15 +852,9 @@ packages:
'@kevisual/oss@0.0.20':
resolution: {integrity: sha512-apsE+D79kNQrgdvgGzoS/kGEEfrO58WoHSFpUQOL1leuGdcmiT6pKLhBaWiAkmiJkacLBRwUNUTjz6xI+4liBg==}
'@kevisual/permission@0.0.3':
resolution: {integrity: sha512-8JsA/5O5Ax/z+M+MYpFYdlioHE6jNmWMuFSokBWYs9CCAHNiSKMR01YLkoVDoPvncfH/Y8F5K/IEXRCbptuMNA==}
'@kevisual/permission@0.0.4':
resolution: {integrity: sha512-zwBYPnT/z21W4q2wkklJrxvoYBYWG/+a3iXFDKqXQAnDOcxm/SU1f1N6FQb9KxGKl36/fclVlhxlxqszvKCenQ==}
'@kevisual/query@0.0.38':
resolution: {integrity: sha512-bfvbSodsZyMfwY+1T2SvDeOCKsT/AaIxlVe0+B1R/fNhlg2MDq2CP0L9HKiFkEm+OXrvXcYDMKPUituVUM5J6Q==}
'@kevisual/query@0.0.39':
resolution: {integrity: sha512-3UEPBIvtdykNkrby3hvrgrHdgd17Uq+Pnr4zs+JBzATkU2eKaOqtTUJqdyIEwuySCwzGTxrnlUzWP4tziDQDLQ==}
@@ -873,6 +867,9 @@ packages:
'@kevisual/router@0.0.84':
resolution: {integrity: sha512-l/TUFuqTJegB/S3FZQRBMUoz0Spvg8EzV3C/kBi/VO9KKCzjqZDVvhZJJbTQh9879CBY6vUy1ajo9WcLYnwbNA==}
'@kevisual/router@0.0.85':
resolution: {integrity: sha512-ihSzPXHOMSOnZD/+Eso4yZMt4MoUXyLdfRHhXJGg90+sJBr/BjsmgAokit4pI9gWU+Rs/3JqQ2/aqA43FHtGoA==}
'@kevisual/types@0.0.12':
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
@@ -966,8 +963,8 @@ packages:
resolution: {integrity: sha512-ejQvXqlcU30h7liR9fXtj7PIAau1t/sFbJpgWPfiYDs7zd16jpH0IsSXKcba2jF6ChTXvIjACs27kNMc5xxE2Q==}
engines: {node: '>=18.0.0'}
'@smithy/core@3.23.6':
resolution: {integrity: sha512-4xE+0L2NrsFKpEVFlFELkIHQddBvMbQ41LRIP74dGCXnY1zQ9DgksrBcRBDJT+iOzGy4VEJIeU3hkUK5mn06kg==}
'@smithy/core@3.23.7':
resolution: {integrity: sha512-/+ldRdtiO5Cb26afAZOG1FZM0x7D4AYdjpyOv2OScJw+4C7X+OLdRnNKF5UyUE0VpPgSKr3rnF/kvprRA4h2kg==}
engines: {node: '>=18.0.0'}
'@smithy/credential-provider-imds@4.2.10':
@@ -994,8 +991,8 @@ packages:
resolution: {integrity: sha512-aArqzOEvcs2dK+xQVCgLbpJQGfZihw8SD4ymhkwNTtwKbnrzdhJsFDKuMQnam2kF69WzgJYOU5eJlCx+CA32bw==}
engines: {node: '>=18.0.0'}
'@smithy/fetch-http-handler@5.3.11':
resolution: {integrity: sha512-wbTRjOxdFuyEg0CpumjZO0hkUl+fetJFqxNROepuLIoijQh51aMBmzFLfoQdwRjxsuuS2jizzIUTjPWgd8pd7g==}
'@smithy/fetch-http-handler@5.3.12':
resolution: {integrity: sha512-muS5tFw+A/uo+U+yig06vk1776UFM+aAp9hFM8efI4ZcHhTcgv6NTeK4x7ltHeMPBwnhEjcf0MULTyxNkSNxDw==}
engines: {node: '>=18.0.0'}
'@smithy/hash-blob-browser@4.2.11':
@@ -1030,12 +1027,12 @@ packages:
resolution: {integrity: sha512-TQZ9kX5c6XbjhaEBpvhSvMEZ0klBs1CFtOdPFwATZSbC9UeQfKHPLPN9Y+I6wZGMOavlYTOlHEPDrt42PMSH9w==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-endpoint@4.4.20':
resolution: {integrity: sha512-9W6Np4ceBP3XCYAGLoMCmn8t2RRVzuD1ndWPLBbv7H9CrwM9Bprf6Up6BM9ZA/3alodg0b7Kf6ftBK9R1N04vw==}
'@smithy/middleware-endpoint@4.4.21':
resolution: {integrity: sha512-CoVGZaqIC0tEjz0ga3ciwCMA5fd/4lIOwO2wx0fH+cTi1zxSFZnMJbIiIF9G1d4vRSDyTupDrpS3FKBBJGkRZg==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-retry@4.4.37':
resolution: {integrity: sha512-/1psZZllBBSQ7+qo5+hhLz7AEPGLx3Z0+e3ramMBEuPK2PfvLK4SrncDB9VegX5mBn+oP/UTDrM6IHrFjvX1ZA==}
'@smithy/middleware-retry@4.4.38':
resolution: {integrity: sha512-WdHvdhjE6Fj78vxFwDKFDwlqGOGRUWrwGeuENUbTVE46Su9mnQM+dXHtbnCaQvwuSYrRsjpe8zUsFpwUp/azlA==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-serde@4.2.11':
@@ -1050,8 +1047,8 @@ packages:
resolution: {integrity: sha512-UALRbJtVX34AdP2VECKVlnNgidLHA2A7YgcJzwSBg1hzmnO/bZBHl/LDQQyYifzUwp1UOODnl9JJ3KNawpUJ9w==}
engines: {node: '>=18.0.0'}
'@smithy/node-http-handler@4.4.12':
resolution: {integrity: sha512-zo1+WKJkR9x7ZtMeMDAAsq2PufwiLDmkhcjpWPRRkmeIuOm6nq1qjFICSZbnjBvD09ei8KMo26BWxsu2BUU+5w==}
'@smithy/node-http-handler@4.4.13':
resolution: {integrity: sha512-o8CP8w6tlUA0lk+Qfwm6Ed0jCWk3bEY6iBOJjdBaowbXKCSClk8zIHQvUL6RUZMvuNafF27cbRCMYqw6O1v4aA==}
engines: {node: '>=18.0.0'}
'@smithy/property-provider@4.2.10':
@@ -1082,8 +1079,8 @@ packages:
resolution: {integrity: sha512-Wab3wW8468WqTKIxI+aZe3JYO52/RYT/8sDOdzkUhjnLakLe9qoQqIcfih/qxcF4qWEFoWBszY0mj5uxffaVXA==}
engines: {node: '>=18.0.0'}
'@smithy/smithy-client@4.12.0':
resolution: {integrity: sha512-R8bQ9K3lCcXyZmBnQqUZJF4ChZmtWT5NLi6x5kgWx5D+/j0KorXcA0YcFg/X5TOgnTCy1tbKc6z2g2y4amFupQ==}
'@smithy/smithy-client@4.12.1':
resolution: {integrity: sha512-Xf9UFHlAihewfkmLNZ6I/Ek6kcYBKoU3cbRS9Z4q++9GWoW0YFbAHs7wMbuXm+nGuKHZ5OKheZMuDdaWPv8DJw==}
engines: {node: '>=18.0.0'}
'@smithy/types@4.13.0':
@@ -1118,12 +1115,12 @@ packages:
resolution: {integrity: sha512-462id/00U8JWFw6qBuTSWfN5TxOHvDu4WliI97qOIOnuC/g+NDAknTU8eoGXEPlLkRVgWEr03jJBLV4o2FL8+A==}
engines: {node: '>=18.0.0'}
'@smithy/util-defaults-mode-browser@4.3.36':
resolution: {integrity: sha512-R0smq7EHQXRVMxkAxtH5akJ/FvgAmNF6bUy/GwY/N20T4GrwjT633NFm0VuRpC+8Bbv8R9A0DoJ9OiZL/M3xew==}
'@smithy/util-defaults-mode-browser@4.3.37':
resolution: {integrity: sha512-JlPZhV1kQCGNJgofRTU6E8kHrjCKsb6cps8gco8QDVaFl7biFYzHg0p1x89ytIWyVyCkY3nOpO8tJPM47Vqlww==}
engines: {node: '>=18.0.0'}
'@smithy/util-defaults-mode-node@4.2.39':
resolution: {integrity: sha512-otWuoDm35btJV1L8MyHrPl462B07QCdMTktKc7/yM+Psv6KbED/ziXiHnmr7yPHUjfIwE9S8Max0LO24Mo3ZVg==}
'@smithy/util-defaults-mode-node@4.2.40':
resolution: {integrity: sha512-BM5cPEsyxHdYYO4Da77E94lenhaVPNUzBTyCGDkcw/n/mE8Q1cfHwr+n/w2bNPuUsPC30WaW5/hGKWOTKqw8kw==}
engines: {node: '>=18.0.0'}
'@smithy/util-endpoints@3.3.1':
@@ -1142,8 +1139,8 @@ packages:
resolution: {integrity: sha512-HrBzistfpyE5uqTwiyLsFHscgnwB0kgv8vySp7q5kZ0Eltn/tjosaSGGDj/jJ9ys7pWzIP/icE2d+7vMKXLv7A==}
engines: {node: '>=18.0.0'}
'@smithy/util-stream@4.5.15':
resolution: {integrity: sha512-OlOKnaqnkU9X+6wEkd7mN+WB7orPbCVDauXOj22Q7VtiTkvy7ZdSsOg4QiNAZMgI4OkvNf+/VLUC3VXkxuWJZw==}
'@smithy/util-stream@4.5.16':
resolution: {integrity: sha512-c7awZV6cxY0czgDDSr+Bz0XfRtg8AwW2BWhrHhLJISrpmwv8QzA2qzTllWyMVNdy1+UJr9vCm29hzuh3l8TTFw==}
engines: {node: '>=18.0.0'}
'@smithy/util-uri-escape@4.2.1':
@@ -1172,8 +1169,8 @@ packages:
'@types/archiver@7.0.0':
resolution: {integrity: sha512-/3vwGwx9n+mCQdYZ2IKGGHEFL30I96UgBlk8EtRDDFQ9uxM1l4O5Ci6r00EMAkiDaTqD9DQ6nVrWRICnBPtzzg==}
'@types/bun@1.3.9':
resolution: {integrity: sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw==}
'@types/bun@1.3.10':
resolution: {integrity: sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ==}
'@types/busboy@1.5.4':
resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==}
@@ -1339,8 +1336,8 @@ packages:
bullmq@5.70.1:
resolution: {integrity: sha512-HjfGHfICkAClrFL0Y07qNbWcmiOCv1l+nusupXUjrvTPuDEyPEJ23MP0lUwUs/QEy1a3pWt/P/sCsSZ1RjRK+w==}
bun-types@1.3.9:
resolution: {integrity: sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg==}
bun-types@1.3.10:
resolution: {integrity: sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg==}
busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
@@ -1644,6 +1641,9 @@ packages:
es-toolkit@1.44.0:
resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
es-toolkit@1.45.1:
resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==}
esbuild-register@3.6.0:
resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
peerDependencies:
@@ -1723,8 +1723,11 @@ packages:
fast-json-patch@3.1.1:
resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==}
fast-xml-parser@5.3.6:
resolution: {integrity: sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==}
fast-xml-builder@1.0.0:
resolution: {integrity: sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==}
fast-xml-parser@5.4.1:
resolution: {integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==}
hasBin: true
fclone@1.0.11:
@@ -2707,76 +2710,76 @@ snapshots:
'@smithy/util-utf8': 2.3.0
tslib: 2.8.1
'@aws-sdk/client-s3@3.1000.0':
'@aws-sdk/client-s3@3.1001.0':
dependencies:
'@aws-crypto/sha1-browser': 5.2.0
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
'@aws-sdk/core': 3.973.15
'@aws-sdk/credential-provider-node': 3.972.14
'@aws-sdk/core': 3.973.16
'@aws-sdk/credential-provider-node': 3.972.15
'@aws-sdk/middleware-bucket-endpoint': 3.972.6
'@aws-sdk/middleware-expect-continue': 3.972.6
'@aws-sdk/middleware-flexible-checksums': 3.973.1
'@aws-sdk/middleware-flexible-checksums': 3.973.2
'@aws-sdk/middleware-host-header': 3.972.6
'@aws-sdk/middleware-location-constraint': 3.972.6
'@aws-sdk/middleware-logger': 3.972.6
'@aws-sdk/middleware-recursion-detection': 3.972.6
'@aws-sdk/middleware-sdk-s3': 3.972.15
'@aws-sdk/middleware-sdk-s3': 3.972.16
'@aws-sdk/middleware-ssec': 3.972.6
'@aws-sdk/middleware-user-agent': 3.972.15
'@aws-sdk/middleware-user-agent': 3.972.16
'@aws-sdk/region-config-resolver': 3.972.6
'@aws-sdk/signature-v4-multi-region': 3.996.3
'@aws-sdk/signature-v4-multi-region': 3.996.4
'@aws-sdk/types': 3.973.4
'@aws-sdk/util-endpoints': 3.996.3
'@aws-sdk/util-user-agent-browser': 3.972.6
'@aws-sdk/util-user-agent-node': 3.973.0
'@aws-sdk/util-user-agent-node': 3.973.1
'@smithy/config-resolver': 4.4.9
'@smithy/core': 3.23.6
'@smithy/core': 3.23.7
'@smithy/eventstream-serde-browser': 4.2.10
'@smithy/eventstream-serde-config-resolver': 4.3.10
'@smithy/eventstream-serde-node': 4.2.10
'@smithy/fetch-http-handler': 5.3.11
'@smithy/fetch-http-handler': 5.3.12
'@smithy/hash-blob-browser': 4.2.11
'@smithy/hash-node': 4.2.10
'@smithy/hash-stream-node': 4.2.10
'@smithy/invalid-dependency': 4.2.10
'@smithy/md5-js': 4.2.10
'@smithy/middleware-content-length': 4.2.10
'@smithy/middleware-endpoint': 4.4.20
'@smithy/middleware-retry': 4.4.37
'@smithy/middleware-endpoint': 4.4.21
'@smithy/middleware-retry': 4.4.38
'@smithy/middleware-serde': 4.2.11
'@smithy/middleware-stack': 4.2.10
'@smithy/node-config-provider': 4.3.10
'@smithy/node-http-handler': 4.4.12
'@smithy/node-http-handler': 4.4.13
'@smithy/protocol-http': 5.3.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
'@smithy/url-parser': 4.2.10
'@smithy/util-base64': 4.3.1
'@smithy/util-body-length-browser': 4.2.1
'@smithy/util-body-length-node': 4.2.2
'@smithy/util-defaults-mode-browser': 4.3.36
'@smithy/util-defaults-mode-node': 4.2.39
'@smithy/util-defaults-mode-browser': 4.3.37
'@smithy/util-defaults-mode-node': 4.2.40
'@smithy/util-endpoints': 3.3.1
'@smithy/util-middleware': 4.2.10
'@smithy/util-retry': 4.2.10
'@smithy/util-stream': 4.5.15
'@smithy/util-stream': 4.5.16
'@smithy/util-utf8': 4.2.1
'@smithy/util-waiter': 4.2.10
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
'@aws-sdk/core@3.973.15':
'@aws-sdk/core@3.973.16':
dependencies:
'@aws-sdk/types': 3.973.4
'@aws-sdk/xml-builder': 3.972.8
'@smithy/core': 3.23.6
'@aws-sdk/xml-builder': 3.972.9
'@smithy/core': 3.23.7
'@smithy/node-config-provider': 4.3.10
'@smithy/property-provider': 4.2.10
'@smithy/protocol-http': 5.3.10
'@smithy/signature-v4': 5.3.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
'@smithy/util-base64': 4.3.1
'@smithy/util-middleware': 4.2.10
@@ -2788,37 +2791,37 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/credential-provider-env@3.972.13':
'@aws-sdk/credential-provider-env@3.972.14':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/types': 3.973.4
'@smithy/property-provider': 4.2.10
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/credential-provider-http@3.972.15':
'@aws-sdk/credential-provider-http@3.972.16':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/types': 3.973.4
'@smithy/fetch-http-handler': 5.3.11
'@smithy/node-http-handler': 4.4.12
'@smithy/fetch-http-handler': 5.3.12
'@smithy/node-http-handler': 4.4.13
'@smithy/property-provider': 4.2.10
'@smithy/protocol-http': 5.3.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
'@smithy/util-stream': 4.5.15
'@smithy/util-stream': 4.5.16
tslib: 2.8.1
'@aws-sdk/credential-provider-ini@3.972.13':
'@aws-sdk/credential-provider-ini@3.972.14':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/credential-provider-env': 3.972.13
'@aws-sdk/credential-provider-http': 3.972.15
'@aws-sdk/credential-provider-login': 3.972.13
'@aws-sdk/credential-provider-process': 3.972.13
'@aws-sdk/credential-provider-sso': 3.972.13
'@aws-sdk/credential-provider-web-identity': 3.972.13
'@aws-sdk/nested-clients': 3.996.3
'@aws-sdk/core': 3.973.16
'@aws-sdk/credential-provider-env': 3.972.14
'@aws-sdk/credential-provider-http': 3.972.16
'@aws-sdk/credential-provider-login': 3.972.14
'@aws-sdk/credential-provider-process': 3.972.14
'@aws-sdk/credential-provider-sso': 3.972.14
'@aws-sdk/credential-provider-web-identity': 3.972.14
'@aws-sdk/nested-clients': 3.996.4
'@aws-sdk/types': 3.973.4
'@smithy/credential-provider-imds': 4.2.10
'@smithy/property-provider': 4.2.10
@@ -2828,10 +2831,10 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/credential-provider-login@3.972.13':
'@aws-sdk/credential-provider-login@3.972.14':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/nested-clients': 3.996.3
'@aws-sdk/core': 3.973.16
'@aws-sdk/nested-clients': 3.996.4
'@aws-sdk/types': 3.973.4
'@smithy/property-provider': 4.2.10
'@smithy/protocol-http': 5.3.10
@@ -2841,14 +2844,14 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/credential-provider-node@3.972.14':
'@aws-sdk/credential-provider-node@3.972.15':
dependencies:
'@aws-sdk/credential-provider-env': 3.972.13
'@aws-sdk/credential-provider-http': 3.972.15
'@aws-sdk/credential-provider-ini': 3.972.13
'@aws-sdk/credential-provider-process': 3.972.13
'@aws-sdk/credential-provider-sso': 3.972.13
'@aws-sdk/credential-provider-web-identity': 3.972.13
'@aws-sdk/credential-provider-env': 3.972.14
'@aws-sdk/credential-provider-http': 3.972.16
'@aws-sdk/credential-provider-ini': 3.972.14
'@aws-sdk/credential-provider-process': 3.972.14
'@aws-sdk/credential-provider-sso': 3.972.14
'@aws-sdk/credential-provider-web-identity': 3.972.14
'@aws-sdk/types': 3.973.4
'@smithy/credential-provider-imds': 4.2.10
'@smithy/property-provider': 4.2.10
@@ -2858,20 +2861,20 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/credential-provider-process@3.972.13':
'@aws-sdk/credential-provider-process@3.972.14':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/types': 3.973.4
'@smithy/property-provider': 4.2.10
'@smithy/shared-ini-file-loader': 4.4.5
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/credential-provider-sso@3.972.13':
'@aws-sdk/credential-provider-sso@3.972.14':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/nested-clients': 3.996.3
'@aws-sdk/token-providers': 3.999.0
'@aws-sdk/core': 3.973.16
'@aws-sdk/nested-clients': 3.996.4
'@aws-sdk/token-providers': 3.1001.0
'@aws-sdk/types': 3.973.4
'@smithy/property-provider': 4.2.10
'@smithy/shared-ini-file-loader': 4.4.5
@@ -2880,10 +2883,10 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/credential-provider-web-identity@3.972.13':
'@aws-sdk/credential-provider-web-identity@3.972.14':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/nested-clients': 3.996.3
'@aws-sdk/core': 3.973.16
'@aws-sdk/nested-clients': 3.996.4
'@aws-sdk/types': 3.973.4
'@smithy/property-provider': 4.2.10
'@smithy/shared-ini-file-loader': 4.4.5
@@ -2909,12 +2912,12 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/middleware-flexible-checksums@3.973.1':
'@aws-sdk/middleware-flexible-checksums@3.973.2':
dependencies:
'@aws-crypto/crc32': 5.2.0
'@aws-crypto/crc32c': 5.2.0
'@aws-crypto/util': 5.2.0
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/crc64-nvme': 3.972.3
'@aws-sdk/types': 3.973.4
'@smithy/is-array-buffer': 4.2.1
@@ -2922,7 +2925,7 @@ snapshots:
'@smithy/protocol-http': 5.3.10
'@smithy/types': 4.13.0
'@smithy/util-middleware': 4.2.10
'@smithy/util-stream': 4.5.15
'@smithy/util-stream': 4.5.16
'@smithy/util-utf8': 4.2.1
tslib: 2.8.1
@@ -2953,20 +2956,20 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/middleware-sdk-s3@3.972.15':
'@aws-sdk/middleware-sdk-s3@3.972.16':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/types': 3.973.4
'@aws-sdk/util-arn-parser': 3.972.2
'@smithy/core': 3.23.6
'@smithy/core': 3.23.7
'@smithy/node-config-provider': 4.3.10
'@smithy/protocol-http': 5.3.10
'@smithy/signature-v4': 5.3.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
'@smithy/util-config-provider': 4.2.1
'@smithy/util-middleware': 4.2.10
'@smithy/util-stream': 4.5.15
'@smithy/util-stream': 4.5.16
'@smithy/util-utf8': 4.2.1
tslib: 2.8.1
@@ -2976,51 +2979,51 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/middleware-user-agent@3.972.15':
'@aws-sdk/middleware-user-agent@3.972.16':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/types': 3.973.4
'@aws-sdk/util-endpoints': 3.996.3
'@smithy/core': 3.23.6
'@smithy/core': 3.23.7
'@smithy/protocol-http': 5.3.10
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/nested-clients@3.996.3':
'@aws-sdk/nested-clients@3.996.4':
dependencies:
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
'@aws-sdk/core': 3.973.15
'@aws-sdk/core': 3.973.16
'@aws-sdk/middleware-host-header': 3.972.6
'@aws-sdk/middleware-logger': 3.972.6
'@aws-sdk/middleware-recursion-detection': 3.972.6
'@aws-sdk/middleware-user-agent': 3.972.15
'@aws-sdk/middleware-user-agent': 3.972.16
'@aws-sdk/region-config-resolver': 3.972.6
'@aws-sdk/types': 3.973.4
'@aws-sdk/util-endpoints': 3.996.3
'@aws-sdk/util-user-agent-browser': 3.972.6
'@aws-sdk/util-user-agent-node': 3.973.0
'@aws-sdk/util-user-agent-node': 3.973.1
'@smithy/config-resolver': 4.4.9
'@smithy/core': 3.23.6
'@smithy/fetch-http-handler': 5.3.11
'@smithy/core': 3.23.7
'@smithy/fetch-http-handler': 5.3.12
'@smithy/hash-node': 4.2.10
'@smithy/invalid-dependency': 4.2.10
'@smithy/middleware-content-length': 4.2.10
'@smithy/middleware-endpoint': 4.4.20
'@smithy/middleware-retry': 4.4.37
'@smithy/middleware-endpoint': 4.4.21
'@smithy/middleware-retry': 4.4.38
'@smithy/middleware-serde': 4.2.11
'@smithy/middleware-stack': 4.2.10
'@smithy/node-config-provider': 4.3.10
'@smithy/node-http-handler': 4.4.12
'@smithy/node-http-handler': 4.4.13
'@smithy/protocol-http': 5.3.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
'@smithy/url-parser': 4.2.10
'@smithy/util-base64': 4.3.1
'@smithy/util-body-length-browser': 4.2.1
'@smithy/util-body-length-node': 4.2.2
'@smithy/util-defaults-mode-browser': 4.3.36
'@smithy/util-defaults-mode-node': 4.2.39
'@smithy/util-defaults-mode-browser': 4.3.37
'@smithy/util-defaults-mode-node': 4.2.40
'@smithy/util-endpoints': 3.3.1
'@smithy/util-middleware': 4.2.10
'@smithy/util-retry': 4.2.10
@@ -3037,19 +3040,19 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/signature-v4-multi-region@3.996.3':
'@aws-sdk/signature-v4-multi-region@3.996.4':
dependencies:
'@aws-sdk/middleware-sdk-s3': 3.972.15
'@aws-sdk/middleware-sdk-s3': 3.972.16
'@aws-sdk/types': 3.973.4
'@smithy/protocol-http': 5.3.10
'@smithy/signature-v4': 5.3.10
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/token-providers@3.999.0':
'@aws-sdk/token-providers@3.1001.0':
dependencies:
'@aws-sdk/core': 3.973.15
'@aws-sdk/nested-clients': 3.996.3
'@aws-sdk/core': 3.973.16
'@aws-sdk/nested-clients': 3.996.4
'@aws-sdk/types': 3.973.4
'@smithy/property-provider': 4.2.10
'@smithy/shared-ini-file-loader': 4.4.5
@@ -3086,18 +3089,18 @@ snapshots:
bowser: 2.13.1
tslib: 2.8.1
'@aws-sdk/util-user-agent-node@3.973.0':
'@aws-sdk/util-user-agent-node@3.973.1':
dependencies:
'@aws-sdk/middleware-user-agent': 3.972.15
'@aws-sdk/middleware-user-agent': 3.972.16
'@aws-sdk/types': 3.973.4
'@smithy/node-config-provider': 4.3.10
'@smithy/types': 4.13.0
tslib: 2.8.1
'@aws-sdk/xml-builder@3.972.8':
'@aws-sdk/xml-builder@3.972.9':
dependencies:
'@smithy/types': 4.13.0
fast-xml-parser: 5.3.6
fast-xml-parser: 5.4.1
tslib: 2.8.1
'@aws/lambda-invoke-store@0.2.3': {}
@@ -3347,11 +3350,11 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@kevisual/ai@0.0.24':
'@kevisual/ai@0.0.26':
dependencies:
'@kevisual/logger': 0.0.4
'@kevisual/permission': 0.0.3
'@kevisual/query': 0.0.38
'@kevisual/permission': 0.0.4
'@kevisual/query': 0.0.52
'@kevisual/api@0.0.60(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
@@ -3359,7 +3362,7 @@ snapshots:
'@kevisual/js-filter': 0.0.5
'@kevisual/load': 0.0.6
'@paralleldrive/cuid2': 3.3.0
es-toolkit: 1.44.0
es-toolkit: 1.45.1
eventemitter3: 5.0.4
fuse.js: 7.1.0
nanoid: 5.1.6
@@ -3381,7 +3384,7 @@ snapshots:
'@kevisual/query': 0.0.52
'@kevisual/router': 0.0.84
'@kevisual/use-config': 1.0.30(dotenv@17.3.1)
es-toolkit: 1.44.0
es-toolkit: 1.45.1
nanoid: 5.1.6
unstorage: 1.17.4(ioredis@5.9.3)
ws: '@kevisual/ws@8.19.0'
@@ -3443,14 +3446,8 @@ snapshots:
'@kevisual/oss@0.0.20': {}
'@kevisual/permission@0.0.3': {}
'@kevisual/permission@0.0.4': {}
'@kevisual/query@0.0.38':
dependencies:
tslib: 2.8.1
'@kevisual/query@0.0.39':
dependencies:
tslib: 2.8.1
@@ -3463,7 +3460,11 @@ snapshots:
'@kevisual/router@0.0.84':
dependencies:
es-toolkit: 1.44.0
es-toolkit: 1.45.1
'@kevisual/router@0.0.85':
dependencies:
es-toolkit: 1.45.1
'@kevisual/types@0.0.12': {}
@@ -3580,7 +3581,7 @@ snapshots:
'@smithy/util-middleware': 4.2.10
tslib: 2.8.1
'@smithy/core@3.23.6':
'@smithy/core@3.23.7':
dependencies:
'@smithy/middleware-serde': 4.2.11
'@smithy/protocol-http': 5.3.10
@@ -3588,7 +3589,7 @@ snapshots:
'@smithy/util-base64': 4.3.1
'@smithy/util-body-length-browser': 4.2.1
'@smithy/util-middleware': 4.2.10
'@smithy/util-stream': 4.5.15
'@smithy/util-stream': 4.5.16
'@smithy/util-utf8': 4.2.1
'@smithy/uuid': 1.1.1
tslib: 2.8.1
@@ -3631,7 +3632,7 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@smithy/fetch-http-handler@5.3.11':
'@smithy/fetch-http-handler@5.3.12':
dependencies:
'@smithy/protocol-http': 5.3.10
'@smithy/querystring-builder': 4.2.10
@@ -3684,9 +3685,9 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@smithy/middleware-endpoint@4.4.20':
'@smithy/middleware-endpoint@4.4.21':
dependencies:
'@smithy/core': 3.23.6
'@smithy/core': 3.23.7
'@smithy/middleware-serde': 4.2.11
'@smithy/node-config-provider': 4.3.10
'@smithy/shared-ini-file-loader': 4.4.5
@@ -3695,12 +3696,12 @@ snapshots:
'@smithy/util-middleware': 4.2.10
tslib: 2.8.1
'@smithy/middleware-retry@4.4.37':
'@smithy/middleware-retry@4.4.38':
dependencies:
'@smithy/node-config-provider': 4.3.10
'@smithy/protocol-http': 5.3.10
'@smithy/service-error-classification': 4.2.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
'@smithy/util-middleware': 4.2.10
'@smithy/util-retry': 4.2.10
@@ -3725,7 +3726,7 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@smithy/node-http-handler@4.4.12':
'@smithy/node-http-handler@4.4.13':
dependencies:
'@smithy/abort-controller': 4.2.10
'@smithy/protocol-http': 5.3.10
@@ -3774,14 +3775,14 @@ snapshots:
'@smithy/util-utf8': 4.2.1
tslib: 2.8.1
'@smithy/smithy-client@4.12.0':
'@smithy/smithy-client@4.12.1':
dependencies:
'@smithy/core': 3.23.6
'@smithy/middleware-endpoint': 4.4.20
'@smithy/core': 3.23.7
'@smithy/middleware-endpoint': 4.4.21
'@smithy/middleware-stack': 4.2.10
'@smithy/protocol-http': 5.3.10
'@smithy/types': 4.13.0
'@smithy/util-stream': 4.5.15
'@smithy/util-stream': 4.5.16
tslib: 2.8.1
'@smithy/types@4.13.0':
@@ -3822,20 +3823,20 @@ snapshots:
dependencies:
tslib: 2.8.1
'@smithy/util-defaults-mode-browser@4.3.36':
'@smithy/util-defaults-mode-browser@4.3.37':
dependencies:
'@smithy/property-provider': 4.2.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
tslib: 2.8.1
'@smithy/util-defaults-mode-node@4.2.39':
'@smithy/util-defaults-mode-node@4.2.40':
dependencies:
'@smithy/config-resolver': 4.4.9
'@smithy/credential-provider-imds': 4.2.10
'@smithy/node-config-provider': 4.3.10
'@smithy/property-provider': 4.2.10
'@smithy/smithy-client': 4.12.0
'@smithy/smithy-client': 4.12.1
'@smithy/types': 4.13.0
tslib: 2.8.1
@@ -3860,10 +3861,10 @@ snapshots:
'@smithy/types': 4.13.0
tslib: 2.8.1
'@smithy/util-stream@4.5.15':
'@smithy/util-stream@4.5.16':
dependencies:
'@smithy/fetch-http-handler': 5.3.11
'@smithy/node-http-handler': 4.4.12
'@smithy/fetch-http-handler': 5.3.12
'@smithy/node-http-handler': 4.4.13
'@smithy/types': 4.13.0
'@smithy/util-base64': 4.3.1
'@smithy/util-buffer-from': 4.2.1
@@ -3901,9 +3902,9 @@ snapshots:
dependencies:
'@types/readdir-glob': 1.1.5
'@types/bun@1.3.9':
'@types/bun@1.3.10':
dependencies:
bun-types: 1.3.9
bun-types: 1.3.10
'@types/busboy@1.5.4':
dependencies:
@@ -4091,7 +4092,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
bun-types@1.3.9:
bun-types@1.3.10:
dependencies:
'@types/node': 25.3.3
@@ -4245,16 +4246,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
drizzle-orm@0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.9)(pg@8.19.0):
drizzle-orm@0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.10)(pg@8.19.0):
optionalDependencies:
'@types/pg': 8.18.0
better-sqlite3: 12.6.2
bun-types: 1.3.9
bun-types: 1.3.10
pg: 8.19.0
drizzle-zod@0.8.3(drizzle-orm@0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.9)(pg@8.19.0))(zod@4.3.6):
drizzle-zod@0.8.3(drizzle-orm@0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.10)(pg@8.19.0))(zod@4.3.6):
dependencies:
drizzle-orm: 0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.9)(pg@8.19.0)
drizzle-orm: 0.45.1(@types/pg@8.18.0)(better-sqlite3@12.6.2)(bun-types@1.3.10)(pg@8.19.0)
zod: 4.3.6
eastasianwidth@0.2.0: {}
@@ -4284,6 +4285,8 @@ snapshots:
es-toolkit@1.44.0: {}
es-toolkit@1.45.1: {}
esbuild-register@3.6.0(esbuild@0.25.12):
dependencies:
debug: 4.4.3
@@ -4417,8 +4420,11 @@ snapshots:
fast-json-patch@3.1.1: {}
fast-xml-parser@5.3.6:
fast-xml-builder@1.0.0: {}
fast-xml-parser@5.4.1:
dependencies:
fast-xml-builder: 1.0.0
strnum: 2.1.2
fclone@1.0.11: {}

View File

@@ -0,0 +1,6 @@
export const renderServerHtml = (data: any, html: string) => {
if (html.includes('<body>')) {
return html.replace('<body>', `<body><script>window.__SERVER_DATA__ = ${JSON.stringify(data)}</script>`);
}
return html;
}

View File

@@ -1,8 +1,18 @@
type StudioOpts = { user: string, userAppKey?: string; appIds: string[] }
type StudioOpts = {
user: string,
userAppKey?: string;
appIds: string[]
infoList?: {
user: string;
id: string;
status: 'waiting' | 'connected' | 'closed';
}[]
}
export const createStudioAppListHtml = (opts: StudioOpts) => {
const user = opts.user!;
const userAppKey = opts?.userAppKey;
let showUserAppKey = userAppKey;
const infos = opts.infoList || [];
if (showUserAppKey && showUserAppKey.startsWith(user + '--')) {
showUserAppKey = showUserAppKey.replace(user + '--', '');
}
@@ -333,7 +343,7 @@ export const createStudioAppListHtml = (opts: StudioOpts) => {
</div>
` : ''}
${appListContent}
<pre>${JSON.stringify(infos, null, 2)}</pre>
<div class="footer">
© ${new Date().getFullYear()} Studio - 应用管理
</div>

View File

@@ -1,7 +1,7 @@
import childProcess from 'child_process';
export const selfRestart = async () => {
const appName = 'code-center';
const appName = 'root/code-center';
// 检测 pm2 是否安装和是否有 appName 这个应用
try {
const res = childProcess.execSync(`pm2 list`);

View File

@@ -3,46 +3,40 @@ import { getLoginUserByToken } from '@/modules/auth.ts';
import { logger } from '../logger.ts';
export const wsProxyManager = new WsProxyManager();
import { WebSocketListenerFun } from '@kevisual/router/src/server/server-type.ts'
// 生成一个随机六位字符串作为注册 ID
const generateRegistryId = () => {
return Math.random().toString(36).substring(2, 8);
}
export const wssFun: WebSocketListenerFun = async (req, res) => {
// do nothing, just to enable ws upgrade event
const { id, ws, token, data, emitter } = req;
// console.log('req', req)
const { type } = data || {};
if (type === 'registryClient') {
const loginUser = await getLoginUserByToken(token);
if (!loginUser?.tokenUser) {
logger.debug('未登录,断开连接');
ws.send(JSON.stringify({ code: 401, message: '未登录' }));
setTimeout(() => {
ws.close(401, 'Unauthorized');
}, 1000);
let isLogin = false;
let user = '';
if (loginUser?.tokenUser) {
isLogin = true;
user = loginUser?.tokenUser?.username;
} else {
logger.debug('未登录,请求等待用户验证', data);
user = data?.username || '';
}
if (!user) {
logger.debug('未提供用户名,无法注册 ws 连接');
ws.close();
return;
}
const user = loginUser?.tokenUser?.username;
const userApp = user + '--' + id;
logger.debug('注册 ws 连接', userApp);
const wsMessage = wsProxyManager.get(userApp);
if (wsMessage) {
logger.debug('ws 连接已存在,关闭旧连接', userApp);
wsMessage.ws.close();
wsProxyManager.unregister(userApp);
await new Promise((resolve) => setTimeout(resolve, 200));
let userApp = user + '--' + id;
// TODO: 如果存在, 而且之前的那个关闭了,不需要验证,直接覆盖和复用.
let wsConnect = await wsProxyManager.createNewConnection({ ws, user, userApp, isLogin });
if (wsConnect.isNew) {
logger.debug('新连接注册成功', userApp);
}
// @ts-ignore
wsProxyManager.register(userApp, { user, ws });
ws.send(
JSON.stringify({
type: 'connected',
user: user,
id,
}),
);
emitter.once('close--' + id, () => {
logger.debug('ws emitter closed');
wsProxyManager.unregister(userApp);
});
// @ts-ignore
ws.data.userApp = userApp;
ws.data.userApp = wsConnect.id;
return;
}
// @ts-ignore

View File

@@ -1,7 +1,9 @@
import { nanoid } from 'nanoid';
import { customAlphabet } from 'nanoid';
import { WebSocket } from 'ws';
import { logger } from '../logger.ts';
import { EventEmitter } from 'eventemitter3';
const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const nanoid = customAlphabet(letters, 10);
class WsMessage {
ws: WebSocket;
@@ -9,11 +11,16 @@ class WsMessage {
emitter: EventEmitter;
private pingTimer?: NodeJS.Timeout;
private readonly PING_INTERVAL = 30000; // 30 秒发送一次 ping
constructor({ ws, user }: WssMessageOptions) {
id?: string;
status?: 'waiting' | 'connected' | 'closed';
manager: WsProxyManager;
constructor({ ws, user, id, isLogin, manager }: WssMessageOptions) {
this.ws = ws;
this.user = user;
this.id = id;
this.emitter = new EventEmitter();
this.manager = manager;
this.status = isLogin ? 'connected' : 'waiting';
this.startPing();
}
@@ -39,12 +46,44 @@ class WsMessage {
this.stopPing();
this.emitter.removeAllListeners();
}
isClosed() {
return this.ws.readyState === WebSocket.CLOSED;
}
async sendResponse(data: any) {
if (data.id) {
this.emitter.emit(data.id, data?.data);
}
}
async sendConnected() {
const id = this.id;
const user = this.user;
const data = { type: 'verified', user, id };
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
this.status = 'connected';
}
if (id.includes('-registry-')) {
const newId = id.split('-registry-')[0];
this.manager.changeId(id, newId);
const ws = this.ws;
// @ts-ignore
if (this.ws?.data) {
// @ts-ignore
this.ws.data.userApp = newId;
}
}
}
getInfo() {
const shortAppId = this.id ? this.id.split('--')[1] : '';
return {
user: this.user,
id: this.id,
status: this.status,
shortAppId,
pathname: this.id ? `/${this.user}/v1/${shortAppId}` : '',
};
}
async sendData(data: any, context?: any, opts?: { timeout?: number }) {
if (this.ws.readyState !== WebSocket.OPEN) {
return { code: 500, message: 'WebSocket is not open' };
@@ -64,6 +103,7 @@ class WsMessage {
const msg = { path: data?.path, key: data?.key, id: data?.id };
return new Promise((resolve) => {
const timer = setTimeout(() => {
console.log('ws-proxy sendData timeout', msg);
resolve({
code: 500,
message: `运行超时执行的id: ${id},参数是${JSON.stringify(msg)}`,
@@ -79,7 +119,12 @@ class WsMessage {
type WssMessageOptions = {
ws: WebSocket;
user?: string;
id?: string;
realId?: string;
isLogin?: boolean;
manager: WsProxyManager;
};
export class WsProxyManager {
wssMap: Map<string, WsMessage> = new Map();
PING_INTERVAL = 30000; // 30 秒检查一次连接状态
@@ -89,7 +134,7 @@ export class WsProxyManager {
}
this.checkConnceted();
}
register(id: string, opts?: { ws: WebSocket; user: string }) {
register(id: string, opts?: { ws: WebSocket; user: string, id?: string }) {
if (this.wssMap.has(id)) {
const value = this.wssMap.get(id);
if (value) {
@@ -100,8 +145,24 @@ export class WsProxyManager {
const [username, appId] = id.split('--');
const url = new URL(`/${username}/v1/${appId}`, 'https://kevisual.cn/');
console.log('WsProxyManager register', id, '访问地址', url.toString());
const value = new WsMessage({ ws: opts?.ws, user: opts?.user });
const value = new WsMessage({ ...opts, manager: this } as WssMessageOptions);
this.wssMap.set(id, value);
return value;
}
changeId(oldId: string, newId: string) {
const value = this.wssMap.get(oldId);
const originalValue = this.wssMap.get(newId);
if (originalValue) {
logger.debug(`WsProxyManager changeId: ${newId} already exists, close old connection`);
originalValue.ws.close();
originalValue.destroy();
}
if (value) {
this.wssMap.delete(oldId);
this.wssMap.set(newId, value);
value.id = newId;
logger.debug(`WsProxyManager changeId: ${oldId} -> ${newId}`);
}
}
unregister(id: string) {
const value = this.wssMap.get(id);
@@ -117,9 +178,33 @@ export class WsProxyManager {
}
return Array.from(this.wssMap.keys());
}
getIdsInfo(beginWith?: string) {
const ids = this.getIds(beginWith);
const infoList = this.getInfoList(ids);
return {
ids,
infoList,
};
}
getInfoList(ids: string[]) {
return ids.map(id => {
const value = this.wssMap.get(id);
if (value) {
return value.getInfo();
}
return null;
}).filter(Boolean);
}
get(id: string) {
return this.wssMap.get(id);
}
createId(id: string) {
if (!this.wssMap.has(id)) {
return id;
}
const newId = id + '-' + nanoid(6);
return newId;
}
checkConnceted() {
const that = this;
setTimeout(() => {
@@ -132,4 +217,40 @@ export class WsProxyManager {
that.checkConnceted();
}, this.PING_INTERVAL);
}
async createNewConnection(opts: { ws: any; user: string, userApp: string, isLogin?: boolean }) {
const id = opts.userApp;
let realId: string = id;
const isLogin = opts.isLogin || false;
const has = this.wssMap.has(id);
const registryId = '-registry-' + generateRegistryId(); // 生成一个随机六位字符串作为注册 ID
let isNeedVerify = !isLogin;
if (has) {
const value = this.wssMap.get(id);
if (value) {
if (value.isClosed()) {
// 短时间内还在, 等于简单重启了一下应用,不需要重新注册.
logger.debug('之前的连接已关闭,复用注册 ID 连接 ws', id);
this.unregister(id);
await new Promise(resolve => setTimeout(resolve, 100));
const wsMessage = this.register(id, { ws: opts.ws, user: opts.user, id });
wsMessage.sendConnected();
return { wsMessage, isNew: false, id: id };
} else {
// 没有关闭,需要重新注册鉴权一下, 生成新的 id 连接.
isNeedVerify = true;
}
}
}
// 没有连接, 直接注册新的连接.
if (isNeedVerify) {
realId = id + registryId;
logger.debug('未登录用户,使用临时注册 ID 连接 ws', realId);
}
const wsMessage = this.register(realId, { ws: opts.ws, user: opts.user, id: realId });
return { wsMessage, isNew: true, id: realId };
}
}
// 生成一个随机六位字符串作为注册 ID
const generateRegistryId = () => {
return Math.random().toString(36).substring(2, 8);
}

View File

@@ -7,14 +7,17 @@ import { getLoginUser } from '@/modules/auth.ts';
import { createStudioAppListHtml } from '../html/studio-app-list/index.ts';
import { omit } from 'es-toolkit';
import { baseProxyUrl, proxyDomain } from '../domain.ts';
import { renderServerHtml } from '../html/render-server-html.ts';
type ProxyOptions = {
createNotFoundPage: (msg?: string) => any;
};
export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opts?: ProxyOptions) => {
const { url } = req;
const { url, method } = req;
const _url = new URL(url || '', `http://localhost`);
const { pathname, searchParams } = _url;
const isGet = method === 'GET';
let [user, app, userAppKey] = pathname.split('/').slice(1);
if (!user || !app) {
opts?.createNotFoundPage?.('应用未找到');
@@ -32,14 +35,9 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt
if (!userAppKey) {
if (isAdmin) {
// 获取所有的管理员的应用列表
const ids = wsProxyManager.getIds(user + '--');
const html = createStudioAppListHtml({ user, appIds: ids, userAppKey });
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
return;
return handleRequest(req, res, { user, app, userAppKey, isAdmin });
} else {
opts?.createNotFoundPage?.('没有访问应用权限');
opts?.createNotFoundPage?.('应用访问失败');
return false;
}
}
@@ -57,15 +55,20 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt
}
logger.debug('data', data);
const client = wsProxyManager.get(userAppKey);
const ids = wsProxyManager.getIds(user + '--');
const { ids, infoList } = wsProxyManager.getIdsInfo(user + '--');
if (!client) {
if (isGet) {
if (isAdmin) {
const html = createStudioAppListHtml({ user, appIds: ids, userAppKey });
const html = createStudioAppListHtml({ user, appIds: ids, userAppKey, infoList });
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
} else {
opts?.createNotFoundPage?.('应用访问失败');
}
} else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: '应用访问失败' }));
}
return false;
}
const path = searchParams.get('path');
@@ -80,6 +83,11 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt
if (!isAdmin) {
message = omit(data, ['token', 'cookies']);
}
if (client.status === 'waiting') {
res.writeHead(603, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: '应用没有鉴权' }));
return true;
}
const value = await client.sendData(message, {
state: { tokenUser: omit(loginUser.tokenUser, ['oauthExpand']) },
});
@@ -91,3 +99,38 @@ export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opt
opts?.createNotFoundPage?.('应用未启动');
return true;
};
const handleRequest = async (req: IncomingMessage, res: ServerResponse, opts?: { user?: string, app?: string, userAppKey?: string, isAdmin?: boolean }) => {
const { user, userAppKey } = opts || {};
const isGet = req.method === 'GET';
// 获取所有的管理员的应用列表
const { ids, infoList } = wsProxyManager.getIdsInfo(user + '--');
if (isGet) {
const html = createStudioAppListHtml({ user, appIds: ids, userAppKey, infoList });
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
return;
} else {
const url = new URL(req.url || '', 'http://localhost');
const path = url.searchParams.get('path');
if (path) {
const appId = url.searchParams.get('appId') || '';
const client = wsProxyManager.get(appId!)!;
if (!client) {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: '应用未找到' }));
return;
}
if (path === 'connected') {
client.sendConnected();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ code: 200, message: '应用已连接' }));
return;
}
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ code: 200, data: { ids, infoList } }));
return;
}
}

View File

@@ -184,7 +184,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
/**
* url是pathname的路径
*/
const url = pathname;
const url = pathname || '';
if (!domainApp && noProxyUrl.includes(url)) {
if (url === '/') {
rediretHome(req, res);
@@ -312,13 +312,14 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
const indexFile = isExist.indexFilePath; // 已经必定存在了
try {
let appFileUrl: string;
if (domainApp) {
appFileUrl = (url + '').replace(`/`, '');
} else {
appFileUrl = (url + '').replace(`/${user}/${app}/`, '');
}
appFileUrl = url.replace(`/${user}/${app}/`, '');
appFileUrl = decodeURIComponent(appFileUrl); // Decode URL components
let appFile = await userApp.getFile(appFileUrl);
if (!appFile && domainApp) {
const domainAppFileUrl = url.replace(`/`, '');
appFile = await userApp.getFile(domainAppFileUrl);
}
if (!appFile && url.endsWith('/')) {
appFile = await userApp.getFile(appFileUrl + 'index.html');
} else if (!appFile && !url.endsWith('/')) {