diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 0659574a..53141295 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -30,7 +30,12 @@ jobs: image-name: compute-consumer-ui-plugin context: . dockerfile-path: ui/consumer/Dockerfile - secrets: inherit + # The Sentry token goes in as a BuildKit secret only. `secrets: inherit` + # would also pass it to publish-docker's SENTRY_AUTH_TOKEN, which it + # forwards as a build-arg, and build-args persist in the exported cache. + secrets: + build-secrets: | + "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" # Deployed as a Component (config/components/provider-ui-plugin) folded # into compute-manager's own kustomize bundle/Flux Kustomization — same diff --git a/ui/consumer/Dockerfile b/ui/consumer/Dockerfile index 2f4663cd..c4808e3d 100644 --- a/ui/consumer/Dockerfile +++ b/ui/consumer/Dockerfile @@ -44,7 +44,11 @@ RUN npm install -g "$(node -p 'require("./package.json").packageManager')" --no- COPY ui/consumer/ . COPY --from=console-wasm /out/ /console-wasm/ ENV CONSOLE_WASM_DIR=/console-wasm -RUN pnpm build +# The Sentry token is a BuildKit secret (publish-docker's build-secrets), so it +# never lands in a layer, the image history or the exported build cache. When +# absent the file is missing, the variable is empty and the upload is skipped. +RUN --mount=type=secret,id=SENTRY_AUTH_TOKEN,required=false \ + SENTRY_AUTH_TOKEN="$(cat /run/secrets/SENTRY_AUTH_TOKEN 2>/dev/null)" pnpm build FROM node:26.13.0-alpine3.24@sha256:c6ad9e9c1d80f6eb607c26b4b0a132ff7a2344fad1c78ea3baa2a7d4c8de6d94 # Node keeps its own copy of the CA roots apart from Alpine's bundle. Fail the diff --git a/ui/consumer/package.json b/ui/consumer/package.json index cf63f851..b5a53967 100644 --- a/ui/consumer/package.json +++ b/ui/consumer/package.json @@ -34,6 +34,7 @@ }, "devDependencies": { "@module-federation/vite": "^1.23.9", + "@sentry/vite-plugin": "5.4.1", "@types/node": "^26.6.6", "@types/react": "^19.3.0", "@types/react-dom": "^19.3.0", diff --git a/ui/consumer/pnpm-lock.yaml b/ui/consumer/pnpm-lock.yaml index 00c06662..d600b664 100644 --- a/ui/consumer/pnpm-lock.yaml +++ b/ui/consumer/pnpm-lock.yaml @@ -69,6 +69,9 @@ importers: '@module-federation/vite': specifier: ^1.23.9 version: 1.23.9(typescript@7.0.2)(vite@7.3.7(@types/node@26.6.6)) + '@sentry/vite-plugin': + specifier: 5.4.1 + version: 5.4.1(rollup@4.62.2) '@types/node': specifier: ^26.6.6 version: 26.6.6 @@ -1231,6 +1234,82 @@ packages: cpu: [x64] os: [win32] + '@sentry/bundler-plugins@10.78.0': + resolution: {integrity: sha512-vI52/j8xjDewXfbfdL0V/wKPMUUAp6e5rf5Xww8lJB9cNhCT5nQ71c78GE48wFuDEn7PuD9e9t6gvYujrESZkA==} + engines: {node: '>= 18'} + peerDependencies: + rollup: '>=3.2.0' + webpack: '>=5.0.0' + peerDependenciesMeta: + rollup: + optional: true + webpack: + optional: true + + '@sentry/cli-darwin@2.58.6': + resolution: {integrity: sha512-udAVvcyfNa0R+95GvPz/+43/N3TC0TYKdkQ7D7jhPSzbcMc7l2fxRNN5yB3UpCA5fWFnW4toeaqwDBhb/Wh3LA==} + engines: {node: '>=10'} + os: [darwin] + + '@sentry/cli-linux-arm64@2.58.6': + resolution: {integrity: sha512-q8mEcNNmeXMy5i+jWT30TVpH7LcP4HD21CD5XRSPAd/a912HF6EpK0ybf/1USO14WOhoXbAGi9txwaWabSe33g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux, freebsd, android] + + '@sentry/cli-linux-arm@2.58.6': + resolution: {integrity: sha512-pD0LAt5PcUzAinBwvDqc66x9+2CabHEv486yP0gRjWO7SakbaxmfVq/EXd8VLq/Tzi39LAu422UYK1lpW3MILw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux, freebsd, android] + + '@sentry/cli-linux-i686@2.58.6': + resolution: {integrity: sha512-q8vNJi1eOV/4vxAFWBsEwLHoSYapaZHIf4j76KJGJXFKTkEbsjCOOsKbwUIBTQQhRgV4DFWh3ryfsPS/que4Kg==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [linux, freebsd, android] + + '@sentry/cli-linux-x64@2.58.6': + resolution: {integrity: sha512-DZu956Mhi3ZRjTBe1WdbGV46ldVbA8d2rgp/fh51GsI25zjBHah4wZnPTSzpc+YqxU6pJpg579B/r3jrIK530Q==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux, freebsd, android] + + '@sentry/cli-win32-arm64@2.58.6': + resolution: {integrity: sha512-nj0Ff/kmAB73EPDhR8B4O9r+NUHK5GkPCkGWC+kXVemqAJWL5jcJ5KdxG0l/S0z6RoEoltID8/43/B+TaMlT7A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@sentry/cli-win32-i686@2.58.6': + resolution: {integrity: sha512-WNZiDzPbgsEMQWq4avsQ391v/xWKJDIWWWo9GYl+N/w5qcYKkoDW7wQG7T9FasI6ENn68phChTOAPXXxbfAdOg==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [win32] + + '@sentry/cli-win32-x64@2.58.6': + resolution: {integrity: sha512-R35WJ17oF4D2eqI1DR2sQQqr0fjRTt5xoP16WrTu91XM2lndRMFsnjh+/GttbxapLCBNlrjzia99MJ0PZHZpgA==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@sentry/cli@2.58.6': + resolution: {integrity: sha512-baBcNPLLfUi9WuL+Tpri9BFaAdvugZIKelC5X0tt0Zdy+K0K+PCVSrnNmwMWU/HyaF/SEv6b6UHnXIdqanBlcg==} + engines: {node: '>= 10'} + hasBin: true + + '@sentry/conventions@0.16.0': + resolution: {integrity: sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==} + engines: {node: '>=14'} + + '@sentry/core@10.78.0': + resolution: {integrity: sha512-MMR4ME+agrjbvQ0DtTYJJypm+QlCoz9UJgWN8gjcXqlyDjYk69LwPjnaocYN1JyQMy2dx5Hk4S/Rt12gTQ5cGw==} + engines: {node: '>=18'} + + '@sentry/vite-plugin@5.4.1': + resolution: {integrity: sha512-poFfn3sQbSFaZpXH8CG27D0eNtDD64wFEniQCb853e7huko9vOl4UP3BjT3vsrnmVuRqagnbxItza10MOC7ysA==} + engines: {node: '>= 18'} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -1495,6 +1574,10 @@ packages: resolution: {integrity: sha512-Xwrja8nx9e5o2N1my4DsKCeKpdrnACyr1wtbPxBDgGzKzKyE9kRtBFA8mWldI+RVlD7CBZNWY/wQ2+ydwOR6kQ==} engines: {node: '>=14.0'} + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + ai@7.0.161: resolution: {integrity: sha512-DcHxTJKuAqGFZST4RgE5nCfciY+P6ym9/TKq/5UHh0U/0d4V1k+1xvYSpMR5Rq+akjeerw5teL6AXJVwmoludg==} engines: {node: '>=22'} @@ -1509,6 +1592,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + baseline-browser-mapping@2.11.1: resolution: {integrity: sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==} engines: {node: '>=6.0.0'} @@ -1517,6 +1604,10 @@ packages: bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + browserslist@4.28.7: resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -1632,6 +1723,10 @@ packages: dompurify@3.4.17: resolution: {integrity: sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + electron-to-chromium@1.5.395: resolution: {integrity: sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==} @@ -1677,6 +1772,10 @@ packages: picomatch: optional: true + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + framer-motion@13.5.1: resolution: {integrity: sha512-HeWOaeHD3kyTSIEMT6+nw7fBn4saIfxxabZyAITbycAl4xr1kzGJKIvGt/OWghSlvIA9qTnZ1zTGelHAe6S8DA==} peerDependencies: @@ -1701,10 +1800,18 @@ packages: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + immer@11.1.18: resolution: {integrity: sha512-EQyQtLiYW029lyoczMl/Hh4Xu7cDecSc58JRYpHyL4tIAu3eqd1yJzQX04d2BZHDkzFFvm6qJEJWOtfDSWAXbQ==} @@ -1715,6 +1822,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic-dompurify@3.22.0: resolution: {integrity: sha512-cz/BkSODnQir4IV2quqbuEHhAGz4MAYGvhoemsxuwMpY/oZbRHlNjPLPyIQ0fdULiwDPUE+OHPwWb6XTEiNk1A==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} @@ -1750,6 +1860,10 @@ packages: engines: {node: '>=6'} hasBin: true + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + lru-cache@11.5.2: resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} @@ -1771,12 +1885,23 @@ packages: '@types/react': optional: true + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@1.4.5: resolution: {integrity: sha512-oLLC2+YvQUfAa+vxoufE/yc1icb87M9iXIRqAoR/2EhE/8cb3SF/+Gi0c2By1B+5Vz2e2vQtUvHiu1+63Znh+w==} mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + monaco-editor@0.52.2: resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} @@ -1805,6 +1930,15 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-releases@2.0.51: resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} engines: {node: '>=18'} @@ -1834,9 +1968,25 @@ packages: resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} engines: {node: '>=12.20.0'} + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + parse5@8.0.1: resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1848,6 +1998,13 @@ packages: resolution: {integrity: sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==} engines: {node: ^10 || ^12 || >=14} + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2021,6 +2178,9 @@ packages: resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} @@ -2166,6 +2326,9 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@8.0.1: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} @@ -2182,6 +2345,14 @@ packages: resolution: {integrity: sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==} engines: {node: ^22.14.0 || >=24.0.0} + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + why-is-node-running@3.2.1: resolution: {integrity: sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==} engines: {node: '>=20.11'} @@ -2209,6 +2380,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + zod@4.6.7: resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} @@ -3203,6 +3378,80 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.62.2': optional: true + '@sentry/bundler-plugins@10.78.0(rollup@4.62.2)': + dependencies: + '@babel/core': 7.29.7 + '@sentry/cli': 2.58.6 + '@sentry/core': 10.78.0 + dotenv: 17.4.2 + find-up: 5.0.0 + glob: 13.0.6 + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.62.2 + transitivePeerDependencies: + - encoding + - supports-color + + '@sentry/cli-darwin@2.58.6': + optional: true + + '@sentry/cli-linux-arm64@2.58.6': + optional: true + + '@sentry/cli-linux-arm@2.58.6': + optional: true + + '@sentry/cli-linux-i686@2.58.6': + optional: true + + '@sentry/cli-linux-x64@2.58.6': + optional: true + + '@sentry/cli-win32-arm64@2.58.6': + optional: true + + '@sentry/cli-win32-i686@2.58.6': + optional: true + + '@sentry/cli-win32-x64@2.58.6': + optional: true + + '@sentry/cli@2.58.6': + dependencies: + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0 + progress: 2.0.3 + proxy-from-env: 1.1.0 + which: 2.0.2 + optionalDependencies: + '@sentry/cli-darwin': 2.58.6 + '@sentry/cli-linux-arm': 2.58.6 + '@sentry/cli-linux-arm64': 2.58.6 + '@sentry/cli-linux-i686': 2.58.6 + '@sentry/cli-linux-x64': 2.58.6 + '@sentry/cli-win32-arm64': 2.58.6 + '@sentry/cli-win32-i686': 2.58.6 + '@sentry/cli-win32-x64': 2.58.6 + transitivePeerDependencies: + - encoding + - supports-color + + '@sentry/conventions@0.16.0': {} + + '@sentry/core@10.78.0': + dependencies: + '@sentry/conventions': 0.16.0 + + '@sentry/vite-plugin@5.4.1(rollup@4.62.2)': + dependencies: + '@sentry/bundler-plugins': 10.78.0(rollup@4.62.2) + transitivePeerDependencies: + - encoding + - rollup + - supports-color + - webpack + '@standard-schema/spec@1.1.0': {} '@standard-schema/utils@0.3.0': {} @@ -3407,6 +3656,12 @@ snapshots: adm-zip@0.6.1: {} + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + ai@7.0.161(zod@4.6.7): dependencies: '@ai-sdk/gateway': 4.0.134(zod@4.6.7) @@ -3420,12 +3675,18 @@ snapshots: assertion-error@2.0.1: {} + balanced-match@4.0.4: {} + baseline-browser-mapping@2.11.1: {} bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + browserslist@4.28.7: dependencies: baseline-browser-mapping: 2.11.1 @@ -3532,6 +3793,8 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 + dotenv@17.4.2: {} + electron-to-chromium@1.5.395: {} entities@8.0.0: {} @@ -3585,6 +3848,11 @@ snapshots: optionalDependencies: picomatch: 4.0.7 + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + framer-motion@13.5.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: motion-dom: 13.5.1 @@ -3601,18 +3869,33 @@ snapshots: get-nonce@1.0.1: {} + glob@13.0.6: + dependencies: + minimatch: 10.2.6 + minipass: 7.1.3 + path-scurry: 2.0.2 + html-encoding-sniffer@6.0.0: dependencies: '@exodus/bytes': 1.15.1 transitivePeerDependencies: - '@noble/hashes' + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + immer@11.1.18: {} internmap@2.0.3: {} is-potential-custom-element-name@1.0.1: {} + isexe@2.0.0: {} + isomorphic-dompurify@3.22.0: dependencies: dompurify: 3.4.17 @@ -3659,6 +3942,10 @@ snapshots: json5@2.2.3: {} + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + lru-cache@11.5.2: {} lru-cache@5.1.1: @@ -3675,12 +3962,22 @@ snapshots: optionalDependencies: '@types/react': 19.3.0 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + magic-string@1.4.5: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 mdn-data@2.27.1: {} + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + + minipass@7.1.3: {} + monaco-editor@0.52.2: {} motion-dom@13.5.1: @@ -3701,6 +3998,10 @@ snapshots: nanoid@3.3.20: {} + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-releases@2.0.51: {} nuqs@2.10.2(react-router@8.3.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0): @@ -3712,10 +4013,25 @@ snapshots: obug@3.0.0: {} + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + parse5@8.0.1: dependencies: entities: 8.0.0 + path-exists@4.0.0: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + picocolors@1.1.1: {} picomatch@4.0.7: {} @@ -3726,6 +4042,10 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.2 + progress@2.0.3: {} + + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} react-day-picker@10.0.2(@types/react@19.3.0)(react@19.3.0): @@ -3897,6 +4217,8 @@ snapshots: dependencies: tldts: 7.4.9 + tr46@0.0.3: {} + tr46@6.0.0: dependencies: punycode: 2.3.1 @@ -4014,6 +4336,8 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + webidl-conversions@3.0.1: {} + webidl-conversions@8.0.1: {} whatwg-mimetype@5.0.0: {} @@ -4034,6 +4358,15 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + why-is-node-running@3.2.1: {} ws@8.21.3: {} @@ -4044,4 +4377,6 @@ snapshots: yallist@3.1.1: {} + yocto-queue@0.1.0: {} + zod@4.6.7: {} diff --git a/ui/consumer/pnpm-workspace.yaml b/ui/consumer/pnpm-workspace.yaml index d08daa52..b14ac1ab 100644 --- a/ui/consumer/pnpm-workspace.yaml +++ b/ui/consumer/pnpm-workspace.yaml @@ -20,9 +20,10 @@ minimumReleaseAgeExclude: - '@tanstack/virtual-core@3.19.11' - lucide-react@1.67.0 -# esbuild checks its platform binary on install. CI and the image install with -# --ignore-scripts. +# esbuild and @sentry/cli check their platform binaries on install. CI and the +# image install with --ignore-scripts. allowBuilds: + '@sentry/cli': true esbuild: true fsevents: false diff --git a/ui/consumer/vite.config.ts b/ui/consumer/vite.config.ts index 326eed82..96c9612b 100644 --- a/ui/consumer/vite.config.ts +++ b/ui/consumer/vite.config.ts @@ -1,5 +1,6 @@ /// import { federation } from '@module-federation/vite'; +import { sentryVitePlugin } from '@sentry/vite-plugin'; import react from '@vitejs/plugin-react'; import { existsSync, readFileSync } from 'node:fs'; import { resolve } from 'node:path'; @@ -79,87 +80,115 @@ function consoleWasm(): Plugin { // browser never contacts this origin directly. MF's automatic publicPath makes // federated chunks resolve relative to remoteEntry.js, which is what lets them // load correctly through that same-origin proxy prefix. -export default defineConfig({ - server: { - port: 7778, - strictPort: true, - // Allow cross-origin fetches of the manifest/remote during Tier 0/standalone. - cors: true, - }, - preview: { - port: 7778, - // Bind IPv4 explicitly — "localhost"-only binding resolves to IPv6-only - // ([::1]) on some hosts, and the portal's server-side manifest fetch to - // http://localhost:7778 then gets ECONNREFUSED on IPv4, silently dropping - // the plugin out of the registry with no visible error. - host: '127.0.0.1', - strictPort: true, - cors: true, - }, - build: { - target: 'esnext', - // Minified: the portal downloads and parses every page's chunks on first - // visit, and minifying cuts the bundle from ~6.0MB to ~2.5MB (~1.3MB to - // ~0.8MB gzipped). Source maps keep it readable in devtools; the browser - // fetches them only when devtools is open. - sourcemap: true, - }, - experimental: { - renderBuiltUrl(_filename, { hostType }) { - return hostType === 'js' ? { relative: true } : undefined; +export default defineConfig(({ command }) => { + const hostShared = (requiredVersion: string | false) => ({ + singleton: true, + requiredVersion, + ...(command === 'build' ? { import: false as const } : {}), + }); + + return { + server: { + port: 7778, + strictPort: true, + // Allow cross-origin fetches of the manifest/remote during Tier 0/standalone. + cors: true, }, - }, - plugins: [ - react(), - consoleWasm(), - federation({ - // MUST equal the manifest `name` — the host keys the remote by this id. - name: 'workload.compute.datumapis.com', - // The manifest's `remoteEntry` field points the host at this filename, - // requested through the asset proxy as /api/plugins/compute/remoteEntry.js. - filename: 'remoteEntry.js', - manifest: true, - // Exposed keys map 1:1 to the manifest's `exposedModules` keys / $codeRefs. - // The host loads e.g. loadRemote('workload.compute.datumapis.com/WorkloadList'). - exposes: { - './WorkloadList': './src/pages/workload-list.tsx', - './WorkloadDetail': './src/pages/workload-detail.tsx', - './InstanceDetail': './src/pages/instance-detail.tsx', - './InstanceShellWindow': './src/pages/instance-shell-window.tsx', - './WorkloadsHomeColumn': './src/cards/workloads-home-column.tsx', - }, - // Host-pinned singletons. requiredVersion tracks the host's majors - // (react 19, react-router 8, react-query 5) — cloud-portal moved - // react-router 7 -> 8 in fabef049 without bumping this, which silently - // broke every plugin page here (Module Federation rejects a singleton - // whose requiredVersion the host's actual version doesn't satisfy). - // Keep this in lockstep with cloud-portal's package.json majors. - // singleton:true guarantees one instance — the host provides all of - // these, so plugin queries share the host's QueryClient cache. - shared: { - react: { singleton: true, requiredVersion: '^19.0.0' }, - 'react-dom': { singleton: true, requiredVersion: '^19.0.0' }, - 'react-router': { singleton: true, requiredVersion: '^8.0.0' }, - '@tanstack/react-query': { singleton: true, requiredVersion: '^5.0.0' }, - // Curated datum-ui subset shared by the host (see the host's - // federation-host.ts DATUM_UI_SHARED). requiredVersion:false — the - // host's copy always wins, which is what keeps styling identical to - // built-in pages; the local install is types + standalone fallback. - '@datum-cloud/datum-ui/badge': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/button': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/card': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/empty-content': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/icons': { singleton: true, requiredVersion: false }, - // Do not share `logs`: MF colocates lucide-react / date-fns into the - // logs loadShare chunk, so a host-provided logs module replaces those - // exports and crashes WorkloadDetail / related pages. - // `select` is shared by the host (see cloud-portal `federation-host.ts`) so - // the overview range control renders the same Select as ALB. - '@datum-cloud/datum-ui/select': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/separator': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/skeleton': { singleton: true, requiredVersion: false }, - '@datum-cloud/datum-ui/table': { singleton: true, requiredVersion: false }, + preview: { + port: 7778, + // Bind IPv4 explicitly — "localhost"-only binding resolves to IPv6-only + // ([::1]) on some hosts, and the portal's server-side manifest fetch to + // http://localhost:7778 then gets ECONNREFUSED on IPv4, silently dropping + // the plugin out of the registry with no visible error. + host: '127.0.0.1', + strictPort: true, + cors: true, + }, + build: { + target: 'esnext', + // Minified: the portal downloads and parses every page's chunks on first + // visit, and minifying cuts the bundle from ~6.0MB to ~2.5MB (~1.3MB to + // ~0.8MB gzipped). Source maps keep it readable in devtools; the browser + // fetches them only when devtools is open. + sourcemap: true, + }, + experimental: { + renderBuiltUrl(_filename, { hostType }) { + return hostType === 'js' ? { relative: true } : undefined; }, - }), - ], + }, + plugins: [ + react(), + consoleWasm(), + federation({ + // MUST equal the manifest `name` — the host keys the remote by this id. + name: 'workload.compute.datumapis.com', + // The manifest's `remoteEntry` field points the host at this filename, + // requested through the asset proxy as /api/plugins/compute/remoteEntry.js. + filename: 'remoteEntry.js', + manifest: true, + // Exposed keys map 1:1 to the manifest's `exposedModules` keys / $codeRefs. + // The host loads e.g. loadRemote('workload.compute.datumapis.com/WorkloadList'). + exposes: { + './WorkloadList': './src/pages/workload-list.tsx', + './WorkloadDetail': './src/pages/workload-detail.tsx', + './InstanceDetail': './src/pages/instance-detail.tsx', + './InstanceShellWindow': './src/pages/instance-shell-window.tsx', + './WorkloadsHomeColumn': './src/cards/workloads-home-column.tsx', + }, + // Host-pinned singletons. requiredVersion tracks the host's majors + // (react 19, react-router 8, react-query 5) — cloud-portal moved + // react-router 7 -> 8 in fabef049 without bumping this, which silently + // broke every plugin page here (Module Federation rejects a singleton + // whose requiredVersion the host's actual version doesn't satisfy). + // Keep this in lockstep with cloud-portal's package.json majors. + // singleton:true guarantees one instance — the host provides all of + // these, so plugin queries share the host's QueryClient cache. + // Builds rely on the host for these (import: false), so they bundle no + // fallback copy, which the browser would otherwise fetch and parse on + // every load though the host's copy always wins. Dev keeps the + // fallbacks so the standalone preview runs without a host. + shared: { + react: hostShared('^19.0.0'), + // The host does not share this subpath, so it keeps its (small) + // fallback; left implicit it would inherit import: false from + // `react` and throw "must be provided by host". + 'react/jsx-runtime': { singleton: true, requiredVersion: '^19.0.0' }, + 'react-dom': hostShared('^19.0.0'), + 'react-router': hostShared('^8.0.0'), + '@tanstack/react-query': hostShared('^5.0.0'), + // Curated datum-ui subset shared by the host (see the host's + // federation-host.ts DATUM_UI_SHARED). requiredVersion:false — the + // host's copy always wins, which is what keeps styling identical to + // built-in pages; the local install is types + standalone fallback. + '@datum-cloud/datum-ui/badge': hostShared(false), + '@datum-cloud/datum-ui/button': hostShared(false), + '@datum-cloud/datum-ui/card': hostShared(false), + '@datum-cloud/datum-ui/empty-content': hostShared(false), + '@datum-cloud/datum-ui/icons': hostShared(false), + // Do not share `logs`: MF colocates lucide-react / date-fns into the + // logs loadShare chunk, so a host-provided logs module replaces those + // exports and crashes WorkloadDetail / related pages. + // `select` is shared by the host (see cloud-portal `federation-host.ts`) so + // the overview range control renders the same Select as ALB. + '@datum-cloud/datum-ui/select': hostShared(false), + '@datum-cloud/datum-ui/separator': hostShared(false), + '@datum-cloud/datum-ui/skeleton': hostShared(false), + '@datum-cloud/datum-ui/table': hostShared(false), + }, + }), + // The plugin runs inside cloud-portal, so its errors reach the portal's + // Sentry project. Debug IDs tie frames to these maps without a release, + // since the portal's release names its own build, not this plugin's. + // No token (local builds, forks) skips the upload. + sentryVitePlugin({ + org: 'sentry', + project: 'cloud-portal', + authToken: process.env.SENTRY_AUTH_TOKEN, + disable: command !== 'build' || !process.env.SENTRY_AUTH_TOKEN, + release: { create: false, finalize: false, inject: false }, + telemetry: false, + }), + ], + }; });