mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-14 17:41:20 +00:00
added index manager
This commit is contained in:
parent
28fd2fd2d1
commit
7a33cc7f65
142
package-lock.json
generated
142
package-lock.json
generated
@ -1,27 +1,21 @@
|
||||
{
|
||||
"name": "qapp-core",
|
||||
"version": "1.0.11",
|
||||
"version": "1.0.13",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "qapp-core",
|
||||
"version": "1.0.11",
|
||||
"version": "1.0.13",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"@tanstack/react-virtual": "^3.13.2",
|
||||
"@types/react": "^19.0.10",
|
||||
"bloom-filters": "^3.0.4",
|
||||
"buffer": "^6.0.3",
|
||||
"compressorjs": "^1.2.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.4",
|
||||
"react": "^19.0.0",
|
||||
"react-dropzone": "^14.3.8",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-intersection-observer": "^9.16.0",
|
||||
@ -29,15 +23,29 @@
|
||||
"zustand": "^4.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/react": "^19.0.10",
|
||||
"react": "^19.0.0",
|
||||
"tsup": "^8.4.0",
|
||||
"typescript": "^5.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.26.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
||||
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.25.9",
|
||||
"js-tokens": "^4.0.0",
|
||||
@ -51,6 +59,7 @@
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
|
||||
"integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.26.9",
|
||||
"@babel/types": "^7.26.9",
|
||||
@ -66,6 +75,7 @@
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
|
||||
"integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/traverse": "^7.25.9",
|
||||
"@babel/types": "^7.25.9"
|
||||
@ -78,6 +88,7 @@
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
|
||||
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@ -86,6 +97,7 @@
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
|
||||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@ -94,6 +106,7 @@
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
|
||||
"integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.26.9"
|
||||
},
|
||||
@ -108,6 +121,7 @@
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
|
||||
"integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@ -119,6 +133,7 @@
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
|
||||
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"@babel/parser": "^7.26.9",
|
||||
@ -132,6 +147,7 @@
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
|
||||
"integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"@babel/generator": "^7.26.9",
|
||||
@ -149,6 +165,7 @@
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
|
||||
"integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.25.9",
|
||||
"@babel/helper-validator-identifier": "^7.25.9"
|
||||
@ -161,6 +178,7 @@
|
||||
"version": "11.13.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
|
||||
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
@ -179,6 +197,7 @@
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@ -187,6 +206,7 @@
|
||||
"version": "11.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
|
||||
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
"@emotion/sheet": "^1.4.0",
|
||||
@ -198,12 +218,14 @@
|
||||
"node_modules/@emotion/hash": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
|
||||
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="
|
||||
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz",
|
||||
"integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.9.0"
|
||||
}
|
||||
@ -211,12 +233,14 @@
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
|
||||
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
|
||||
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@emotion/react": {
|
||||
"version": "11.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
|
||||
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@ -240,6 +264,7 @@
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
|
||||
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@emotion/hash": "^0.9.2",
|
||||
"@emotion/memoize": "^0.9.0",
|
||||
@ -251,12 +276,14 @@
|
||||
"node_modules/@emotion/sheet": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
|
||||
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="
|
||||
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@emotion/styled": {
|
||||
"version": "11.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz",
|
||||
"integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@ -278,12 +305,14 @@
|
||||
"node_modules/@emotion/unitless": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
|
||||
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="
|
||||
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
|
||||
"integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
@ -291,12 +320,14 @@
|
||||
"node_modules/@emotion/utils": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
|
||||
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA=="
|
||||
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@emotion/weak-memoize": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
|
||||
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="
|
||||
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.1",
|
||||
@ -719,6 +750,7 @@
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
@ -732,6 +764,7 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
@ -740,6 +773,7 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
@ -747,12 +781,14 @@
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
@ -762,6 +798,7 @@
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.7.tgz",
|
||||
"integrity": "sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
@ -771,6 +808,7 @@
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.4.7.tgz",
|
||||
"integrity": "sha512-Rk8cs9ufQoLBw582Rdqq7fnSXXZTqhYRbpe1Y5SAz9lJKZP3CIdrj0PfG8HJLGw1hrsHFN/rkkm70IDzhJsG1g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0"
|
||||
},
|
||||
@ -796,6 +834,7 @@
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.7.tgz",
|
||||
"integrity": "sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@mui/core-downloads-tracker": "^6.4.7",
|
||||
@ -844,6 +883,7 @@
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.6.tgz",
|
||||
"integrity": "sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@mui/utils": "^6.4.6",
|
||||
@ -870,6 +910,7 @@
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.6.tgz",
|
||||
"integrity": "sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@emotion/cache": "^11.13.5",
|
||||
@ -903,6 +944,7 @@
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.7.tgz",
|
||||
"integrity": "sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@mui/private-theming": "^6.4.6",
|
||||
@ -942,6 +984,7 @@
|
||||
"version": "7.2.21",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz",
|
||||
"integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
@ -955,6 +998,7 @@
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz",
|
||||
"integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@mui/types": "^7.2.21",
|
||||
@ -994,6 +1038,7 @@
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
@ -1286,17 +1331,20 @@
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
|
||||
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
|
||||
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="
|
||||
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz",
|
||||
"integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@ -1305,6 +1353,7 @@
|
||||
"version": "4.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
|
||||
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
@ -1362,6 +1411,7 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"cosmiconfig": "^7.0.0",
|
||||
@ -1488,6 +1538,7 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@ -1511,6 +1562,7 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@ -1563,12 +1615,14 @@
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
@ -1584,6 +1638,7 @@
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
@ -1626,6 +1681,7 @@
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
@ -1642,6 +1698,7 @@
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
@ -1671,6 +1728,7 @@
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
@ -1719,6 +1777,7 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@ -1754,7 +1813,8 @@
|
||||
"node_modules/find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.1",
|
||||
@ -1790,6 +1850,7 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@ -1818,6 +1879,7 @@
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@ -1834,6 +1896,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
@ -1845,6 +1908,7 @@
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
@ -1852,7 +1916,8 @@
|
||||
"node_modules/hoist-non-react-statics/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
@ -1877,6 +1942,7 @@
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
@ -1892,6 +1958,7 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@ -1899,7 +1966,8 @@
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/is-blob": {
|
||||
"version": "2.1.0",
|
||||
@ -1938,6 +2006,7 @@
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
@ -1996,6 +2065,7 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
|
||||
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
@ -2006,7 +2076,8 @@
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.3",
|
||||
@ -2023,7 +2094,8 @@
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/load-tsconfig": {
|
||||
"version": "0.2.5",
|
||||
@ -2094,7 +2166,8 @@
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
@ -2145,6 +2218,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"callsites": "^3.0.0"
|
||||
},
|
||||
@ -2156,6 +2230,7 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"error-ex": "^1.3.1",
|
||||
@ -2181,7 +2256,8 @@
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
@ -2203,6 +2279,7 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -2210,7 +2287,8 @@
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
@ -2398,12 +2476,14 @@
|
||||
"node_modules/react-is": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz",
|
||||
"integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g=="
|
||||
"integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
@ -2436,12 +2516,14 @@
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.16.0",
|
||||
"path-parse": "^1.0.7",
|
||||
@ -2679,7 +2761,8 @@
|
||||
"node_modules/stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.35.0",
|
||||
@ -2707,6 +2790,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
|
25
package.json
25
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qapp-core",
|
||||
"version": "1.0.12",
|
||||
"version": "1.0.13",
|
||||
"description": "Qortal's core React library with global state, UI components, and utilities",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
@ -15,34 +15,41 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format esm,cjs --dts",
|
||||
"build": "tsup",
|
||||
"prepare": "npm run build",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"@tanstack/react-virtual": "^3.13.2",
|
||||
"@types/react": "^19.0.10",
|
||||
"bloom-filters": "^3.0.4",
|
||||
"buffer": "^6.0.3",
|
||||
"compressorjs": "^1.2.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.4",
|
||||
"react": "^19.0.0",
|
||||
"react-dropzone": "^14.3.8",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-intersection-observer": "^9.16.0",
|
||||
"short-unique-id": "^5.2.0",
|
||||
"zustand": "^4.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"tsup": "^8.4.0",
|
||||
"typescript": "^5.2.0"
|
||||
"typescript": "^5.2.0",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.7",
|
||||
"@mui/material": "^6.4.7",
|
||||
"react": "^19.0.0",
|
||||
"@types/react": "^19.0.10"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -1,25 +1,115 @@
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Breadcrumbs,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Card,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Divider,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { useIndexStore } from "../../state/indexes";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { IndexCategory, useIndexStore } from "../../state/indexes";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
export const IndexManager = () => {
|
||||
import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos";
|
||||
import { hashWordWithoutPublicSalt } from "../../utils/encryption";
|
||||
import { usePublish } from "../../hooks/usePublish";
|
||||
import {
|
||||
dismissToast,
|
||||
showError,
|
||||
showLoading,
|
||||
showSuccess,
|
||||
} from "../../utils/toast";
|
||||
import { objectToBase64 } from "../../utils/base64";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import { OptionsManager } from "../OptionsManager";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { useModal } from "../useModal";
|
||||
import { createAvatarLink } from "../../utils/qortal";
|
||||
import { extractComponents } from "../../utils/text";
|
||||
import NavigateNextIcon from "@mui/icons-material/NavigateNext";
|
||||
|
||||
const uid = new ShortUniqueId({ length: 10, dictionary: "alphanum" });
|
||||
|
||||
interface PropsMode {
|
||||
link: string;
|
||||
name: string;
|
||||
mode: number;
|
||||
setMode: (mode: number) => void;
|
||||
username: string;
|
||||
}
|
||||
|
||||
interface PropsIndexManager {
|
||||
username: string | null;
|
||||
}
|
||||
|
||||
const cleanString = (str: string) => str.replace(/\s{2,}/g, ' ').trim().toLocaleLowerCase();
|
||||
|
||||
export const IndexManager = ({ username }: PropsIndexManager) => {
|
||||
const open = useIndexStore((state) => state.open);
|
||||
const setOpen = useIndexStore((state) => state.setOpen);
|
||||
const [title, setTitle] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [hasMetadata, setHasMetadata] = useState(false);
|
||||
const [mode, setMode] = useState(1);
|
||||
|
||||
const publish = usePublish();
|
||||
const handleClose = () => {
|
||||
setOpen(null);
|
||||
setMode(1);
|
||||
setTitle("");
|
||||
setDescription("");
|
||||
setHasMetadata(false);
|
||||
};
|
||||
|
||||
const getMetadata = useCallback(async (name: string, link: string) => {
|
||||
try {
|
||||
const identifierWithoutHash = name + link;
|
||||
const identifier = await hashWordWithoutPublicSalt(
|
||||
identifierWithoutHash,
|
||||
20
|
||||
);
|
||||
const rawData = await publish.fetchPublish(
|
||||
{
|
||||
name: name,
|
||||
service: "METADATA",
|
||||
identifier,
|
||||
},
|
||||
"JSON"
|
||||
);
|
||||
|
||||
if (
|
||||
rawData?.resource &&
|
||||
rawData?.resource?.data?.title &&
|
||||
rawData?.resource?.data?.description
|
||||
) {
|
||||
setHasMetadata(true);
|
||||
setDescription(rawData?.resource?.data?.description);
|
||||
setTitle(rawData?.resource?.data?.title);
|
||||
}
|
||||
} catch (error) {}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (open?.name && open?.link) {
|
||||
setTimeout(() => {
|
||||
getMetadata(open?.name, open?.link);
|
||||
}, 100);
|
||||
}
|
||||
}, [open?.link, open?.name]);
|
||||
|
||||
if (!open || !username) return null;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={!!open}
|
||||
@ -41,6 +131,69 @@ export const IndexManager = () => {
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
{mode === 1 && (
|
||||
<EntryMode
|
||||
link={open?.link}
|
||||
name={open?.name}
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
username={username}
|
||||
hasMetadata={hasMetadata}
|
||||
/>
|
||||
)}
|
||||
{mode === 2 && (
|
||||
<CreateIndex
|
||||
link={open?.link}
|
||||
name={open?.name}
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
username={username}
|
||||
category={open?.category}
|
||||
rootName={open?.rootName}
|
||||
/>
|
||||
)}
|
||||
{/* {mode === 3 && (
|
||||
<YourIndices
|
||||
link={open?.link}
|
||||
name={open?.name}
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
username={username}
|
||||
category={open?.category}
|
||||
rootName={open?.rootName}
|
||||
/>
|
||||
)} */}
|
||||
{mode === 4 && (
|
||||
<AddMetadata
|
||||
link={open?.link}
|
||||
name={open?.name}
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
username={username}
|
||||
title={title}
|
||||
description={description}
|
||||
setDescription={setDescription}
|
||||
setTitle={setTitle}
|
||||
/>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
interface PropsEntryMode extends PropsMode {
|
||||
hasMetadata: boolean;
|
||||
}
|
||||
|
||||
const EntryMode = ({
|
||||
link,
|
||||
name,
|
||||
mode,
|
||||
setMode,
|
||||
username,
|
||||
hasMetadata,
|
||||
}: PropsEntryMode) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
@ -48,16 +201,14 @@ export const IndexManager = () => {
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
width: "100%",
|
||||
alignItems: 'flex-start'
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<IconButton disabled={mode === 1} onClick={()=> setMode(1)}><ArrowBackIosIcon /></IconButton>
|
||||
{mode === 1 && (
|
||||
<>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
onClick={() => setMode(2)}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
@ -70,7 +221,7 @@ export const IndexManager = () => {
|
||||
<Typography>Create new index</Typography>
|
||||
</Box>
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
{/* <ButtonBase
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
@ -85,12 +236,13 @@ export const IndexManager = () => {
|
||||
>
|
||||
<Typography>Your indices</Typography>
|
||||
</Box>
|
||||
</ButtonBase>
|
||||
</ButtonBase> */}
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: "100%",
|
||||
visibility: username === name ? 'visible' : 'hidden'
|
||||
}}
|
||||
onClick={()=> setMode(4)}
|
||||
onClick={() => setMode(4)}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
@ -98,21 +250,731 @@ export const IndexManager = () => {
|
||||
border: "2px solid",
|
||||
borderRadius: 2,
|
||||
width: "100%",
|
||||
gap: "20px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography>Add metadata</Typography>
|
||||
{hasMetadata && <CheckCircleIcon color="success" />}
|
||||
</Box>
|
||||
</ButtonBase>
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === 4 && <AddMetadata />}
|
||||
</Box>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AddMetadata = () => {
|
||||
return <Box>hello</Box>;
|
||||
interface PropsAddMetadata extends PropsMode {
|
||||
title: string;
|
||||
description: string;
|
||||
setTitle: (val: string) => void;
|
||||
setDescription: (val: string) => void;
|
||||
}
|
||||
|
||||
const AddMetadata = ({
|
||||
link,
|
||||
name,
|
||||
mode,
|
||||
setMode,
|
||||
username,
|
||||
title,
|
||||
description,
|
||||
setDescription,
|
||||
setTitle,
|
||||
}: PropsAddMetadata) => {
|
||||
const publish = usePublish();
|
||||
|
||||
const disableButton = !title.trim() || !description.trim() || !name || !link;
|
||||
|
||||
const createMetadata = async () => {
|
||||
const loadId = showLoading("Publishing metadata...");
|
||||
try {
|
||||
const identifierWithoutHash = name + link;
|
||||
const identifier = await hashWordWithoutPublicSalt(
|
||||
identifierWithoutHash,
|
||||
20
|
||||
);
|
||||
const objectToPublish = {
|
||||
title,
|
||||
description,
|
||||
};
|
||||
const toBase64 = await objectToBase64(objectToPublish);
|
||||
const res = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
service: "METADATA",
|
||||
identifier: identifier,
|
||||
base64: toBase64,
|
||||
});
|
||||
|
||||
if (res?.signature) {
|
||||
showSuccess("Successfully published metadata");
|
||||
publish.updatePublish(
|
||||
{
|
||||
identifier,
|
||||
service: "METADATA",
|
||||
name: username,
|
||||
},
|
||||
objectToPublish
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Failed to publish metadata";
|
||||
showError(message);
|
||||
} finally {
|
||||
dismissToast(loadId);
|
||||
}
|
||||
};
|
||||
|
||||
const res = extractComponents(link || "");
|
||||
const appName = res?.name || "";
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
width: "100%",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<IconButton disabled={mode === 1} onClick={() => setMode(1)}>
|
||||
<ArrowBackIosIcon />
|
||||
</IconButton>
|
||||
<Typography>Example of how it could look like:</Typography>
|
||||
<Card sx={{
|
||||
width: '100%',
|
||||
padding: '5px'
|
||||
}}>
|
||||
<Box sx={{ mb: 3, display: "flex", gap: 2, width: "100%" }}>
|
||||
<Avatar
|
||||
alt={appName}
|
||||
src={createAvatarLink(appName)}
|
||||
variant="square"
|
||||
sx={{ width: 24, height: 24, mt: 0.5 }}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
width: "calc(100% - 50px)",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'flex-start'
|
||||
}}
|
||||
>
|
||||
<Breadcrumbs
|
||||
separator={<NavigateNextIcon fontSize="small" />}
|
||||
aria-label="breadcrumb"
|
||||
>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{res?.service}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textAlign: "start",
|
||||
}}
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{appName}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textAlign: "start",
|
||||
}}
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{res?.path}
|
||||
</Typography>
|
||||
</Breadcrumbs>
|
||||
</Box>
|
||||
<Spacer height="10px" />
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
display: "block",
|
||||
textDecoration: "none",
|
||||
width: "100%",
|
||||
textAlign: "start",
|
||||
"&:hover": { textDecoration: "underline" },
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Card>
|
||||
<Box>
|
||||
<Typography>Title</Typography>
|
||||
<TextField
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
size="small"
|
||||
placeholder="Add a title for the link"
|
||||
slotProps={{
|
||||
htmlInput: { maxLength: 50 },
|
||||
}}
|
||||
fullWidth
|
||||
helperText={
|
||||
<Typography
|
||||
variant="caption"
|
||||
color={title.length >= 50 ? "error" : "text.secondary"}
|
||||
>
|
||||
{title.length}/{50} characters
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography>Description</Typography>
|
||||
<TextField
|
||||
fullWidth
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
size="small"
|
||||
placeholder="Add a description for the link"
|
||||
slotProps={{
|
||||
htmlInput: { maxLength: 120 },
|
||||
}}
|
||||
helperText={
|
||||
<Typography
|
||||
variant="caption"
|
||||
color={description.length >= 120 ? "error" : "text.secondary"}
|
||||
>
|
||||
{description.length}/{120} characters
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={createMetadata}
|
||||
disabled={disableButton}
|
||||
variant="contained"
|
||||
>
|
||||
Publish metadata
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface PropsCreateIndex extends PropsMode {
|
||||
category: IndexCategory;
|
||||
rootName: string;
|
||||
}
|
||||
|
||||
const CreateIndex = ({
|
||||
link,
|
||||
name,
|
||||
mode,
|
||||
setMode,
|
||||
username,
|
||||
category,
|
||||
rootName,
|
||||
}: PropsCreateIndex) => {
|
||||
const [terms, setTerms] = useState<string[]>([]);
|
||||
const publish = usePublish();
|
||||
const [size, setSize] = useState(0);
|
||||
const [fullSize, setFullSize] = useState(0);
|
||||
const { isShow, onCancel, onOk, show } = useModal();
|
||||
const [recommendedIndices, setRecommendedIndices] = useState([])
|
||||
const [recommendedSelection, setRecommendedSelection] = useState("")
|
||||
|
||||
|
||||
const objectToPublish = useMemo(() => {
|
||||
if(recommendedSelection){
|
||||
return [
|
||||
{
|
||||
n: name,
|
||||
t: cleanString(recommendedSelection),
|
||||
c: category,
|
||||
l: link,
|
||||
}
|
||||
]
|
||||
}
|
||||
return terms?.map((term) => {
|
||||
return {
|
||||
n: name,
|
||||
t: cleanString(term),
|
||||
c: category,
|
||||
l: link,
|
||||
};
|
||||
});
|
||||
}, [name, terms, category, link, recommendedSelection]);
|
||||
const objectToCalculateSize = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
n: name,
|
||||
t: "",
|
||||
c: category,
|
||||
l: link,
|
||||
},
|
||||
];
|
||||
}, [name, category, link]);
|
||||
|
||||
const shouldRecommendMax = !recommendedSelection && terms?.length === 1 && 230 - size > 50;
|
||||
const recommendedSize = 230 - size;
|
||||
|
||||
useEffect(() => {
|
||||
const getSize = async (data: any, data2: any) => {
|
||||
try {
|
||||
const toBase64 = await objectToBase64(data);
|
||||
const size = toBase64?.length;
|
||||
setSize(size);
|
||||
const toBase642 = await objectToBase64(data2);
|
||||
const size2 = toBase642?.length;
|
||||
setFullSize(size2);
|
||||
} catch (error) {}
|
||||
};
|
||||
getSize(objectToCalculateSize, objectToPublish);
|
||||
}, [objectToCalculateSize, objectToPublish]);
|
||||
|
||||
const getRecommendedIndices = useCallback(async (nameParam: string, linkParam: string, rootNameParam: string)=> {
|
||||
try {
|
||||
const hashedRootName = await hashWordWithoutPublicSalt(rootNameParam, 20);
|
||||
const hashedLink = await hashWordWithoutPublicSalt(linkParam, 20);
|
||||
const identifier = `idx-${hashedRootName}-${hashedLink}-`;
|
||||
const res = await fetch(`/arbitrary/indices/${nameParam}/${identifier}`)
|
||||
const data = await res.json()
|
||||
setRecommendedIndices(data)
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}, [])
|
||||
useEffect(()=> {
|
||||
if(name && link && rootName){
|
||||
getRecommendedIndices(name, link, rootName)
|
||||
}
|
||||
}, [name, link, rootName, getRecommendedIndices])
|
||||
const disableButton = (terms.length === 0 && !recommendedSelection) || !name || !link;
|
||||
|
||||
const createIndex = async () => {
|
||||
const loadId = showLoading("Publishing index...");
|
||||
try {
|
||||
const hashedRootName = await hashWordWithoutPublicSalt(rootName, 20);
|
||||
const hashedLink = await hashWordWithoutPublicSalt(link, 20);
|
||||
const randomUid = uid.rnd();
|
||||
const identifier = `idx-${hashedRootName}-${hashedLink}-${randomUid}`;
|
||||
const toBase64 = await objectToBase64(objectToPublish);
|
||||
const res = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
service: "JSON",
|
||||
identifier: identifier,
|
||||
base64: toBase64,
|
||||
});
|
||||
|
||||
if (res?.signature) {
|
||||
showSuccess("Successfully published index");
|
||||
publish.updatePublish(
|
||||
{
|
||||
identifier,
|
||||
service: "JSON",
|
||||
name: username,
|
||||
},
|
||||
objectToPublish
|
||||
);
|
||||
setTerms([]);
|
||||
}
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Failed to publish index";
|
||||
showError(message);
|
||||
} finally {
|
||||
dismissToast(loadId);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setRecommendedSelection((event.target as HTMLInputElement).value);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
width: "100%",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<IconButton disabled={mode === 1} onClick={() => setMode(1)}>
|
||||
<ArrowBackIosIcon />
|
||||
</IconButton>
|
||||
{recommendedIndices?.length > 0 && (
|
||||
<>
|
||||
<Typography>Recommended Indices</Typography>
|
||||
<RadioGroup
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={recommendedSelection}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{recommendedIndices?.map((ri: any, i)=> {
|
||||
return <FormControlLabel key={i} value={ri?.term} control={<Radio />} label={ri?.term} />
|
||||
})}
|
||||
</RadioGroup>
|
||||
<Divider sx={{
|
||||
width: '100%'
|
||||
}} />
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
<Box>
|
||||
<RadioGroup
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={recommendedSelection}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<FormControlLabel value="" control={<Radio />} label="Add search term" />
|
||||
</RadioGroup>
|
||||
<Spacer height="10px" />
|
||||
{!recommendedSelection && (
|
||||
<OptionsManager
|
||||
maxLength={17}
|
||||
items={terms}
|
||||
onlyStrings
|
||||
label="search terms"
|
||||
setItems={async (termsNew: string[]) => {
|
||||
try {
|
||||
if (terms?.length === 1 && termsNew?.length === 2) {
|
||||
await show({
|
||||
message: "",
|
||||
});
|
||||
}
|
||||
setTerms(termsNew);
|
||||
} catch (error) {
|
||||
//error
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Spacer height="10px" />
|
||||
<Typography
|
||||
sx={{
|
||||
visibility:
|
||||
shouldRecommendMax && fullSize > 230 ? "visible" : "hidden",
|
||||
}}
|
||||
>
|
||||
It is recommended to keep your term character count below{" "}
|
||||
{recommendedSize} characters
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={createIndex}
|
||||
disabled={disableButton}
|
||||
variant="contained"
|
||||
>
|
||||
Publish index
|
||||
</Button>
|
||||
</DialogActions>
|
||||
<Dialog
|
||||
open={isShow}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
sx={{
|
||||
zIndex: 999991,
|
||||
}}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
Adding multiple indices
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Subsequent indices will keep your publish fees lower, but they will
|
||||
have less strength in future search results.
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<Button onClick={onOk}>
|
||||
Continue
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const YourIndices = ({
|
||||
link,
|
||||
name,
|
||||
mode,
|
||||
setMode,
|
||||
username,
|
||||
category,
|
||||
rootName,
|
||||
}: PropsCreateIndex) => {
|
||||
const [terms, setTerms] = useState<string[]>([]);
|
||||
const publish = usePublish();
|
||||
const [size, setSize] = useState(0);
|
||||
const [fullSize, setFullSize] = useState(0);
|
||||
const { isShow, onCancel, onOk, show } = useModal();
|
||||
const [recommendedIndices, setRecommendedIndices] = useState([])
|
||||
const [recommendedSelection, setRecommendedSelection] = useState("")
|
||||
const objectToPublish = useMemo(() => {
|
||||
if(recommendedSelection){
|
||||
return [
|
||||
{
|
||||
n: name,
|
||||
t: recommendedSelection.toLocaleLowerCase(),
|
||||
c: category,
|
||||
l: link,
|
||||
}
|
||||
]
|
||||
}
|
||||
return terms?.map((term) => {
|
||||
return {
|
||||
n: name,
|
||||
t: term.toLocaleLowerCase(),
|
||||
c: category,
|
||||
l: link,
|
||||
};
|
||||
});
|
||||
}, [name, terms, category, link, recommendedSelection]);
|
||||
const objectToCalculateSize = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
n: name,
|
||||
t: "",
|
||||
c: category,
|
||||
l: link,
|
||||
},
|
||||
];
|
||||
}, [name, category, link]);
|
||||
|
||||
const shouldRecommendMax = !recommendedSelection && terms?.length === 1 && 230 - size > 50;
|
||||
const recommendedSize = 230 - size;
|
||||
|
||||
useEffect(() => {
|
||||
const getSize = async (data: any, data2: any) => {
|
||||
try {
|
||||
const toBase64 = await objectToBase64(data);
|
||||
const size = toBase64?.length;
|
||||
setSize(size);
|
||||
const toBase642 = await objectToBase64(data2);
|
||||
const size2 = toBase642?.length;
|
||||
setFullSize(size2);
|
||||
} catch (error) {}
|
||||
};
|
||||
getSize(objectToCalculateSize, objectToPublish);
|
||||
}, [objectToCalculateSize, objectToPublish]);
|
||||
|
||||
const getYourIndices = useCallback(async (nameParam: string, linkParam: string, rootNameParam: string)=> {
|
||||
try {
|
||||
const hashedRootName = await hashWordWithoutPublicSalt(rootNameParam, 20);
|
||||
const hashedLink = await hashWordWithoutPublicSalt(linkParam, 20);
|
||||
const identifier = `idx-${hashedRootName}-${hashedLink}-`;
|
||||
const res = await fetch(`/arbitrary/indices/${nameParam}/${identifier}`)
|
||||
const data = await res.json()
|
||||
setRecommendedIndices(data)
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}, [])
|
||||
useEffect(()=> {
|
||||
if(username && link && rootName){
|
||||
getYourIndices(username, link, rootName)
|
||||
}
|
||||
}, [username, link, rootName, getYourIndices])
|
||||
const disableButton = (terms.length === 0 && !recommendedSelection) || !name || !link;
|
||||
|
||||
const createIndex = async () => {
|
||||
const loadId = showLoading("Publishing index...");
|
||||
try {
|
||||
const hashedRootName = await hashWordWithoutPublicSalt(rootName, 20);
|
||||
const hashedLink = await hashWordWithoutPublicSalt(link, 20);
|
||||
const randomUid = uid.rnd();
|
||||
const identifier = `idx-${hashedRootName}-${hashedLink}-${randomUid}`;
|
||||
const toBase64 = await objectToBase64(objectToPublish);
|
||||
const res = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
service: "JSON",
|
||||
identifier: identifier,
|
||||
base64: toBase64,
|
||||
});
|
||||
|
||||
if (res?.signature) {
|
||||
showSuccess("Successfully published index");
|
||||
publish.updatePublish(
|
||||
{
|
||||
identifier,
|
||||
service: "JSON",
|
||||
name: username,
|
||||
},
|
||||
objectToPublish
|
||||
);
|
||||
setTerms([]);
|
||||
}
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Failed to publish index";
|
||||
showError(message);
|
||||
} finally {
|
||||
dismissToast(loadId);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setRecommendedSelection((event.target as HTMLInputElement).value);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
width: "100%",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<IconButton disabled={mode === 1} onClick={() => setMode(1)}>
|
||||
<ArrowBackIosIcon />
|
||||
</IconButton>
|
||||
{recommendedIndices?.length > 0 && (
|
||||
<>
|
||||
<Typography>Recommended Indices</Typography>
|
||||
<RadioGroup
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={recommendedSelection}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{recommendedIndices?.map((ri: any, i)=> {
|
||||
return <FormControlLabel key={i} value={ri?.term} control={<Radio />} label={ri?.term} />
|
||||
})}
|
||||
</RadioGroup>
|
||||
<Divider sx={{
|
||||
width: '100%'
|
||||
}} />
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
<Box>
|
||||
<RadioGroup
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={recommendedSelection}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<FormControlLabel value="" control={<Radio />} label="Add search term" />
|
||||
</RadioGroup>
|
||||
<Spacer height="10px" />
|
||||
{!recommendedSelection && (
|
||||
<OptionsManager
|
||||
maxLength={17}
|
||||
items={terms}
|
||||
onlyStrings
|
||||
label="search terms"
|
||||
setItems={async (termsNew: string[]) => {
|
||||
try {
|
||||
if (terms?.length === 1 && termsNew?.length === 2) {
|
||||
await show({
|
||||
message: "",
|
||||
});
|
||||
}
|
||||
setTerms(termsNew);
|
||||
} catch (error) {
|
||||
//error
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Spacer height="10px" />
|
||||
<Typography
|
||||
sx={{
|
||||
visibility:
|
||||
shouldRecommendMax && fullSize > 230 ? "visible" : "hidden",
|
||||
}}
|
||||
>
|
||||
It is recommended to keep your term character count below{" "}
|
||||
{recommendedSize} characters
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={createIndex}
|
||||
disabled={disableButton}
|
||||
variant="contained"
|
||||
>
|
||||
Publish index
|
||||
</Button>
|
||||
</DialogActions>
|
||||
<Dialog
|
||||
open={isShow}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
sx={{
|
||||
zIndex: 999991,
|
||||
}}
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
Adding multiple indices
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Subsequent indices will keep your publish fees lower, but they will
|
||||
have less strength in future search results.
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<Button onClick={onOk}>
|
||||
Continue
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
89
src/components/OptionsManager.tsx
Normal file
89
src/components/OptionsManager.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import { useState } from "react";
|
||||
import { TextField, Button, Chip, Box, Stack } from "@mui/material";
|
||||
|
||||
interface PropsOptionsManager {
|
||||
items: string[];
|
||||
setItems: (items: string[]) => void;
|
||||
label?: string;
|
||||
maxLength: number;
|
||||
onlyStrings?: boolean;
|
||||
}
|
||||
|
||||
export function OptionsManager({
|
||||
items,
|
||||
setItems,
|
||||
label = "Keyword",
|
||||
maxLength,
|
||||
onlyStrings,
|
||||
}: PropsOptionsManager) {
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
const [editIndex, setEditIndex] = useState<number | null>(null);
|
||||
|
||||
const handleAddOrUpdateItem = () => {
|
||||
const trimmed = inputValue.trim();
|
||||
if (!trimmed) return;
|
||||
|
||||
let value: string;
|
||||
if (onlyStrings) {
|
||||
value = trimmed;
|
||||
} else {
|
||||
value = isNaN(Number(trimmed)) ? trimmed : String(Number(trimmed));
|
||||
}
|
||||
|
||||
if (editIndex !== null) {
|
||||
const updatedItems = [...items];
|
||||
updatedItems[editIndex] = value;
|
||||
setItems(updatedItems);
|
||||
setEditIndex(null);
|
||||
} else {
|
||||
if (maxLength && items.length >= maxLength) return;
|
||||
if (!items.includes(value)) {
|
||||
setItems([...items, value]);
|
||||
}
|
||||
}
|
||||
|
||||
setInputValue("");
|
||||
};
|
||||
|
||||
const handleDeleteItem = (index: number) => {
|
||||
setItems(items.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
const handleEditItem = (index: number) => {
|
||||
setInputValue(items[index]);
|
||||
setEditIndex(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack direction="row" spacing={2} alignItems="center">
|
||||
<TextField
|
||||
size="small"
|
||||
label={editIndex !== null ? `Edit ${label}` : `Add ${label}`}
|
||||
variant="outlined"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") handleAddOrUpdateItem();
|
||||
}}
|
||||
sx={{ width: "240px" }}
|
||||
/>
|
||||
<Button size="small" variant="contained" onClick={handleAddOrUpdateItem}>
|
||||
{editIndex !== null ? "Update" : "Add"}
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<Box mt={2} sx={{ maxWidth: "400px", flexWrap: "wrap", display: "flex" }}>
|
||||
{items.map((item, index) => (
|
||||
<Chip
|
||||
key={index}
|
||||
label={item}
|
||||
onDelete={() => handleDeleteItem(index)}
|
||||
onClick={() => handleEditItem(index)}
|
||||
sx={{ margin: 0.5 }}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
58
src/components/useModal.tsx
Normal file
58
src/components/useModal.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
interface State {
|
||||
isShow: boolean;
|
||||
}
|
||||
|
||||
interface Message {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
interface PromiseHandlers<T = unknown> {
|
||||
resolve: (value: T) => void;
|
||||
reject: () => void;
|
||||
}
|
||||
|
||||
export const useModal = <T = any>() => {
|
||||
const [state, setState] = useState<State>({ isShow: false });
|
||||
const [message, setMessage] = useState<Message>({
|
||||
message: ""
|
||||
});
|
||||
|
||||
const promiseConfig = useRef<PromiseHandlers<T> | null>(null);
|
||||
|
||||
const show = (data: Message): Promise<T> => {
|
||||
setMessage(data);
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
promiseConfig.current = { resolve, reject };
|
||||
setState({ isShow: true });
|
||||
});
|
||||
};
|
||||
|
||||
const hide = () => {
|
||||
setState({ isShow: false });
|
||||
setMessage({ message: "" });
|
||||
};
|
||||
|
||||
const onOk = (payload: T) => {
|
||||
if (promiseConfig.current) {
|
||||
promiseConfig.current.resolve(payload);
|
||||
}
|
||||
hide();
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
if (promiseConfig.current) {
|
||||
promiseConfig.current.reject();
|
||||
}
|
||||
hide();
|
||||
};
|
||||
|
||||
return {
|
||||
show,
|
||||
onOk,
|
||||
onCancel,
|
||||
isShow: state.isShow,
|
||||
message,
|
||||
};
|
||||
};
|
@ -32,7 +32,7 @@ interface GlobalProviderProps {
|
||||
appName: string;
|
||||
publicSalt: string
|
||||
};
|
||||
toastStyle: CSSProperties
|
||||
toastStyle?: CSSProperties
|
||||
}
|
||||
|
||||
// ✅ Create Context with Proper Type
|
||||
@ -44,6 +44,7 @@ const GlobalContext = createContext<GlobalContextType | null>(null);
|
||||
export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProviderProps) => {
|
||||
// ✅ Call hooks and pass in options dynamically
|
||||
const auth = useAuth(config?.auth || {});
|
||||
|
||||
const appInfo = useAppInfo(config.appName, config?.publicSalt)
|
||||
const lists = useResources()
|
||||
const identifierOperations = useIdentifiers(config.publicSalt, config.appName)
|
||||
@ -51,6 +52,8 @@ export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProv
|
||||
const indexOperations = useIndexes()
|
||||
// ✅ Merge all hooks into a single `contextValue`
|
||||
const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, localStorageOperations, indexOperations }), [auth, lists, appInfo, identifierOperations, localStorageOperations]);
|
||||
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={contextValue}>
|
||||
<Toaster
|
||||
@ -61,7 +64,8 @@ export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProv
|
||||
}}
|
||||
containerStyle={{zIndex: 999999}}
|
||||
/>
|
||||
<IndexManager />
|
||||
<IndexManager username={auth?.name} />
|
||||
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
);
|
||||
|
@ -4,11 +4,13 @@ import { OpenIndex, useIndexStore } from "../state/indexes";
|
||||
export const useIndexes = () => {
|
||||
const setOpen = useIndexStore((state) => state.setOpen);
|
||||
const openPageIndexManager = useCallback(
|
||||
({ link, name }: OpenIndex) => {
|
||||
if(!link || !name) return
|
||||
({ link, name, category, rootName }: OpenIndex) => {
|
||||
if(!link || !name || !category) return
|
||||
setOpen({
|
||||
name,
|
||||
link,
|
||||
category,
|
||||
rootName
|
||||
});
|
||||
},
|
||||
[setOpen]
|
||||
|
@ -1,6 +1,7 @@
|
||||
export { useResourceStatus } from './hooks/useResourceStatus';
|
||||
export { Spacer } from './common/Spacer';
|
||||
import './index.css'
|
||||
export { IndexCategory } from './state/indexes';
|
||||
export { hashWordWithoutPublicSalt } from './utils/encryption';
|
||||
export { createAvatarLink } from './utils/qortal';
|
||||
export { objectToBase64 } from './utils/base64';
|
||||
|
@ -1,8 +1,23 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
export enum IndexCategory {
|
||||
'PUBLIC_PAGE_VIDEO' = 1,
|
||||
'PUBLIC_PAGE_AUDIO' = 2,
|
||||
'PUBLIC_PAGE_IMAGE' = 3,
|
||||
'PUBLIC_PAGE_PDF' = 4,
|
||||
'PUBLIC_PAGE_OTHER' = 5,
|
||||
'PUBLIC_RESOURCE_VIDEO' = 6,
|
||||
'PUBLIC_RESOURCE_AUDIO' = 7,
|
||||
'PUBLIC_RESOURCE_IMAGE' = 8,
|
||||
'PUBLIC_RESOURCE_PDF' = 9,
|
||||
'PUBLIC_RESOURCE_OTHER' = 10,
|
||||
}
|
||||
|
||||
export interface OpenIndex {
|
||||
link: string
|
||||
name: string
|
||||
category: IndexCategory
|
||||
rootName: string
|
||||
}
|
||||
|
||||
interface IndexState {
|
||||
|
@ -17,11 +17,21 @@ export enum EnumCollisionStrength {
|
||||
ENTITY_LABEL = 6,
|
||||
}
|
||||
|
||||
export async function hashWord(
|
||||
|
||||
// Custom URL-safe replacements (reserving '-' and '_')
|
||||
const safeBase64 = (base64: string): string =>
|
||||
base64
|
||||
.replace(/\+/g, ".") // Replace '+' with '.' (URL-safe)
|
||||
.replace(/\//g, "~") // Replace '/' with '~' (URL-safe)
|
||||
.replace(/_/g, "!") // Replace '_' with '!' if needed (optional)
|
||||
.replace(/=+$/, ""); // Remove padding
|
||||
|
||||
|
||||
export async function hashWord(
|
||||
word: string,
|
||||
collisionStrength: number,
|
||||
publicSalt: string
|
||||
): Promise<string> {
|
||||
): Promise<string> {
|
||||
const saltedWord = publicSalt + word;
|
||||
|
||||
try {
|
||||
@ -29,24 +39,17 @@ export async function hashWord(
|
||||
|
||||
const encoded = new TextEncoder().encode(saltedWord);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
||||
const base64 = Buffer.from(hashBuffer).toString("base64");
|
||||
|
||||
return Buffer.from(hashBuffer)
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "")
|
||||
.slice(0, collisionStrength);
|
||||
return safeBase64(base64).slice(0, collisionStrength);
|
||||
} catch (err) {
|
||||
const hash = SHA256(saltedWord);
|
||||
const base64 = EncBase64.stringify(hash);
|
||||
|
||||
return base64
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "")
|
||||
.slice(0, collisionStrength);
|
||||
return safeBase64(base64).slice(0, collisionStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function hashWordWithoutPublicSalt(
|
||||
word: string,
|
||||
@ -57,22 +60,14 @@ export async function hashWordWithoutPublicSalt(
|
||||
|
||||
const encoded = new TextEncoder().encode(word);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
||||
const base64 = Buffer.from(hashBuffer).toString("base64");
|
||||
|
||||
return Buffer.from(hashBuffer)
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "")
|
||||
.slice(0, collisionStrength);
|
||||
return safeBase64(base64).slice(0, collisionStrength);
|
||||
} catch (err) {
|
||||
const hash = SHA256(word);
|
||||
const base64 = EncBase64.stringify(hash);
|
||||
|
||||
return base64
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "")
|
||||
.slice(0, collisionStrength);
|
||||
return safeBase64(base64).slice(0, collisionStrength);
|
||||
}
|
||||
}
|
||||
|
||||
|
14
tsup.config.ts
Normal file
14
tsup.config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { defineConfig } from 'tsup';
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/index.ts'],
|
||||
format: ['esm', 'cjs'],
|
||||
dts: true,
|
||||
external: [
|
||||
'react',
|
||||
'@mui/material',
|
||||
'@mui/system',
|
||||
'@emotion/react',
|
||||
'@emotion/styled',
|
||||
],
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user