diff --git a/package.json b/package.json index 48816881..72ae379c 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "is-docker": "^3.0.0", "is-localhost-ip": "^2.0.0", "isbot": "^5.1.31", - "jsonwebtoken": "^9.0.2", + "jsonwebtoken": "^9.0.3", "jszip": "^3.10.1", "kafkajs": "^2.1.0", "lucide-react": "^0.543.0", @@ -143,8 +143,8 @@ "@types/react-window": "^1.8.8", "babel-plugin-react-compiler": "19.1.0-rc.2", "cross-env": "^10.1.0", - "cypress": "^13.6.6", - "extract-react-intl-messages": "^4.1.1", + "cypress": "^15.8.0", + "extract-react-intl-messages": "^5.0.0", "husky": "^9.1.7", "jest": "^29.7.0", "lint-staged": "^16.2.6", @@ -164,7 +164,7 @@ "stylelint-config-css-modules": "^4.5.1", "stylelint-config-prettier": "^9.0.3", "stylelint-config-recommended": "^14.0.0", - "tar": "^6.1.2", + "tar": "^7.5.4", "ts-jest": "^29.4.6", "ts-node": "^10.9.1", "tsup": "^8.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f2b1ce6..81a7d935 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,8 +117,8 @@ importers: specifier: ^5.1.31 version: 5.1.32 jsonwebtoken: - specifier: ^9.0.2 - version: 9.0.2 + specifier: ^9.0.3 + version: 9.0.3 jszip: specifier: ^3.10.1 version: 3.10.1 @@ -250,11 +250,11 @@ importers: specifier: ^10.1.0 version: 10.1.0 cypress: - specifier: ^13.6.6 - version: 13.17.0 + specifier: ^15.8.0 + version: 15.9.0 extract-react-intl-messages: - specifier: ^4.1.1 - version: 4.1.1(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + specifier: ^5.0.0 + version: 5.0.0(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) husky: specifier: ^9.1.7 version: 9.1.7 @@ -313,8 +313,8 @@ importers: specifier: ^14.0.0 version: 14.0.1(stylelint@15.11.0(typescript@5.9.3)) tar: - specifier: ^6.1.2 - version: 6.2.1 + specifier: ^7.5.4 + version: 7.5.4 ts-jest: specifier: ^29.4.6 version: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) @@ -566,10 +566,6 @@ packages: resolution: {integrity: sha512-co2spjR7wZoZ3Ck0H/jv76bpiuO3oJHtOmq9/gxFiod2DcT9NFg01u/hXcG8MJFnEJuMB6e3vGqS6IOnLwHqRw==} engines: {node: '>=16'} - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -687,8 +683,8 @@ packages: peerDependencies: postcss-selector-parser: ^6.0.13 - '@cypress/request@3.0.9': - resolution: {integrity: sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==} + '@cypress/request@3.0.10': + resolution: {integrity: sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==} engines: {node: '>= 6'} '@cypress/xvfb@1.2.4': @@ -1567,6 +1563,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -2936,6 +2936,9 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/tmp@0.2.6': + resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} + '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} @@ -3097,9 +3100,6 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -3310,17 +3310,13 @@ packages: chart.js: '>=2.8.0' date-fns: '>=2.0.0' - check-more-types@2.24.0: - resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} - engines: {node: '>= 0.8.0'} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} @@ -3351,8 +3347,8 @@ packages: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + cli-table3@0.6.1: + resolution: {integrity: sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==} engines: {node: 10.* || >= 12.*} cli-truncate@2.1.0: @@ -3414,6 +3410,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -3612,9 +3612,9 @@ packages: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} - cypress@13.17.0: - resolution: {integrity: sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==} - engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} + cypress@15.9.0: + resolution: {integrity: sha512-Ks6Bdilz3TtkLZtTQyqYaqtL/WT3X3APKaSLhTV96TmTyudzSjc6EJsJCHmBb7DxO+3R12q3Jkbjgm/iPgmwfg==} + engines: {node: ^20.1.0 || ^22.0.0 || >=24.0.0} hasBin: true d3-array@2.12.1: @@ -3983,9 +3983,9 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - extract-react-intl-messages@4.1.1: - resolution: {integrity: sha512-dPogci5X7HVtV7VbUxajH/1YgfNRaW2VtEiVidZ/31Tq8314uzOtzVMNo0IrAPD2E+H1wHoPiu/j565TZsyIZg==} - engines: {node: '>=10'} + extract-react-intl-messages@5.0.0: + resolution: {integrity: sha512-7K1aA3WxhhjBXsuZ2buZm5MLuPHjzkbErV2qqhf0m0K9RMqdwe6mYrOAMZ+1z1bfrngwQ2Iv44+RLjILO8qPdA==} + engines: {node: '>=20'} hasBin: true extract-zip@2.0.1: @@ -4044,6 +4044,10 @@ packages: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} + file-entry-cache@5.0.1: + resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==} + engines: {node: '>=4'} + file-entry-cache@7.0.2: resolution: {integrity: sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==} engines: {node: '>=12.0.0'} @@ -4063,6 +4067,10 @@ packages: fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + flat-cache@2.0.1: + resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==} + engines: {node: '>=4'} + flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -4071,6 +4079,9 @@ packages: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true + flatted@2.0.2: + resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} + flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} @@ -4112,10 +4123,6 @@ packages: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -4180,9 +4187,6 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} - getos@3.2.1: - resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} - getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} @@ -4285,6 +4289,10 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hasha@5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -4871,8 +4879,8 @@ packages: jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} jsprim@2.0.2: @@ -4882,11 +4890,11 @@ packages: jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - jwa@1.4.2: - resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} kafkajs@2.2.4: resolution: {integrity: sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA==} @@ -4909,10 +4917,6 @@ packages: known-css-properties@0.36.0: resolution: {integrity: sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==} - lazy-ass@1.6.0: - resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} - engines: {node: '> 0.8'} - leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -5006,10 +5010,6 @@ packages: lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - lodash.pick@4.4.0: - resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} - deprecated: This package is deprecated. Use destructuring assignment syntax instead. - lodash.truncate@4.4.2: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} @@ -5195,21 +5195,17 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} @@ -6093,8 +6089,8 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -6318,6 +6314,11 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -6751,13 +6752,19 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + systeminformation@5.30.5: + resolution: {integrity: sha512-DpWmpCckhwR3hG+6udb6/aQB7PpiqVnvSljrjbKxNSvTRsGsg7NVE3/vouoYf96xgwMxXFKcS4Ux+cnkFwYM7A==} + engines: {node: '>=8.0.0'} + os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] + hasBin: true + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} + tar@7.5.4: + resolution: {integrity: sha512-AN04xbWGrSTDmVwlI4/GTlIIwMFk/XEv7uL8aa57zuvRy6s4hdBed+lVq2fAZ89XDa7Us3ANXcE3Tvqvja1kTA==} + engines: {node: '>=18'} terser@5.43.1: resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} @@ -7142,6 +7149,10 @@ packages: resolution: {integrity: sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==} engines: {node: '>=8.3'} + write@1.0.3: + resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} + engines: {node: '>=4'} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -7156,6 +7167,10 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -7452,9 +7467,6 @@ snapshots: dependencies: '@clickhouse/client-common': 1.14.0 - '@colors/colors@1.5.0': - optional: true - '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -7552,7 +7564,7 @@ snapshots: dependencies: postcss-selector-parser: 6.1.2 - '@cypress/request@3.0.9': + '@cypress/request@3.0.10': dependencies: aws-sign2: 0.7.0 aws4: 1.13.2 @@ -7567,7 +7579,7 @@ snapshots: json-stringify-safe: 5.0.1 mime-types: 2.1.35 performance-now: 2.1.0 - qs: 6.14.0 + qs: 6.14.1 safe-buffer: 5.2.1 tough-cookie: 5.1.2 tunnel-agent: 0.6.0 @@ -8249,6 +8261,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -10102,6 +10118,8 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/tmp@0.2.6': {} + '@types/use-sync-external-store@0.0.6': {} '@types/yargs-parser@21.0.3': {} @@ -10308,8 +10326,6 @@ snapshots: async-function@1.0.0: {} - async@3.2.6: {} - asynckit@0.4.0: {} at-least-node@1.0.0: {} @@ -10563,13 +10579,11 @@ snapshots: chart.js: 4.5.1 date-fns: 2.30.0 - check-more-types@2.24.0: {} - chokidar@4.0.3: dependencies: readdirp: 4.1.2 - chownr@2.0.0: {} + chownr@3.0.0: {} ci-info@3.9.0: {} @@ -10593,11 +10607,11 @@ snapshots: dependencies: restore-cursor: 5.1.0 - cli-table3@0.6.5: + cli-table3@0.6.1: dependencies: string-width: 4.2.3 optionalDependencies: - '@colors/colors': 1.5.0 + colors: 1.4.0 cli-truncate@2.1.0: dependencies: @@ -10655,6 +10669,9 @@ snapshots: colorette@2.0.20: {} + colors@1.4.0: + optional: true + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -10870,22 +10887,22 @@ snapshots: dependencies: array-find-index: 1.0.2 - cypress@13.17.0: + cypress@15.9.0: dependencies: - '@cypress/request': 3.0.9 + '@cypress/request': 3.0.10 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) '@types/sinonjs__fake-timers': 8.1.1 '@types/sizzle': 2.3.9 + '@types/tmp': 0.2.6 arch: 2.2.0 blob-util: 2.0.2 bluebird: 3.7.2 buffer: 5.7.1 cachedir: 2.4.0 chalk: 4.1.2 - check-more-types: 2.24.0 ci-info: 4.3.0 cli-cursor: 3.1.0 - cli-table3: 0.6.5 + cli-table3: 0.6.1 commander: 6.2.1 common-tags: 1.8.2 dayjs: 1.11.13 @@ -10897,9 +10914,8 @@ snapshots: extract-zip: 2.0.1(supports-color@8.1.1) figures: 3.2.0 fs-extra: 9.1.0 - getos: 3.2.1 + hasha: 5.2.2 is-installed-globally: 0.4.0 - lazy-ass: 1.6.0 listr2: 3.14.0(enquirer@2.4.1) lodash: 4.17.21 log-symbols: 4.1.0 @@ -10909,8 +10925,8 @@ snapshots: process: 0.11.10 proxy-from-env: 1.0.0 request-progress: 3.0.0 - semver: 7.7.3 supports-color: 8.1.1 + systeminformation: 5.30.5 tmp: 0.2.5 tree-kill: 1.2.2 untildify: 4.0.0 @@ -11386,17 +11402,17 @@ snapshots: extend@3.0.2: {} - extract-react-intl-messages@4.1.1(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)): + extract-react-intl-messages@5.0.0(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)): dependencies: '@babel/core': 7.28.3 babel-plugin-react-intl: 7.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + file-entry-cache: 5.0.1 flat: 5.0.2 glob: 7.2.3 js-yaml: 3.14.1 load-json-file: 6.2.0 lodash.merge: 4.6.2 lodash.mergewith: 4.6.2 - lodash.pick: 4.4.0 meow: 6.1.1 mkdirp: 1.0.4 pify: 5.0.0 @@ -11464,6 +11480,10 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + file-entry-cache@5.0.1: + dependencies: + flat-cache: 2.0.1 + file-entry-cache@7.0.2: dependencies: flat-cache: 3.2.0 @@ -11488,6 +11508,12 @@ snapshots: mlly: 1.8.0 rollup: 4.53.3 + flat-cache@2.0.1: + dependencies: + flatted: 2.0.2 + rimraf: 2.6.3 + write: 1.0.3 + flat-cache@3.2.0: dependencies: flatted: 3.3.3 @@ -11496,6 +11522,8 @@ snapshots: flat@5.0.2: {} + flatted@2.0.2: {} + flatted@3.3.3: {} for-each@0.3.5: @@ -11548,10 +11576,6 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -11618,10 +11642,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - getos@3.2.1: - dependencies: - async: 3.2.6 - getpass@0.1.7: dependencies: assert-plus: 1.0.0 @@ -11756,6 +11776,11 @@ snapshots: dependencies: has-symbols: 1.1.0 + hasha@5.2.2: + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -12494,9 +12519,9 @@ snapshots: jsonify@0.0.1: {} - jsonwebtoken@9.0.2: + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -12521,15 +12546,15 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 - jwa@1.4.2: + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jws@3.2.2: + jws@4.0.1: dependencies: - jwa: 1.4.2 + jwa: 2.0.1 safe-buffer: 5.2.1 kafkajs@2.2.4: {} @@ -12547,8 +12572,6 @@ snapshots: known-css-properties@0.36.0: optional: true - lazy-ass@1.6.0: {} - leven@3.1.0: {} lie@3.3.0: @@ -12641,8 +12664,6 @@ snapshots: lodash.once@4.1.1: {} - lodash.pick@4.4.0: {} - lodash.truncate@4.4.2: {} lodash.uniq@4.5.0: {} @@ -12833,18 +12854,15 @@ snapshots: minimist@1.2.8: {} - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: + minizlib@3.1.0: dependencies: - minipass: 3.3.6 - yallist: 4.0.0 + minipass: 7.1.2 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 mkdirp@1.0.4: {} @@ -13688,7 +13706,7 @@ snapshots: pure-rand@7.0.1: {} - qs@6.14.0: + qs@6.14.1: dependencies: side-channel: 1.1.0 @@ -14026,6 +14044,10 @@ snapshots: rfdc@1.4.1: {} + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + rimraf@3.0.2: dependencies: glob: 7.2.3 @@ -14628,6 +14650,8 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 + systeminformation@5.30.5: {} + table@6.9.0: dependencies: ajv: 8.17.1 @@ -14636,14 +14660,13 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tar@6.2.1: + tar@7.5.4: dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 terser@5.43.1: dependencies: @@ -15050,6 +15073,10 @@ snapshots: sort-keys: 4.2.0 write-file-atomic: 3.0.3 + write@1.0.3: + dependencies: + mkdirp: 0.5.6 + xtend@4.0.2: {} y18n@5.0.8: {} @@ -15058,6 +15085,8 @@ snapshots: yallist@4.0.0: {} + yallist@5.0.0: {} + yaml@1.10.2: {} yaml@2.8.1: {} diff --git a/prisma/migrations/15_add_share/migration.sql b/prisma/migrations/15_add_share/migration.sql index d9f1e7cf..3971b54c 100644 --- a/prisma/migrations/15_add_share/migration.sql +++ b/prisma/migrations/15_add_share/migration.sql @@ -3,6 +3,7 @@ CREATE TABLE "share" ( "share_id" UUID NOT NULL, "entity_id" UUID NOT NULL, "share_type" INTEGER NOT NULL, + "name" VARCHAR(200) NOT NULL, "slug" VARCHAR(100) NOT NULL, "parameters" JSONB NOT NULL, "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, @@ -21,9 +22,10 @@ CREATE UNIQUE INDEX "share_slug_key" ON "share"("slug"); CREATE INDEX "share_entity_id_idx" ON "share"("entity_id"); -- MigrateData -INSERT INTO "share" (share_id, entity_id, share_type, slug, parameters, created_at) +INSERT INTO "share" (share_id, entity_id, name, share_type, slug, parameters, created_at) SELECT gen_random_uuid(), website_id, + name, 1, share_id, '{}'::jsonb, diff --git a/prisma/migrations/16_boards/migration.sql b/prisma/migrations/16_boards/migration.sql new file mode 100644 index 00000000..ef0b28dc --- /dev/null +++ b/prisma/migrations/16_boards/migration.sql @@ -0,0 +1,33 @@ +-- CreateTable +CREATE TABLE "board" ( + "board_id" UUID NOT NULL, + "type" VARCHAR(50) NOT NULL, + "name" VARCHAR(200) NOT NULL, + "description" VARCHAR(500) NOT NULL, + "parameters" JSONB NOT NULL, + "slug" VARCHAR(100) NOT NULL, + "user_id" UUID, + "team_id" UUID, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6), + + CONSTRAINT "board_pkey" PRIMARY KEY ("board_id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "board_board_id_key" ON "board"("board_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "board_slug_key" ON "board"("slug"); + +-- CreateIndex +CREATE INDEX "board_slug_idx" ON "board"("slug"); + +-- CreateIndex +CREATE INDEX "board_user_id_idx" ON "board"("user_id"); + +-- CreateIndex +CREATE INDEX "board_team_id_idx" ON "board"("team_id"); + +-- CreateIndex +CREATE INDEX "board_created_at_idx" ON "board"("created_at"); \ No newline at end of file diff --git a/prisma/migrations/17_remove_duplicate_key/migration.sql b/prisma/migrations/17_remove_duplicate_key/migration.sql new file mode 100644 index 00000000..a49eed8f --- /dev/null +++ b/prisma/migrations/17_remove_duplicate_key/migration.sql @@ -0,0 +1,35 @@ +-- DropIndex +DROP INDEX "board_board_id_key"; + +-- DropIndex +DROP INDEX "link_link_id_key"; + +-- DropIndex +DROP INDEX "pixel_pixel_id_key"; + +-- DropIndex +DROP INDEX "report_report_id_key"; + +-- DropIndex +DROP INDEX "revenue_revenue_id_key"; + +-- DropIndex +DROP INDEX "segment_segment_id_key"; + +-- DropIndex +DROP INDEX "session_session_id_key"; + +-- DropIndex +DROP INDEX "share_share_id_key"; + +-- DropIndex +DROP INDEX "team_team_id_key"; + +-- DropIndex +DROP INDEX "team_user_team_user_id_key"; + +-- DropIndex +DROP INDEX "user_user_id_key"; + +-- DropIndex +DROP INDEX "website_website_id_key"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 01cc372f..e58ebd0b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,7 +11,7 @@ datasource db { } model User { - id String @id @unique @map("user_id") @db.Uuid + id String @id() @map("user_id") @db.Uuid username String @unique @db.VarChar(255) password String @db.VarChar(60) role String @map("role") @db.VarChar(50) @@ -27,12 +27,13 @@ model User { pixels Pixel[] @relation("user") teams TeamUser[] reports Report[] + boards Board[] @relation("user") @@map("user") } model Session { - id String @id @unique @map("session_id") @db.Uuid + id String @id() @map("session_id") @db.Uuid websiteId String @map("website_id") @db.Uuid browser String? @db.VarChar(20) os String? @db.VarChar(20) @@ -64,7 +65,7 @@ model Session { } model Website { - id String @id @unique @map("website_id") @db.Uuid + id String @id() @map("website_id") @db.Uuid name String @db.VarChar(100) domain String? @db.VarChar(500) resetAt DateTime? @map("reset_at") @db.Timestamptz(6) @@ -185,7 +186,7 @@ model SessionData { } model Team { - id String @id() @unique() @map("team_id") @db.Uuid + id String @id() @map("team_id") @db.Uuid name String @db.VarChar(50) accessCode String? @unique @map("access_code") @db.VarChar(50) logoUrl String? @map("logo_url") @db.VarChar(2183) @@ -197,13 +198,14 @@ model Team { members TeamUser[] links Link[] pixels Pixel[] + boards Board[] @@index([accessCode]) @@map("team") } model TeamUser { - id String @id() @unique() @map("team_user_id") @db.Uuid + id String @id() @map("team_user_id") @db.Uuid teamId String @map("team_id") @db.Uuid userId String @map("user_id") @db.Uuid role String @db.VarChar(50) @@ -219,7 +221,7 @@ model TeamUser { } model Report { - id String @id() @unique() @map("report_id") @db.Uuid + id String @id() @map("report_id") @db.Uuid userId String @map("user_id") @db.Uuid websiteId String @map("website_id") @db.Uuid type String @db.VarChar(50) @@ -240,7 +242,7 @@ model Report { } model Segment { - id String @id() @unique() @map("segment_id") @db.Uuid + id String @id() @map("segment_id") @db.Uuid websiteId String @map("website_id") @db.Uuid type String @db.VarChar(50) name String @db.VarChar(200) @@ -255,7 +257,7 @@ model Segment { } model Revenue { - id String @id() @unique() @map("revenue_id") @db.Uuid + id String @id() @map("revenue_id") @db.Uuid websiteId String @map("website_id") @db.Uuid sessionId String @map("session_id") @db.Uuid eventId String @map("event_id") @db.Uuid @@ -275,7 +277,7 @@ model Revenue { } model Link { - id String @id() @unique() @map("link_id") @db.Uuid + id String @id() @map("link_id") @db.Uuid name String @db.VarChar(100) url String @db.VarChar(500) slug String @unique() @db.VarChar(100) @@ -296,7 +298,7 @@ model Link { } model Pixel { - id String @id() @unique() @map("pixel_id") @db.Uuid + id String @id() @map("pixel_id") @db.Uuid name String @db.VarChar(100) slug String @unique() @db.VarChar(100) userId String? @map("user_id") @db.Uuid @@ -315,9 +317,32 @@ model Pixel { @@map("pixel") } +model Board { + id String @id() @map("board_id") @db.Uuid + type String @db.VarChar(50) + name String @db.VarChar(200) + description String @db.VarChar(500) + parameters Json + slug String @unique() @db.VarChar(100) + userId String? @map("user_id") @db.Uuid + teamId String? @map("team_id") @db.Uuid + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) + + user User? @relation("user", fields: [userId], references: [id]) + team Team? @relation(fields: [teamId], references: [id]) + + @@index([slug]) + @@index([userId]) + @@index([teamId]) + @@index([createdAt]) + @@map("board") +} + model Share { - id String @id() @unique() @map("share_id") @db.Uuid + id String @id() @map("share_id") @db.Uuid entityId String @map("entity_id") @db.Uuid + name String @db.VarChar(200) shareType Int @map("share_type") @db.Integer slug String @unique() @db.VarChar(100) parameters Json diff --git a/scripts/build-geo.js b/scripts/build-geo.js index a83caa6c..e36b097c 100644 --- a/scripts/build-geo.js +++ b/scripts/build-geo.js @@ -3,7 +3,7 @@ import 'dotenv/config'; import fs from 'node:fs'; import path from 'node:path'; import https from 'https'; -import tar from 'tar'; +import { list } from 'tar'; import zlib from 'zlib'; if (process.env.VERCEL && !process.env.BUILD_GEO) { @@ -40,7 +40,7 @@ const isDirectMmdb = url.endsWith('.mmdb'); const downloadCompressed = url => new Promise(resolve => { https.get(url, res => { - resolve(res.pipe(zlib.createGunzip({})).pipe(tar.t())); + resolve(res.pipe(zlib.createGunzip({})).pipe(list())); }); }); diff --git a/src/app/(main)/admin/users/UserAddForm.tsx b/src/app/(main)/admin/users/UserAddForm.tsx index 6c365510..84b8399c 100644 --- a/src/app/(main)/admin/users/UserAddForm.tsx +++ b/src/app/(main)/admin/users/UserAddForm.tsx @@ -10,6 +10,7 @@ import { TextField, } from '@umami/react-zen'; import { useMessages, useUpdateQuery } from '@/components/hooks'; +import { messages } from '@/components/messages'; import { ROLES } from '@/lib/constants'; export function UserAddForm({ onSave, onClose }) { @@ -37,7 +38,10 @@ export function UserAddForm({ onSave, onClose }) { diff --git a/src/app/api/auth/logout/route.ts b/src/app/api/auth/logout/route.ts index 7bf0a813..153f1f52 100644 --- a/src/app/api/auth/logout/route.ts +++ b/src/app/api/auth/logout/route.ts @@ -1,7 +1,14 @@ import redis from '@/lib/redis'; +import { parseRequest } from '@/lib/request'; import { ok } from '@/lib/response'; export async function POST(request: Request) { + const { error } = await parseRequest(request); + + if (error) { + return error(); + } + if (redis.enabled) { const token = request.headers.get('authorization')?.split(' ')?.[1]; diff --git a/src/app/api/auth/sso/route.ts b/src/app/api/auth/sso/route.ts index bba3dde3..f8222869 100644 --- a/src/app/api/auth/sso/route.ts +++ b/src/app/api/auth/sso/route.ts @@ -1,7 +1,7 @@ import { saveAuth } from '@/lib/auth'; import redis from '@/lib/redis'; import { parseRequest } from '@/lib/request'; -import { json } from '@/lib/response'; +import { json, serverError } from '@/lib/response'; export async function POST(request: Request) { const { auth, error } = await parseRequest(request); @@ -10,9 +10,13 @@ export async function POST(request: Request) { return error(); } - if (redis.enabled) { - const token = await saveAuth({ userId: auth.user.id }, 86400); - - return json({ user: auth.user, token }); + if (!redis.enabled) { + return serverError({ + message: 'Redis is disabled', + }); } + + const token = await saveAuth({ userId: auth.user.id }, 86400); + + return json({ user: auth.user, token }); } diff --git a/src/app/api/users/[userId]/route.ts b/src/app/api/users/[userId]/route.ts index aade8aa8..e642fe3c 100644 --- a/src/app/api/users/[userId]/route.ts +++ b/src/app/api/users/[userId]/route.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; import { hashPassword } from '@/lib/password'; import { parseRequest } from '@/lib/request'; -import { badRequest, json, ok, unauthorized } from '@/lib/response'; +import { badRequest, json, notFound, ok, unauthorized } from '@/lib/response'; import { userRoleParam } from '@/lib/schema'; import { canDeleteUser, canUpdateUser, canViewUser } from '@/permissions'; import { deleteUser, getUser, getUserByUsername, updateUser } from '@/queries/prisma'; @@ -27,7 +27,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ user export async function POST(request: Request, { params }: { params: Promise<{ userId: string }> }) { const schema = z.object({ username: z.string().max(255).optional(), - password: z.string().max(255).optional(), + password: z.string().min(8).max(255).optional(), role: userRoleParam.optional(), }); @@ -47,6 +47,10 @@ export async function POST(request: Request, { params }: { params: Promise<{ use const user = await getUser(userId); + if (!user) { + return notFound(); + } + const data: any = {}; if (password) { diff --git a/src/app/api/users/route.ts b/src/app/api/users/route.ts index dbb114cf..4335c33f 100644 --- a/src/app/api/users/route.ts +++ b/src/app/api/users/route.ts @@ -4,6 +4,7 @@ import { uuid } from '@/lib/crypto'; import { hashPassword } from '@/lib/password'; import { parseRequest } from '@/lib/request'; import { badRequest, json, unauthorized } from '@/lib/response'; +import { userRoleParam } from '@/lib/schema'; import { canCreateUser } from '@/permissions'; import { createUser, getUserByUsername } from '@/queries/prisma'; @@ -11,8 +12,8 @@ export async function POST(request: Request) { const schema = z.object({ id: z.uuid().optional(), username: z.string().max(255), - password: z.string(), - role: z.string().regex(/admin|user|view-only/i), + password: z.string().min(8).max(255), + role: userRoleParam, }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/websites/[websiteId]/segments/route.ts b/src/app/api/websites/[websiteId]/segments/route.ts index 45927656..db34193e 100644 --- a/src/app/api/websites/[websiteId]/segments/route.ts +++ b/src/app/api/websites/[websiteId]/segments/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { uuid } from '@/lib/crypto'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { anyObjectParam, searchParams, segmentTypeParam } from '@/lib/schema'; +import { searchParams, segmentParamSchema, segmentTypeParam } from '@/lib/schema'; import { canUpdateWebsite, canViewWebsite } from '@/permissions'; import { createSegment, getWebsiteSegments } from '@/queries/prisma'; @@ -42,7 +42,7 @@ export async function POST( const schema = z.object({ type: segmentTypeParam, name: z.string().max(200), - parameters: anyObjectParam, + parameters: segmentParamSchema, }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/lib/auth.ts b/src/lib/auth.ts index ba6d8b09..832dfb60 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,7 +1,6 @@ import debug from 'debug'; import { ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from '@/lib/constants'; -import { secret } from '@/lib/crypto'; -import { getRandomChars } from '@/lib/generate'; +import { createAuthKey, secret } from '@/lib/crypto'; import { createSecureToken, parseSecureToken, parseToken } from '@/lib/jwt'; import redis from '@/lib/redis'; import { ensureArray } from '@/lib/utils'; @@ -53,7 +52,7 @@ export async function checkAuth(request: Request) { } export async function saveAuth(data: any, expire = 0) { - const authKey = `auth:${getRandomChars(32)}`; + const authKey = `auth:${createAuthKey()}`; if (redis.enabled) { await redis.client.set(authKey, data); diff --git a/src/lib/crypto.ts b/src/lib/crypto.ts index a6d912b8..ee4c977f 100644 --- a/src/lib/crypto.ts +++ b/src/lib/crypto.ts @@ -63,3 +63,7 @@ export function uuid(...args: any) { return process.env.USE_UUIDV7 ? v7() : v4(); } + +export function createAuthKey() { + return crypto.randomBytes(16).toString('hex'); +} diff --git a/src/lib/entity.ts b/src/lib/entity.ts index 1b64e5dd..fd26252d 100644 --- a/src/lib/entity.ts +++ b/src/lib/entity.ts @@ -1,6 +1,7 @@ +import type { Link, Pixel, Website } from '@/generated/prisma/client'; import { getLink, getPixel, getWebsite } from '@/queries/prisma'; -export async function getEntity(entityId: string) { +export async function getEntity(entityId: string): Promise { const website = await getWebsite(entityId); const link = await getLink(entityId); const pixel = await getPixel(entityId); diff --git a/src/lib/schema.ts b/src/lib/schema.ts index c860cee8..ac360a8e 100644 --- a/src/lib/schema.ts +++ b/src/lib/schema.ts @@ -104,6 +104,23 @@ export const reportTypeParam = z.enum([ 'utm', ]); +export const operatorParam = z.enum([ + 'eq', + 'neq', + 's', + 'ns', + 'c', + 'dnc', + 't', + 'f', + 'gt', + 'lt', + 'gte', + 'lte', + 'bf', + 'af', +]); + export const goalReportSchema = z.object({ type: z.literal('goal'), parameters: z @@ -157,7 +174,7 @@ export const retentionReportSchema = z.object({ parameters: z.object({ startDate: z.coerce.date(), endDate: z.coerce.date(), - timezone: z.string().optional(), + timezone: timezoneParam.optional(), }), }); @@ -175,7 +192,7 @@ export const revenueReportSchema = z.object({ startDate: z.coerce.date(), endDate: z.coerce.date(), unit: unitParam.optional(), - timezone: z.string().optional(), + timezone: timezoneParam.optional(), currency: z.string(), }), }); @@ -231,3 +248,22 @@ export const reportResultSchema = z.intersection( ); export const segmentTypeParam = z.enum(['segment', 'cohort']); + +export const segmentParamSchema = z.object({ + filters: z + .array( + z.object({ + name: z.string(), + operator: operatorParam, + value: z.string(), + }), + ) + .optional(), + dateRange: z.string().optional(), + action: z + .object({ + type: z.string(), + value: z.string(), + }) + .optional(), +}); diff --git a/src/permissions/team.ts b/src/permissions/team.ts index 0f07c1a4..784dbe4b 100644 --- a/src/permissions/team.ts +++ b/src/permissions/team.ts @@ -16,7 +16,7 @@ export async function canCreateTeam({ user }: Auth) { return true; } - return !!user; + return hasPermission(user.role, PERMISSIONS.teamCreate); } export async function canUpdateTeam({ user }: Auth, teamId: string) { diff --git a/src/permissions/website.ts b/src/permissions/website.ts index 97952eed..4008449d 100644 --- a/src/permissions/website.ts +++ b/src/permissions/website.ts @@ -1,7 +1,8 @@ import { hasPermission } from '@/lib/auth'; import { PERMISSIONS } from '@/lib/constants'; +import { getEntity } from '@/lib/entity'; import type { Auth } from '@/lib/types'; -import { getLink, getPixel, getTeamUser, getWebsite } from '@/queries/prisma'; +import { getTeamUser, getWebsite } from '@/queries/prisma'; export async function canViewWebsite({ user, shareToken }: Auth, websiteId: string) { if (user?.isAdmin) { @@ -12,11 +13,7 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri return true; } - const website = await getWebsite(websiteId); - const link = await getLink(websiteId); - const pixel = await getPixel(websiteId); - - const entity = website || link || pixel; + const entity = await getEntity(websiteId); if (!entity) { return false; diff --git a/src/queries/prisma/user.ts b/src/queries/prisma/user.ts index 14376fc2..467ea1e0 100644 --- a/src/queries/prisma/user.ts +++ b/src/queries/prisma/user.ts @@ -18,7 +18,7 @@ async function findUser(criteria: Prisma.UserFindUniqueArgs, options: GetUserOpt ...criteria, where: { ...criteria.where, - ...(showDeleted && { deletedAt: null }), + ...(showDeleted ? {} : { deletedAt: null }), }, select: { id: true,