Compare commits
52 Commits
31e8c0346f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a2c01ff73 | |||
| db67c1e69e | |||
| 571f05bcba | |||
| 27503bf4a7 | |||
| b32e622707 | |||
| df3e5a43fa | |||
| 76d26aba5a | |||
| 2a0d508cf4 | |||
| 3f8b9c2c4a | |||
| c97e246ba7 | |||
| 15fd2d3dc8 | |||
| 885abd8c46 | |||
| fda55061a0 | |||
| 90a73bc1f6 | |||
| c0bd0b7964 | |||
| b8db664c62 | |||
| 9fed28819e | |||
| 9400ccf229 | |||
| b972ed3a36 | |||
| 05c8496469 | |||
| d2ffc8d8ec | |||
| e4990d5e3d | |||
| 4e36d01fb1 | |||
| 2d7375e32d | |||
| 2fec4dd04e | |||
| 171847a46c | |||
| 916bb083af | |||
| 5e5df744ce | |||
| 9fb118bd71 | |||
| 17d00ca08f | |||
| 78f781ef39 | |||
| f4afea4560 | |||
| d1fa2dc6b5 | |||
| ddfa18480f | |||
| 6ee39d2028 | |||
| e2b7d62693 | |||
| 97e7a53a2b | |||
| ef5d3c3805 | |||
| 0086aeced2 | |||
| 969fb31351 | |||
| ee261f5c27 | |||
| a1460a97b4 | |||
| aa2bf17791 | |||
| 7de76f29e9 | |||
| ba44339b48 | |||
| e295a6ddbe | |||
| 711e1d4ca5 | |||
| b89e0d02a8 | |||
| b61e32d883 | |||
| f420125c78 | |||
| 80bd6112ad | |||
| cb8723c172 |
41
bun.config.ts
Normal file
41
bun.config.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { buildWithBun } from '@kevisual/code-builder'
|
||||||
|
import { queryList, storeList } from './src/scripts/get-query-list.ts'
|
||||||
|
|
||||||
|
// await buildWithBun({ naming: "app", entry: "query/index.ts", meta: import.meta, dts: true })
|
||||||
|
|
||||||
|
for (const query of queryList) {
|
||||||
|
await buildWithBun({
|
||||||
|
naming: query.name,
|
||||||
|
entry: `query/${query.name}/index.ts`,
|
||||||
|
meta: import.meta,
|
||||||
|
target: 'browser',
|
||||||
|
dts: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const store of storeList) {
|
||||||
|
await buildWithBun({
|
||||||
|
naming: store.name,
|
||||||
|
entry: `store/${store.name}/index.ts`,
|
||||||
|
meta: import.meta,
|
||||||
|
external: ['sonner', 'zustand', '@kevisual/context'],
|
||||||
|
target: 'browser',
|
||||||
|
dts: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await buildWithBun({
|
||||||
|
naming: 'utils-node',
|
||||||
|
entry: 'query/utils/index.ts',
|
||||||
|
meta: import.meta,
|
||||||
|
target: 'node',
|
||||||
|
dts: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
await buildWithBun({
|
||||||
|
naming: 'query-login-node',
|
||||||
|
entry: 'query/query-login/query-login-node.ts',
|
||||||
|
meta: import.meta,
|
||||||
|
target: 'node',
|
||||||
|
dts: true,
|
||||||
|
})
|
||||||
143
bun.lock
Normal file
143
bun.lock
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "@kevisual/api",
|
||||||
|
"dependencies": {
|
||||||
|
"@kevisual/context": "^0.0.8",
|
||||||
|
"@kevisual/js-filter": "^0.0.5",
|
||||||
|
"@kevisual/load": "^0.0.6",
|
||||||
|
"@paralleldrive/cuid2": "^3.3.0",
|
||||||
|
"es-toolkit": "^1.44.0",
|
||||||
|
"eventemitter3": "^5.0.4",
|
||||||
|
"fuse.js": "^7.1.0",
|
||||||
|
"nanoid": "^5.1.6",
|
||||||
|
"path-browserify-esm": "^1.0.6",
|
||||||
|
"sonner": "^2.0.7",
|
||||||
|
"spark-md5": "^3.0.2",
|
||||||
|
"zustand": "^5.0.11",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@kevisual/cache": "^0.0.5",
|
||||||
|
"@kevisual/code-builder": "^0.0.6",
|
||||||
|
"@kevisual/query": "^0.0.49",
|
||||||
|
"@kevisual/remote-app": "^0.0.4",
|
||||||
|
"@kevisual/router": "^0.0.83",
|
||||||
|
"@kevisual/types": "^0.0.12",
|
||||||
|
"@kevisual/use-config": "^1.0.30",
|
||||||
|
"@types/bun": "^1.3.9",
|
||||||
|
"@types/node": "^25.3.0",
|
||||||
|
"@types/spark-md5": "^3.0.5",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"fast-glob": "^3.3.3",
|
||||||
|
"ws": "npm:@kevisual/ws",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@kevisual/cache": ["@kevisual/cache@0.0.5", "", { "dependencies": { "idb-keyval": "^6.2.2", "lru-cache": "^11.2.4", "nanoid": "^5.1.6" } }, "sha512-fgtUYGUUq/DY0KFV4CkWszNqvQUaA8XvMTUjoR9ZXRpau5IIDolD/Wen2TFsZ7G3Rfy+lef5dnaiZVDkZwdVKg=="],
|
||||||
|
|
||||||
|
"@kevisual/code-builder": ["@kevisual/code-builder@0.0.6", "", { "bin": { "code-builder": "bin/code.js", "builder": "bin/code.js" } }, "sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw=="],
|
||||||
|
|
||||||
|
"@kevisual/context": ["@kevisual/context@0.0.8", "", {}, "sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA=="],
|
||||||
|
|
||||||
|
"@kevisual/js-filter": ["@kevisual/js-filter@0.0.5", "", {}, "sha512-+S+Sf3K/aP6XtZI2s7TgKOr35UuvUvtpJ9YDW30a+mY0/N8gRuzyKhieBzQN7Ykayzz70uoMavBXut2rUlLgzw=="],
|
||||||
|
|
||||||
|
"@kevisual/load": ["@kevisual/load@0.0.6", "", { "dependencies": { "eventemitter3": "^5.0.1" } }, "sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA=="],
|
||||||
|
|
||||||
|
"@kevisual/query": ["@kevisual/query@0.0.49", "", {}, "sha512-GrWW+QlBO5lkiqvb7PjOstNtpTQVSR74EHHWjm7YoL9UdT1wuPQXGUApZHmMBSh3NIWCf0AL2G1hPWZMC7YeOQ=="],
|
||||||
|
|
||||||
|
"@kevisual/remote-app": ["@kevisual/remote-app@0.0.4", "", {}, "sha512-2yIlWY98pLCcxG+DJsqXXkd5YYEgymuOsyElH+31AoEPb7mlNREnYS81zN0KM9nvdSmU2G51vV4UVirJlYBZCQ=="],
|
||||||
|
|
||||||
|
"@kevisual/router": ["@kevisual/router@0.0.83", "", { "dependencies": { "es-toolkit": "^1.44.0" } }, "sha512-CVazzM1rXVyvU7QcMQr0/EuqacRNEGalThDDLGQcvKEVHyduJ9yWddn6kezgWFCpNlPKhzSCKkIFuZVixNVxDQ=="],
|
||||||
|
|
||||||
|
"@kevisual/types": ["@kevisual/types@0.0.12", "", {}, "sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q=="],
|
||||||
|
|
||||||
|
"@kevisual/use-config": ["@kevisual/use-config@1.0.30", "", { "dependencies": { "@kevisual/load": "^0.0.6" }, "peerDependencies": { "dotenv": "^17" } }, "sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw=="],
|
||||||
|
|
||||||
|
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
|
||||||
|
|
||||||
|
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||||
|
|
||||||
|
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||||
|
|
||||||
|
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||||
|
|
||||||
|
"@paralleldrive/cuid2": ["@paralleldrive/cuid2@3.3.0", "", { "dependencies": { "@noble/hashes": "^2.0.1", "bignumber.js": "^9.3.1", "error-causes": "^3.0.2" }, "bin": { "cuid2": "bin/cuid2.js" } }, "sha512-OqiFvSOF0dBSesELYY2CAMa4YINvlLpvKOz/rv6NeZEqiyttlHgv98Juwv4Ch+GrEV7IZ8jfI2VcEoYUjXXCjw=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
|
||||||
|
|
||||||
|
"@types/spark-md5": ["@types/spark-md5@3.0.5", "", {}, "sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg=="],
|
||||||
|
|
||||||
|
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
|
||||||
|
|
||||||
|
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
||||||
|
|
||||||
|
"dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
|
||||||
|
|
||||||
|
"error-causes": ["error-causes@3.0.2", "", {}, "sha512-i0B8zq1dHL6mM85FGoxaJnVtx6LD5nL2v0hlpGdntg5FOSyzQ46c9lmz5qx0xRS2+PWHGOHcYxGIBC5Le2dRMw=="],
|
||||||
|
|
||||||
|
"es-toolkit": ["es-toolkit@1.44.0", "", {}, "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg=="],
|
||||||
|
|
||||||
|
"eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
|
||||||
|
|
||||||
|
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||||
|
|
||||||
|
"fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
|
||||||
|
|
||||||
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
|
"fuse.js": ["fuse.js@7.1.0", "", {}, "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ=="],
|
||||||
|
|
||||||
|
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
|
"idb-keyval": ["idb-keyval@6.2.2", "", {}, "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg=="],
|
||||||
|
|
||||||
|
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||||
|
|
||||||
|
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||||
|
|
||||||
|
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||||
|
|
||||||
|
"lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
|
||||||
|
|
||||||
|
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||||
|
|
||||||
|
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||||
|
|
||||||
|
"nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
|
||||||
|
|
||||||
|
"path-browserify-esm": ["path-browserify-esm@1.0.6", "", {}, "sha512-9nUwYvvu/yq1PYrUyYCihNWmpzacaRYF6gGbjLWErrZ4MRDWyfPN7RpE8E7tsw8eqBU/rr7mcoTXbS+Vih8uUA=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||||
|
|
||||||
|
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
|
||||||
|
|
||||||
|
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
|
||||||
|
|
||||||
|
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
||||||
|
|
||||||
|
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||||
|
|
||||||
|
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||||
|
|
||||||
|
"sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
|
||||||
|
|
||||||
|
"spark-md5": ["spark-md5@3.0.2", "", {}, "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="],
|
||||||
|
|
||||||
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||||
|
|
||||||
|
"ws": ["@kevisual/ws@8.19.0", "", {}, "sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw=="],
|
||||||
|
|
||||||
|
"zustand": ["zustand@5.0.11", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
66
package.json
66
package.json
@@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/api",
|
"name": "@kevisual/api",
|
||||||
"version": "0.0.15",
|
"version": "0.0.64",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "mod.ts",
|
"main": "mod.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bun run bun.config.ts",
|
"build": "bun run bun.config.ts"
|
||||||
"postbuild": "bun bun.copy.config.mjs"
|
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
@@ -13,30 +12,42 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"query",
|
"query",
|
||||||
|
"store",
|
||||||
"mod.ts"
|
"mod.ts"
|
||||||
],
|
],
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "pnpm@10.27.0",
|
"packageManager": "pnpm@10.32.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kevisual/cache": "^0.0.4",
|
"@kevisual/cache": "^0.0.5",
|
||||||
"@kevisual/query": "^0.0.33",
|
"@kevisual/code-builder": "^0.0.6",
|
||||||
"@kevisual/router": "^0.0.52",
|
"@kevisual/query": "^0.0.53",
|
||||||
"@kevisual/types": "^0.0.10",
|
"@kevisual/remote-app": "^0.0.6",
|
||||||
"@kevisual/use-config": "^1.0.21",
|
"@kevisual/router": "^0.1.1",
|
||||||
"@types/bun": "^1.3.5",
|
"@kevisual/types": "^0.0.12",
|
||||||
"@types/node": "^25.0.3",
|
"@kevisual/use-config": "^1.0.30",
|
||||||
"dotenv": "^17.2.3",
|
"@types/bun": "^1.3.10",
|
||||||
"fast-glob": "^3.3.3"
|
"@types/node": "^25.4.0",
|
||||||
|
"@types/spark-md5": "^3.0.5",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"fast-glob": "^3.3.3",
|
||||||
|
"ws": "npm:@kevisual/ws"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kevisual/js-filter": "^0.0.3",
|
"@kevisual/context": "^0.0.8",
|
||||||
|
"@kevisual/js-filter": "^0.0.6",
|
||||||
"@kevisual/load": "^0.0.6",
|
"@kevisual/load": "^0.0.6",
|
||||||
"es-toolkit": "^1.43.0",
|
"@paralleldrive/cuid2": "^3.3.0",
|
||||||
"eventemitter3": "^5.0.1",
|
"es-toolkit": "^1.45.1",
|
||||||
"nanoid": "^5.1.6"
|
"eventemitter3": "^5.0.4",
|
||||||
|
"fuse.js": "^7.1.0",
|
||||||
|
"nanoid": "^5.1.6",
|
||||||
|
"path-browserify-esm": "^1.0.6",
|
||||||
|
"sonner": "^2.0.7",
|
||||||
|
"spark-md5": "^3.0.2",
|
||||||
|
"zustand": "^5.0.11"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./mod.ts",
|
".": "./mod.ts",
|
||||||
@@ -44,6 +55,25 @@
|
|||||||
"./login-node": "./query/query-login/query-login-node.ts",
|
"./login-node": "./query/query-login/query-login-node.ts",
|
||||||
"./config": "./query/query-config/query-config.ts",
|
"./config": "./query/query-config/query-config.ts",
|
||||||
"./proxy": "./query/query-proxy/index.ts",
|
"./proxy": "./query/query-proxy/index.ts",
|
||||||
"./query/**/*.ts": "./query/**/*.ts"
|
"./secret": "./query/query-secret/index.ts",
|
||||||
|
"./resources": "./query/query-resources/index.ts",
|
||||||
|
"./utils-node": "./dist/utils-node.js",
|
||||||
|
"./query-login-node": "./dist/query-login-node.js",
|
||||||
|
"./utils": "./dist/utils.js",
|
||||||
|
"./query-secret": "./dist/query-secret.js",
|
||||||
|
"./query-mark": "./dist/query-mark.js",
|
||||||
|
"./query-upload": "./dist/query-upload.js",
|
||||||
|
"./query-app": "./dist/query-app.js",
|
||||||
|
"./query-proxy": "./dist/query-proxy.js",
|
||||||
|
"./query-shop": "./dist/query-shop.js",
|
||||||
|
"./query-config": "./dist/query-config.js",
|
||||||
|
"./query-login": "./dist/query-login.js",
|
||||||
|
"./query-ai": "./dist/query-ai.js",
|
||||||
|
"./query-resources": "./dist/query-resources.js",
|
||||||
|
"./store-mark": "./dist/store-mark.js",
|
||||||
|
"./store-auth": "./dist/store-auth.js",
|
||||||
|
"./src/*": "./src/*",
|
||||||
|
"./store/*": "./src/*",
|
||||||
|
"./query/*": "./query/*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
600
pnpm-lock.yaml
generated
600
pnpm-lock.yaml
generated
@@ -8,49 +8,82 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@kevisual/context':
|
||||||
|
specifier: ^0.0.8
|
||||||
|
version: 0.0.8
|
||||||
'@kevisual/js-filter':
|
'@kevisual/js-filter':
|
||||||
specifier: ^0.0.3
|
specifier: ^0.0.6
|
||||||
version: 0.0.3
|
version: 0.0.6
|
||||||
'@kevisual/load':
|
'@kevisual/load':
|
||||||
specifier: ^0.0.6
|
specifier: ^0.0.6
|
||||||
version: 0.0.6
|
version: 0.0.6
|
||||||
|
'@paralleldrive/cuid2':
|
||||||
|
specifier: ^3.3.0
|
||||||
|
version: 3.3.0
|
||||||
es-toolkit:
|
es-toolkit:
|
||||||
specifier: ^1.43.0
|
specifier: ^1.45.1
|
||||||
version: 1.43.0
|
version: 1.45.1
|
||||||
eventemitter3:
|
eventemitter3:
|
||||||
specifier: ^5.0.1
|
specifier: ^5.0.4
|
||||||
version: 5.0.1
|
version: 5.0.4
|
||||||
|
fuse.js:
|
||||||
|
specifier: ^7.1.0
|
||||||
|
version: 7.1.0
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.1.6
|
specifier: ^5.1.6
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
|
path-browserify-esm:
|
||||||
|
specifier: ^1.0.6
|
||||||
|
version: 1.0.6
|
||||||
|
sonner:
|
||||||
|
specifier: ^2.0.7
|
||||||
|
version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
|
spark-md5:
|
||||||
|
specifier: ^3.0.2
|
||||||
|
version: 3.0.2
|
||||||
|
zustand:
|
||||||
|
specifier: ^5.0.11
|
||||||
|
version: 5.0.11(react@19.2.4)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kevisual/cache':
|
'@kevisual/cache':
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.5
|
||||||
version: 0.0.4
|
version: 0.0.5
|
||||||
|
'@kevisual/code-builder':
|
||||||
|
specifier: ^0.0.6
|
||||||
|
version: 0.0.6
|
||||||
'@kevisual/query':
|
'@kevisual/query':
|
||||||
specifier: ^0.0.33
|
specifier: ^0.0.53
|
||||||
version: 0.0.33
|
version: 0.0.53
|
||||||
|
'@kevisual/remote-app':
|
||||||
|
specifier: ^0.0.6
|
||||||
|
version: 0.0.6
|
||||||
'@kevisual/router':
|
'@kevisual/router':
|
||||||
specifier: ^0.0.52
|
specifier: ^0.1.1
|
||||||
version: 0.0.52
|
version: 0.1.1
|
||||||
'@kevisual/types':
|
'@kevisual/types':
|
||||||
specifier: ^0.0.10
|
specifier: ^0.0.12
|
||||||
version: 0.0.10
|
version: 0.0.12
|
||||||
'@kevisual/use-config':
|
'@kevisual/use-config':
|
||||||
specifier: ^1.0.21
|
specifier: ^1.0.30
|
||||||
version: 1.0.21(dotenv@17.2.3)
|
version: 1.0.30(dotenv@17.3.1)
|
||||||
'@types/bun':
|
'@types/bun':
|
||||||
specifier: ^1.3.5
|
specifier: ^1.3.10
|
||||||
version: 1.3.5
|
version: 1.3.10
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.0.3
|
specifier: ^25.4.0
|
||||||
version: 25.0.3
|
version: 25.4.0
|
||||||
|
'@types/spark-md5':
|
||||||
|
specifier: ^3.0.5
|
||||||
|
version: 3.0.5
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^17.2.3
|
specifier: ^17.3.1
|
||||||
version: 17.2.3
|
version: 17.3.1
|
||||||
fast-glob:
|
fast-glob:
|
||||||
specifier: ^3.3.3
|
specifier: ^3.3.3
|
||||||
version: 3.3.3
|
version: 3.3.3
|
||||||
|
ws:
|
||||||
|
specifier: npm:@kevisual/ws
|
||||||
|
version: '@kevisual/ws@8.19.0'
|
||||||
|
|
||||||
packages/api:
|
packages/api:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -74,11 +107,18 @@ importers:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@kevisual/cache@0.0.4':
|
'@kevisual/cache@0.0.5':
|
||||||
resolution: {integrity: sha512-NlyriJ9fC27TgQhWYbEH9hG84R2k0lIofOxo/+nVHN6a6LJSLnVbpDIysRcnH8MI52n/XHfWwLSjeDDL3D1/cQ==}
|
resolution: {integrity: sha512-fgtUYGUUq/DY0KFV4CkWszNqvQUaA8XvMTUjoR9ZXRpau5IIDolD/Wen2TFsZ7G3Rfy+lef5dnaiZVDkZwdVKg==}
|
||||||
|
|
||||||
'@kevisual/js-filter@0.0.3':
|
'@kevisual/code-builder@0.0.6':
|
||||||
resolution: {integrity: sha512-vgUB2fUAWS75GUFr/a/tGSSDrPUUmVDktO38k3hIKwU3ZE4tpuhcVxrpUbkXlFS5i0rbL2mAQeID1C6kIlMGRg==}
|
resolution: {integrity: sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@kevisual/context@0.0.8':
|
||||||
|
resolution: {integrity: sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA==}
|
||||||
|
|
||||||
|
'@kevisual/js-filter@0.0.6':
|
||||||
|
resolution: {integrity: sha512-FcbOsmS1inhwrfgXMM/XLFTGTHUxBCss32JEMYdEFWQDYCar5rN8cxD1W8FuKDTVRlpA+zBpQ/BE6XT4UaeljA==}
|
||||||
|
|
||||||
'@kevisual/load@0.0.6':
|
'@kevisual/load@0.0.6':
|
||||||
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
|
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
|
||||||
@@ -86,26 +126,36 @@ packages:
|
|||||||
'@kevisual/query@0.0.18':
|
'@kevisual/query@0.0.18':
|
||||||
resolution: {integrity: sha512-I2vHTu0I6AyD9PJyr+vxyp9jIJ6rd2EZqLVHTv/+zrVKVc2SS76Tg7aGNkmAFqqLSCB8kLLsmMGtSJU1Qb8VVg==}
|
resolution: {integrity: sha512-I2vHTu0I6AyD9PJyr+vxyp9jIJ6rd2EZqLVHTv/+zrVKVc2SS76Tg7aGNkmAFqqLSCB8kLLsmMGtSJU1Qb8VVg==}
|
||||||
|
|
||||||
'@kevisual/query@0.0.33':
|
'@kevisual/query@0.0.53':
|
||||||
resolution: {integrity: sha512-3w74bcLpwV3z483eg8n0DgkftfjWC6iLONXBvfyjW6IZf6jMOuouFaM4Rk+uEsTgElU6XGMKseNTp6dlQdWYkg==}
|
resolution: {integrity: sha512-PAhpCLBr0emz0lGNlTVHMbJiC5wrtGLbInPddRzgKE35fiyNt+SWSsUWABiD0DeNrLN/OxWyAFobt880Z/e5MQ==}
|
||||||
|
|
||||||
|
'@kevisual/remote-app@0.0.6':
|
||||||
|
resolution: {integrity: sha512-yc3BKAhtY+SzrvQSebeyR/QR93nPctndNMnW6ne1YPK+Kfpuf8gi7W4zlg18EJh7FEpDuDVHKqVp1klsWjESqQ==}
|
||||||
|
|
||||||
'@kevisual/router@0.0.20':
|
'@kevisual/router@0.0.20':
|
||||||
resolution: {integrity: sha512-uSwDYWh+kvAu6i0m0SJVgcLR/CYz7WvIWGz0nSF8Vg6smJuAgI+laHR4ESO8Fbz+Xn8bPHuSwmM//HHLMLx2FA==}
|
resolution: {integrity: sha512-uSwDYWh+kvAu6i0m0SJVgcLR/CYz7WvIWGz0nSF8Vg6smJuAgI+laHR4ESO8Fbz+Xn8bPHuSwmM//HHLMLx2FA==}
|
||||||
|
|
||||||
'@kevisual/router@0.0.52':
|
'@kevisual/router@0.1.1':
|
||||||
resolution: {integrity: sha512-Qiv3P1XjzD813Tm79S+atrDb2eickGCI9tuy/aCu512LcoYYJqZhwwkeT4ES0DinnA13Ckqd43QWBR6UmuYkHQ==}
|
resolution: {integrity: sha512-+uaJc+Bf/T1mfxyfy9PmwuxJGPOLhVqrmsli2xUPqkkFvizrFIGB1vBTITuo5XP/FnwGqxgbjsitG57AMubm3w==}
|
||||||
|
|
||||||
'@kevisual/types@0.0.10':
|
'@kevisual/types@0.0.10':
|
||||||
resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==}
|
resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.21':
|
'@kevisual/types@0.0.12':
|
||||||
resolution: {integrity: sha512-czgy4+tBDBJI6QTnKh2PCwswET6ZpZ4ZqBE/SPkkOivEtlrcPzLs5elwMLZ3goD1XMD4VB3yjumb5WuW/8H8MA==}
|
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
|
||||||
|
|
||||||
|
'@kevisual/use-config@1.0.30':
|
||||||
|
resolution: {integrity: sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
dotenv: ^17
|
dotenv: ^17
|
||||||
|
|
||||||
'@noble/hashes@1.4.0':
|
'@kevisual/ws@8.19.0':
|
||||||
resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
|
resolution: {integrity: sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw==}
|
||||||
engines: {node: '>= 16'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
'@noble/hashes@2.0.1':
|
||||||
|
resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==}
|
||||||
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
@@ -119,42 +169,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
'@peculiar/asn1-cms@2.6.0':
|
'@paralleldrive/cuid2@3.3.0':
|
||||||
resolution: {integrity: sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==}
|
resolution: {integrity: sha512-OqiFvSOF0dBSesELYY2CAMa4YINvlLpvKOz/rv6NeZEqiyttlHgv98Juwv4Ch+GrEV7IZ8jfI2VcEoYUjXXCjw==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@peculiar/asn1-csr@2.6.0':
|
'@types/bun@1.3.10':
|
||||||
resolution: {integrity: sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==}
|
resolution: {integrity: sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ==}
|
||||||
|
|
||||||
'@peculiar/asn1-ecc@2.6.0':
|
|
||||||
resolution: {integrity: sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-pfx@2.6.0':
|
|
||||||
resolution: {integrity: sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-pkcs8@2.6.0':
|
|
||||||
resolution: {integrity: sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-pkcs9@2.6.0':
|
|
||||||
resolution: {integrity: sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-rsa@2.6.0':
|
|
||||||
resolution: {integrity: sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-schema@2.6.0':
|
|
||||||
resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-x509-attr@2.6.0':
|
|
||||||
resolution: {integrity: sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==}
|
|
||||||
|
|
||||||
'@peculiar/asn1-x509@2.6.0':
|
|
||||||
resolution: {integrity: sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==}
|
|
||||||
|
|
||||||
'@peculiar/x509@1.14.2':
|
|
||||||
resolution: {integrity: sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==}
|
|
||||||
engines: {node: '>=22.0.0'}
|
|
||||||
|
|
||||||
'@types/bun@1.3.5':
|
|
||||||
resolution: {integrity: sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==}
|
|
||||||
|
|
||||||
'@types/node-fetch@2.6.12':
|
'@types/node-fetch@2.6.12':
|
||||||
resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
|
resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
|
||||||
@@ -168,8 +188,11 @@ packages:
|
|||||||
'@types/node@22.15.27':
|
'@types/node@22.15.27':
|
||||||
resolution: {integrity: sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==}
|
resolution: {integrity: sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==}
|
||||||
|
|
||||||
'@types/node@25.0.3':
|
'@types/node@25.4.0':
|
||||||
resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==}
|
resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==}
|
||||||
|
|
||||||
|
'@types/spark-md5@3.0.5':
|
||||||
|
resolution: {integrity: sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg==}
|
||||||
|
|
||||||
abort-controller@3.0.0:
|
abort-controller@3.0.0:
|
||||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||||
@@ -179,23 +202,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
||||||
engines: {node: '>= 8.0.0'}
|
engines: {node: '>= 8.0.0'}
|
||||||
|
|
||||||
asn1js@3.0.6:
|
|
||||||
resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
|
|
||||||
asynckit@0.4.0:
|
asynckit@0.4.0:
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
|
bignumber.js@9.3.1:
|
||||||
|
resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
|
||||||
|
|
||||||
braces@3.0.3:
|
braces@3.0.3:
|
||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
bun-types@1.3.5:
|
bun-types@1.3.10:
|
||||||
resolution: {integrity: sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==}
|
resolution: {integrity: sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg==}
|
||||||
|
|
||||||
bytestreamjs@2.0.1:
|
|
||||||
resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==}
|
|
||||||
engines: {node: '>=6.0.0'}
|
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.2:
|
call-bind-apply-helpers@1.0.2:
|
||||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
@@ -205,37 +223,20 @@ packages:
|
|||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
debug@4.4.3:
|
|
||||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
|
||||||
engines: {node: '>=6.0'}
|
|
||||||
peerDependencies:
|
|
||||||
supports-color: '*'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
supports-color:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
delayed-stream@1.0.0:
|
delayed-stream@1.0.0:
|
||||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
depd@2.0.0:
|
dotenv@17.3.1:
|
||||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==}
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
dotenv@17.2.3:
|
|
||||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
ee-first@1.1.1:
|
error-causes@3.0.2:
|
||||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
resolution: {integrity: sha512-i0B8zq1dHL6mM85FGoxaJnVtx6LD5nL2v0hlpGdntg5FOSyzQ46c9lmz5qx0xRS2+PWHGOHcYxGIBC5Le2dRMw==}
|
||||||
|
|
||||||
encodeurl@2.0.0:
|
|
||||||
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
es-define-property@1.0.1:
|
es-define-property@1.0.1:
|
||||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||||
@@ -253,22 +254,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
es-toolkit@1.43.0:
|
es-toolkit@1.45.1:
|
||||||
resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==}
|
resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==}
|
||||||
|
|
||||||
escape-html@1.0.3:
|
|
||||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
|
||||||
|
|
||||||
etag@1.8.1:
|
|
||||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
|
||||||
engines: {node: '>= 0.6'}
|
|
||||||
|
|
||||||
event-target-shim@5.0.1:
|
event-target-shim@5.0.1:
|
||||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
eventemitter3@5.0.1:
|
eventemitter3@5.0.4:
|
||||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
|
||||||
|
|
||||||
fast-glob@3.3.3:
|
fast-glob@3.3.3:
|
||||||
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
||||||
@@ -292,13 +286,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
||||||
engines: {node: '>= 12.20'}
|
engines: {node: '>= 12.20'}
|
||||||
|
|
||||||
fresh@2.0.0:
|
|
||||||
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
function-bind@1.1.2:
|
function-bind@1.1.2:
|
||||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
|
fuse.js@7.1.0:
|
||||||
|
resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -327,19 +321,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
http-errors@2.0.1:
|
|
||||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
humanize-ms@1.2.1:
|
humanize-ms@1.2.1:
|
||||||
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||||
|
|
||||||
idb-keyval@6.2.2:
|
idb-keyval@6.2.2:
|
||||||
resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==}
|
resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==}
|
||||||
|
|
||||||
inherits@2.0.4:
|
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
|
||||||
|
|
||||||
is-extglob@2.1.1:
|
is-extglob@2.1.1:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -372,18 +359,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
mime-db@1.54.0:
|
|
||||||
resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
|
|
||||||
engines: {node: '>= 0.6'}
|
|
||||||
|
|
||||||
mime-types@2.1.35:
|
mime-types@2.1.35:
|
||||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
mime-types@3.0.2:
|
|
||||||
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@@ -410,10 +389,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
||||||
engines: {node: '>= 6.13.0'}
|
engines: {node: '>= 6.13.0'}
|
||||||
|
|
||||||
on-finished@2.4.1:
|
|
||||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
openai@4.98.0:
|
openai@4.98.0:
|
||||||
resolution: {integrity: sha512-TmDKur1WjxxMPQAtLG5sgBSCJmX7ynTsGmewKzoDwl1fRxtbLOsiR0FA/AOAAtYUmP6azal+MYQuOENfdU+7yg==}
|
resolution: {integrity: sha512-TmDKur1WjxxMPQAtLG5sgBSCJmX7ynTsGmewKzoDwl1fRxtbLOsiR0FA/AOAAtYUmP6azal+MYQuOENfdU+7yg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -426,37 +401,28 @@ packages:
|
|||||||
zod:
|
zod:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
path-browserify-esm@1.0.6:
|
||||||
|
resolution: {integrity: sha512-9nUwYvvu/yq1PYrUyYCihNWmpzacaRYF6gGbjLWErrZ4MRDWyfPN7RpE8E7tsw8eqBU/rr7mcoTXbS+Vih8uUA==}
|
||||||
|
|
||||||
path-to-regexp@8.2.0:
|
path-to-regexp@8.2.0:
|
||||||
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
|
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
path-to-regexp@8.3.0:
|
|
||||||
resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==}
|
|
||||||
|
|
||||||
picomatch@2.3.1:
|
picomatch@2.3.1:
|
||||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
|
|
||||||
pkijs@3.3.3:
|
|
||||||
resolution: {integrity: sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==}
|
|
||||||
engines: {node: '>=16.0.0'}
|
|
||||||
|
|
||||||
pvtsutils@1.3.6:
|
|
||||||
resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==}
|
|
||||||
|
|
||||||
pvutils@1.1.5:
|
|
||||||
resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==}
|
|
||||||
engines: {node: '>=16.0.0'}
|
|
||||||
|
|
||||||
queue-microtask@1.2.3:
|
queue-microtask@1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
range-parser@1.2.1:
|
react-dom@19.2.4:
|
||||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==}
|
||||||
engines: {node: '>= 0.6'}
|
peerDependencies:
|
||||||
|
react: ^19.2.4
|
||||||
|
|
||||||
reflect-metadata@0.2.2:
|
react@19.2.4:
|
||||||
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
|
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
reusify@1.1.0:
|
reusify@1.1.0:
|
||||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||||
@@ -465,54 +431,37 @@ packages:
|
|||||||
run-parallel@1.2.0:
|
run-parallel@1.2.0:
|
||||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||||
|
|
||||||
|
scheduler@0.27.0:
|
||||||
|
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
||||||
|
|
||||||
selfsigned@2.4.1:
|
selfsigned@2.4.1:
|
||||||
resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==}
|
resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
selfsigned@5.4.0:
|
sonner@2.0.7:
|
||||||
resolution: {integrity: sha512-Yn8qZOOJv+NhcGY19iC+ngW6hlUCNpvWEkrKllXNhmkLgR9fcErm8EqZ/wev7/tiwjKC9qj17Fa/PtBNzb6q8g==}
|
resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
|
||||||
engines: {node: '>=15.6.0'}
|
peerDependencies:
|
||||||
|
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||||
|
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||||
|
|
||||||
send@1.2.1:
|
spark-md5@3.0.2:
|
||||||
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
|
resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==}
|
||||||
engines: {node: '>= 18'}
|
|
||||||
|
|
||||||
setprototypeof@1.2.0:
|
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
|
||||||
|
|
||||||
statuses@2.0.2:
|
|
||||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
|
||||||
engines: {node: '>= 0.8'}
|
|
||||||
|
|
||||||
to-regex-range@5.0.1:
|
to-regex-range@5.0.1:
|
||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
|
|
||||||
toidentifier@1.0.1:
|
|
||||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
|
||||||
engines: {node: '>=0.6'}
|
|
||||||
|
|
||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
tslib@1.14.1:
|
|
||||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
|
||||||
|
|
||||||
tslib@2.8.1:
|
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
|
||||||
|
|
||||||
tsyringe@4.10.0:
|
|
||||||
resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==}
|
|
||||||
engines: {node: '>= 6.0.0'}
|
|
||||||
|
|
||||||
undici-types@5.26.5:
|
undici-types@5.26.5:
|
||||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||||
|
|
||||||
undici-types@6.21.0:
|
undici-types@6.21.0:
|
||||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
undici-types@7.16.0:
|
undici-types@7.18.2:
|
||||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
||||||
|
|
||||||
web-streams-polyfill@4.0.0-beta.3:
|
web-streams-polyfill@4.0.0-beta.3:
|
||||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||||
@@ -524,19 +473,41 @@ packages:
|
|||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||||
|
|
||||||
|
zustand@5.0.11:
|
||||||
|
resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==}
|
||||||
|
engines: {node: '>=12.20.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '>=18.0.0'
|
||||||
|
immer: '>=9.0.6'
|
||||||
|
react: '>=18.0.0'
|
||||||
|
use-sync-external-store: '>=1.2.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
immer:
|
||||||
|
optional: true
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
use-sync-external-store:
|
||||||
|
optional: true
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@kevisual/cache@0.0.4':
|
'@kevisual/cache@0.0.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
idb-keyval: 6.2.2
|
idb-keyval: 6.2.2
|
||||||
lru-cache: 11.2.4
|
lru-cache: 11.2.4
|
||||||
nanoid: 5.1.6
|
nanoid: 5.1.6
|
||||||
|
|
||||||
'@kevisual/js-filter@0.0.3': {}
|
'@kevisual/code-builder@0.0.6': {}
|
||||||
|
|
||||||
|
'@kevisual/context@0.0.8': {}
|
||||||
|
|
||||||
|
'@kevisual/js-filter@0.0.6': {}
|
||||||
|
|
||||||
'@kevisual/load@0.0.6':
|
'@kevisual/load@0.0.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3: 5.0.1
|
eventemitter3: 5.0.4
|
||||||
|
|
||||||
'@kevisual/query@0.0.18':
|
'@kevisual/query@0.0.18':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -546,30 +517,31 @@ snapshots:
|
|||||||
- ws
|
- ws
|
||||||
- zod
|
- zod
|
||||||
|
|
||||||
'@kevisual/query@0.0.33': {}
|
'@kevisual/query@0.0.53': {}
|
||||||
|
|
||||||
|
'@kevisual/remote-app@0.0.6': {}
|
||||||
|
|
||||||
'@kevisual/router@0.0.20':
|
'@kevisual/router@0.0.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
path-to-regexp: 8.2.0
|
path-to-regexp: 8.2.0
|
||||||
selfsigned: 2.4.1
|
selfsigned: 2.4.1
|
||||||
|
|
||||||
'@kevisual/router@0.0.52':
|
'@kevisual/router@0.1.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3: 5.0.1
|
es-toolkit: 1.45.1
|
||||||
path-to-regexp: 8.3.0
|
|
||||||
selfsigned: 5.4.0
|
|
||||||
send: 1.2.1
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
'@kevisual/types@0.0.10': {}
|
'@kevisual/types@0.0.10': {}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.21(dotenv@17.2.3)':
|
'@kevisual/types@0.0.12': {}
|
||||||
|
|
||||||
|
'@kevisual/use-config@1.0.30(dotenv@17.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kevisual/load': 0.0.6
|
'@kevisual/load': 0.0.6
|
||||||
dotenv: 17.2.3
|
dotenv: 17.3.1
|
||||||
|
|
||||||
'@noble/hashes@1.4.0': {}
|
'@kevisual/ws@8.19.0': {}
|
||||||
|
|
||||||
|
'@noble/hashes@2.0.1': {}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -583,99 +555,15 @@ snapshots:
|
|||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.19.1
|
fastq: 1.19.1
|
||||||
|
|
||||||
'@peculiar/asn1-cms@2.6.0':
|
'@paralleldrive/cuid2@3.3.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
'@noble/hashes': 2.0.1
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
bignumber.js: 9.3.1
|
||||||
'@peculiar/asn1-x509-attr': 2.6.0
|
error-causes: 3.0.2
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-csr@2.6.0':
|
'@types/bun@1.3.10':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
bun-types: 1.3.10
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-ecc@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-pfx@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-cms': 2.6.0
|
|
||||||
'@peculiar/asn1-pkcs8': 2.6.0
|
|
||||||
'@peculiar/asn1-rsa': 2.6.0
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-pkcs8@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-pkcs9@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-cms': 2.6.0
|
|
||||||
'@peculiar/asn1-pfx': 2.6.0
|
|
||||||
'@peculiar/asn1-pkcs8': 2.6.0
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
'@peculiar/asn1-x509-attr': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-rsa@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-schema@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
asn1js: 3.0.6
|
|
||||||
pvtsutils: 1.3.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-x509-attr@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/asn1-x509@2.6.0':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
pvtsutils: 1.3.6
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
'@peculiar/x509@1.14.2':
|
|
||||||
dependencies:
|
|
||||||
'@peculiar/asn1-cms': 2.6.0
|
|
||||||
'@peculiar/asn1-csr': 2.6.0
|
|
||||||
'@peculiar/asn1-ecc': 2.6.0
|
|
||||||
'@peculiar/asn1-pkcs9': 2.6.0
|
|
||||||
'@peculiar/asn1-rsa': 2.6.0
|
|
||||||
'@peculiar/asn1-schema': 2.6.0
|
|
||||||
'@peculiar/asn1-x509': 2.6.0
|
|
||||||
pvtsutils: 1.3.6
|
|
||||||
reflect-metadata: 0.2.2
|
|
||||||
tslib: 2.8.1
|
|
||||||
tsyringe: 4.10.0
|
|
||||||
|
|
||||||
'@types/bun@1.3.5':
|
|
||||||
dependencies:
|
|
||||||
bun-types: 1.3.5
|
|
||||||
|
|
||||||
'@types/node-fetch@2.6.12':
|
'@types/node-fetch@2.6.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -694,9 +582,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
|
|
||||||
'@types/node@25.0.3':
|
'@types/node@25.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.18.2
|
||||||
|
|
||||||
|
'@types/spark-md5@3.0.5': {}
|
||||||
|
|
||||||
abort-controller@3.0.0:
|
abort-controller@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -706,23 +596,17 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
humanize-ms: 1.2.1
|
humanize-ms: 1.2.1
|
||||||
|
|
||||||
asn1js@3.0.6:
|
|
||||||
dependencies:
|
|
||||||
pvtsutils: 1.3.6
|
|
||||||
pvutils: 1.1.5
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
|
bignumber.js@9.3.1: {}
|
||||||
|
|
||||||
braces@3.0.3:
|
braces@3.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
bun-types@1.3.5:
|
bun-types@1.3.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.0.3
|
'@types/node': 25.4.0
|
||||||
|
|
||||||
bytestreamjs@2.0.1: {}
|
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.2:
|
call-bind-apply-helpers@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -733,15 +617,9 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
debug@4.4.3:
|
|
||||||
dependencies:
|
|
||||||
ms: 2.1.3
|
|
||||||
|
|
||||||
delayed-stream@1.0.0: {}
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
depd@2.0.0: {}
|
dotenv@17.3.1: {}
|
||||||
|
|
||||||
dotenv@17.2.3: {}
|
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -749,9 +627,7 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
gopd: 1.2.0
|
gopd: 1.2.0
|
||||||
|
|
||||||
ee-first@1.1.1: {}
|
error-causes@3.0.2: {}
|
||||||
|
|
||||||
encodeurl@2.0.0: {}
|
|
||||||
|
|
||||||
es-define-property@1.0.1: {}
|
es-define-property@1.0.1: {}
|
||||||
|
|
||||||
@@ -768,15 +644,11 @@ snapshots:
|
|||||||
has-tostringtag: 1.0.2
|
has-tostringtag: 1.0.2
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
||||||
es-toolkit@1.43.0: {}
|
es-toolkit@1.45.1: {}
|
||||||
|
|
||||||
escape-html@1.0.3: {}
|
|
||||||
|
|
||||||
etag@1.8.1: {}
|
|
||||||
|
|
||||||
event-target-shim@5.0.1: {}
|
event-target-shim@5.0.1: {}
|
||||||
|
|
||||||
eventemitter3@5.0.1: {}
|
eventemitter3@5.0.4: {}
|
||||||
|
|
||||||
fast-glob@3.3.3:
|
fast-glob@3.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -808,10 +680,10 @@ snapshots:
|
|||||||
node-domexception: 1.0.0
|
node-domexception: 1.0.0
|
||||||
web-streams-polyfill: 4.0.0-beta.3
|
web-streams-polyfill: 4.0.0-beta.3
|
||||||
|
|
||||||
fresh@2.0.0: {}
|
|
||||||
|
|
||||||
function-bind@1.1.2: {}
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
|
fuse.js@7.1.0: {}
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@@ -846,22 +718,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
http-errors@2.0.1:
|
|
||||||
dependencies:
|
|
||||||
depd: 2.0.0
|
|
||||||
inherits: 2.0.4
|
|
||||||
setprototypeof: 1.2.0
|
|
||||||
statuses: 2.0.2
|
|
||||||
toidentifier: 1.0.1
|
|
||||||
|
|
||||||
humanize-ms@1.2.1:
|
humanize-ms@1.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
idb-keyval@6.2.2: {}
|
idb-keyval@6.2.2: {}
|
||||||
|
|
||||||
inherits@2.0.4: {}
|
|
||||||
|
|
||||||
is-extglob@2.1.1: {}
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
@@ -883,16 +745,10 @@ snapshots:
|
|||||||
|
|
||||||
mime-db@1.52.0: {}
|
mime-db@1.52.0: {}
|
||||||
|
|
||||||
mime-db@1.54.0: {}
|
|
||||||
|
|
||||||
mime-types@2.1.35:
|
mime-types@2.1.35:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db: 1.52.0
|
mime-db: 1.52.0
|
||||||
|
|
||||||
mime-types@3.0.2:
|
|
||||||
dependencies:
|
|
||||||
mime-db: 1.54.0
|
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
nanoid@5.1.6: {}
|
nanoid@5.1.6: {}
|
||||||
@@ -905,10 +761,6 @@ snapshots:
|
|||||||
|
|
||||||
node-forge@1.3.1: {}
|
node-forge@1.3.1: {}
|
||||||
|
|
||||||
on-finished@2.4.1:
|
|
||||||
dependencies:
|
|
||||||
ee-first: 1.1.1
|
|
||||||
|
|
||||||
openai@4.98.0:
|
openai@4.98.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.19.100
|
'@types/node': 18.19.100
|
||||||
@@ -921,32 +773,20 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
|
|
||||||
path-to-regexp@8.2.0: {}
|
path-browserify-esm@1.0.6: {}
|
||||||
|
|
||||||
path-to-regexp@8.3.0: {}
|
path-to-regexp@8.2.0: {}
|
||||||
|
|
||||||
picomatch@2.3.1: {}
|
picomatch@2.3.1: {}
|
||||||
|
|
||||||
pkijs@3.3.3:
|
|
||||||
dependencies:
|
|
||||||
'@noble/hashes': 1.4.0
|
|
||||||
asn1js: 3.0.6
|
|
||||||
bytestreamjs: 2.0.1
|
|
||||||
pvtsutils: 1.3.6
|
|
||||||
pvutils: 1.1.5
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
pvtsutils@1.3.6:
|
|
||||||
dependencies:
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
pvutils@1.1.5: {}
|
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
|
||||||
range-parser@1.2.1: {}
|
react-dom@19.2.4(react@19.2.4):
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.4
|
||||||
|
scheduler: 0.27.0
|
||||||
|
|
||||||
reflect-metadata@0.2.2: {}
|
react@19.2.4: {}
|
||||||
|
|
||||||
reusify@1.1.0: {}
|
reusify@1.1.0: {}
|
||||||
|
|
||||||
@@ -954,57 +794,31 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask: 1.2.3
|
queue-microtask: 1.2.3
|
||||||
|
|
||||||
|
scheduler@0.27.0: {}
|
||||||
|
|
||||||
selfsigned@2.4.1:
|
selfsigned@2.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node-forge': 1.3.11
|
'@types/node-forge': 1.3.11
|
||||||
node-forge: 1.3.1
|
node-forge: 1.3.1
|
||||||
|
|
||||||
selfsigned@5.4.0:
|
sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@peculiar/x509': 1.14.2
|
react: 19.2.4
|
||||||
pkijs: 3.3.3
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
|
|
||||||
send@1.2.1:
|
spark-md5@3.0.2: {}
|
||||||
dependencies:
|
|
||||||
debug: 4.4.3
|
|
||||||
encodeurl: 2.0.0
|
|
||||||
escape-html: 1.0.3
|
|
||||||
etag: 1.8.1
|
|
||||||
fresh: 2.0.0
|
|
||||||
http-errors: 2.0.1
|
|
||||||
mime-types: 3.0.2
|
|
||||||
ms: 2.1.3
|
|
||||||
on-finished: 2.4.1
|
|
||||||
range-parser: 1.2.1
|
|
||||||
statuses: 2.0.2
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
|
||||||
|
|
||||||
statuses@2.0.2: {}
|
|
||||||
|
|
||||||
to-regex-range@5.0.1:
|
to-regex-range@5.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|
||||||
toidentifier@1.0.1: {}
|
|
||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
tslib@1.14.1: {}
|
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
|
||||||
|
|
||||||
tsyringe@4.10.0:
|
|
||||||
dependencies:
|
|
||||||
tslib: 1.14.1
|
|
||||||
|
|
||||||
undici-types@5.26.5: {}
|
undici-types@5.26.5: {}
|
||||||
|
|
||||||
undici-types@6.21.0: {}
|
undici-types@6.21.0: {}
|
||||||
|
|
||||||
undici-types@7.16.0: {}
|
undici-types@7.18.2: {}
|
||||||
|
|
||||||
web-streams-polyfill@4.0.0-beta.3: {}
|
web-streams-polyfill@4.0.0-beta.3: {}
|
||||||
|
|
||||||
@@ -1014,3 +828,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tr46: 0.0.3
|
tr46: 0.0.3
|
||||||
webidl-conversions: 3.0.1
|
webidl-conversions: 3.0.1
|
||||||
|
|
||||||
|
zustand@5.0.11(react@19.2.4):
|
||||||
|
optionalDependencies:
|
||||||
|
react: 19.2.4
|
||||||
|
|||||||
1
query/query-ai/index.ts
Normal file
1
query/query-ai/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-ai.ts'
|
||||||
1
query/query-app/index.ts
Normal file
1
query/query-app/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-app.ts'
|
||||||
@@ -22,11 +22,38 @@ export class QueryApp extends BaseQuery {
|
|||||||
data: data,
|
data: data,
|
||||||
}, opts);
|
}, opts);
|
||||||
}
|
}
|
||||||
getApp(data: any, opts?: DataOpts) {
|
getApp(data: {
|
||||||
|
key?: string;
|
||||||
|
version?: string;
|
||||||
|
/**
|
||||||
|
* 当app不存在,会创建一个新的,
|
||||||
|
* 之后上传文件就好了,会执行检测任务
|
||||||
|
*/
|
||||||
|
create?: boolean;
|
||||||
|
}, opts?: DataOpts) {
|
||||||
return this.query.post({
|
return this.query.post({
|
||||||
path: 'app',
|
path: 'app',
|
||||||
key: 'get',
|
key: 'get',
|
||||||
data: data,
|
data: data,
|
||||||
}, opts);
|
}, opts);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 发布应用
|
||||||
|
* @param data
|
||||||
|
* @param opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
publichApp(data: {
|
||||||
|
id?: string;
|
||||||
|
username?: string,
|
||||||
|
detect?: boolean,
|
||||||
|
appKey?: string;
|
||||||
|
version?: string;
|
||||||
|
}, opts?: DataOpts) {
|
||||||
|
return this.query.post({
|
||||||
|
path: 'app',
|
||||||
|
key: 'publish',
|
||||||
|
data: { detect: true, ...data },
|
||||||
|
}, opts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
query/query-config/index.ts
Normal file
1
query/query-config/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-config.ts';
|
||||||
123
query/query-login/browser-cache/cache-store.ts
Normal file
123
query/query-login/browser-cache/cache-store.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import { createStore, UseStore, get, set, del, clear, keys, values, entries, update, setMany, getMany, delMany } from 'idb-keyval';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存存储选项
|
||||||
|
*/
|
||||||
|
export type CacheStoreOpts = {
|
||||||
|
/**
|
||||||
|
* 数据库名称
|
||||||
|
*/
|
||||||
|
dbName?: string;
|
||||||
|
/**
|
||||||
|
* 存储空间名称
|
||||||
|
*/
|
||||||
|
storeName?: string;
|
||||||
|
};
|
||||||
|
export class BaseCacheStore {
|
||||||
|
store: UseStore;
|
||||||
|
constructor(opts?: CacheStoreOpts) {
|
||||||
|
this.store = createStore(opts?.dbName || 'default-db', opts?.storeName || 'cache-store');
|
||||||
|
}
|
||||||
|
async get(key: string) {
|
||||||
|
return get(key, this.store);
|
||||||
|
}
|
||||||
|
async set(key: string, value: any) {
|
||||||
|
return set(key, value, this.store);
|
||||||
|
}
|
||||||
|
async del(key: string) {
|
||||||
|
return del(key, this.store);
|
||||||
|
}
|
||||||
|
async clear() {
|
||||||
|
return clear(this.store);
|
||||||
|
}
|
||||||
|
async keys() {
|
||||||
|
return keys(this.store);
|
||||||
|
}
|
||||||
|
async values() {
|
||||||
|
return values(this.store);
|
||||||
|
}
|
||||||
|
async entries() {
|
||||||
|
return entries(this.store);
|
||||||
|
}
|
||||||
|
async update(key: string, updater: (value: any) => any) {
|
||||||
|
return update(key, updater, this.store);
|
||||||
|
}
|
||||||
|
async setMany(entries: [string, any][]) {
|
||||||
|
return setMany(entries, this.store);
|
||||||
|
}
|
||||||
|
async getMany(keys: string[]) {
|
||||||
|
return getMany(keys, this.store);
|
||||||
|
}
|
||||||
|
async delMany(keys: string[]) {
|
||||||
|
return delMany(keys, this.store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存存储
|
||||||
|
*/
|
||||||
|
export class CacheStore extends BaseCacheStore {
|
||||||
|
constructor(opts?: CacheStoreOpts) {
|
||||||
|
super(opts);
|
||||||
|
}
|
||||||
|
async getData<T = any>(key: string) {
|
||||||
|
const data = await this.get(key);
|
||||||
|
return data.data as T;
|
||||||
|
}
|
||||||
|
async setData(key: string, data: any) {
|
||||||
|
return this.set(key, data);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取缓存数据,并检查是否过期
|
||||||
|
* @param key 缓存键
|
||||||
|
* @returns 缓存数据
|
||||||
|
*/
|
||||||
|
async getCheckData<T = any>(key: string) {
|
||||||
|
const data = await this.get(key);
|
||||||
|
if (data.expireTime && data.expireTime < Date.now()) {
|
||||||
|
await super.del(key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data.data as T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置缓存数据,并检查是否过期
|
||||||
|
* @param key 缓存键
|
||||||
|
* @param data 缓存数据
|
||||||
|
* @param opts 缓存选项
|
||||||
|
* @returns 缓存数据
|
||||||
|
*/
|
||||||
|
async setCheckData(key: string, data: any, opts?: { expireTime?: number; updatedAt?: number }) {
|
||||||
|
const now = Date.now();
|
||||||
|
const expireTime = now + (opts?.expireTime || 1000 * 60 * 60 * 24 * 10);
|
||||||
|
const newData = {
|
||||||
|
data,
|
||||||
|
updatedAt: opts?.updatedAt || Date.now(),
|
||||||
|
expireTime,
|
||||||
|
};
|
||||||
|
await this.set(key, newData);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
async checkNew(key: string, data: any): Promise<boolean> {
|
||||||
|
const existing = await this.get(key);
|
||||||
|
if (!existing) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!data?.updatedAt) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const updatedAt = new Date(data.updatedAt).getTime();
|
||||||
|
if (isNaN(updatedAt)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return updatedAt > existing.updatedAt;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 删除缓存数据
|
||||||
|
* @param key 缓存键
|
||||||
|
* @returns 缓存数据
|
||||||
|
*/
|
||||||
|
async delCheckData(key: string) {
|
||||||
|
return this.del(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
query/query-login/browser-cache/cache.ts
Normal file
29
query/query-login/browser-cache/cache.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
export { CacheStore, BaseCacheStore } from './cache-store.ts'
|
||||||
|
import { CacheStore } from './cache-store.ts'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个简单的缓存类,用于存储字符串。
|
||||||
|
* 对数据进行添加对比内容。
|
||||||
|
*/
|
||||||
|
export class MyCache<T = any> extends CacheStore {
|
||||||
|
key: string;
|
||||||
|
constructor(opts?: { key?: string }) {
|
||||||
|
const { key, ...rest } = opts || {};
|
||||||
|
super(rest);
|
||||||
|
this.key = key || 'my-cache';
|
||||||
|
}
|
||||||
|
async getData<U = T>(key: string = this.key): Promise<U> {
|
||||||
|
return super.getCheckData<U>(key) as any;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置缓存数据,默认过期时间为10天
|
||||||
|
* @param data
|
||||||
|
* @param opts
|
||||||
|
*/
|
||||||
|
async setData<U = T>(data: U, opts?: { expireTime?: number, updatedAt?: number }) {
|
||||||
|
super.setCheckData(this.key, data, opts);
|
||||||
|
}
|
||||||
|
async del(): Promise<void> {
|
||||||
|
await super.del(this.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
query/query-login/index.ts
Normal file
1
query/query-login/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-login-browser.ts';
|
||||||
@@ -16,7 +16,7 @@ export interface Cache {
|
|||||||
*/
|
*/
|
||||||
init?: () => Promise<any>;
|
init?: () => Promise<any>;
|
||||||
}
|
}
|
||||||
type User = {
|
export type User = {
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -31,12 +31,14 @@ export type CacheLoginUser = {
|
|||||||
id?: string;
|
id?: string;
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
|
accessTokenExpiresIn?: number;
|
||||||
|
createdAt?: number;
|
||||||
};
|
};
|
||||||
type CacheLogin = {
|
type CacheLogin = {
|
||||||
loginUsers: CacheLoginUser[];
|
loginUsers: CacheLoginUser[];
|
||||||
} & CacheLoginUser;
|
} & CacheLoginUser;
|
||||||
|
|
||||||
export type CacheStore<T = Cache> = {
|
export type CacheStore<T extends Cache = Cache> = {
|
||||||
name: string;
|
name: string;
|
||||||
/**
|
/**
|
||||||
* 缓存数据
|
* 缓存数据
|
||||||
@@ -80,29 +82,43 @@ export type CacheStore<T = Cache> = {
|
|||||||
getValue(): Promise<CacheLogin>;
|
getValue(): Promise<CacheLogin>;
|
||||||
setValue(value: CacheLogin): Promise<CacheLogin>;
|
setValue(value: CacheLogin): Promise<CacheLogin>;
|
||||||
delValue(): Promise<void>;
|
delValue(): Promise<void>;
|
||||||
init(): Promise<any>;
|
init(): Promise<CacheLogin>;
|
||||||
|
getIsExpired(): Promise<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LoginCacheStoreOpts = {
|
export type LoginCacheStoreOpts<T extends Cache = Cache> = {
|
||||||
name: string;
|
name: string;
|
||||||
cache: Cache;
|
cache: T;
|
||||||
};
|
};
|
||||||
export class LoginCacheStore implements CacheStore<any> {
|
const defaultCacheData: CacheLogin = {
|
||||||
cache: Cache;
|
loginUsers: [],
|
||||||
|
user: undefined,
|
||||||
|
id: undefined,
|
||||||
|
accessToken: undefined,
|
||||||
|
refreshToken: undefined,
|
||||||
|
accessTokenExpiresIn: undefined,
|
||||||
|
createdAt: undefined,
|
||||||
|
}
|
||||||
|
export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
||||||
|
cache: T;
|
||||||
name: string;
|
name: string;
|
||||||
cacheData: CacheLogin;
|
cacheData: CacheLogin;
|
||||||
constructor(opts: LoginCacheStoreOpts) {
|
constructor(opts: LoginCacheStoreOpts<T>) {
|
||||||
if (!opts.cache) {
|
if (!opts.cache) {
|
||||||
throw new Error('cache is required');
|
throw new Error('cache is required');
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.cache = opts.cache;
|
this.cache = opts.cache;
|
||||||
this.cacheData = {
|
this.cacheData = { ...defaultCacheData };
|
||||||
loginUsers: [],
|
this.name = opts.name;
|
||||||
user: undefined,
|
}
|
||||||
id: undefined,
|
/**
|
||||||
accessToken: undefined,
|
* 设置缓存
|
||||||
refreshToken: undefined,
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @returns
|
||||||
|
accessTokenExpiresIn: undefined,
|
||||||
|
createdAt: undefined,
|
||||||
};
|
};
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
}
|
}
|
||||||
@@ -122,6 +138,7 @@ export class LoginCacheStore implements CacheStore<any> {
|
|||||||
*/
|
*/
|
||||||
async delValue() {
|
async delValue() {
|
||||||
await this.cache.del();
|
await this.cache.del();
|
||||||
|
this.cacheData = { ...defaultCacheData };
|
||||||
}
|
}
|
||||||
getValue(): Promise<CacheLogin> {
|
getValue(): Promise<CacheLogin> {
|
||||||
return this.cache.get(this.name);
|
return this.cache.get(this.name);
|
||||||
@@ -129,39 +146,38 @@ export class LoginCacheStore implements CacheStore<any> {
|
|||||||
/**
|
/**
|
||||||
* 初始化,设置默认值
|
* 初始化,设置默认值
|
||||||
*/
|
*/
|
||||||
async init() {
|
async init(): Promise<CacheLogin> {
|
||||||
const defaultData = {
|
const defaultData: CacheLogin = { ...this.cacheData };
|
||||||
loginUsers: [],
|
return new Promise(async (resolve) => {
|
||||||
user: null,
|
if (this.cache.init) {
|
||||||
id: null,
|
try {
|
||||||
accessToken: null,
|
const cacheData = await this.cache.init();
|
||||||
refreshToken: null,
|
this.cacheData = cacheData || defaultData;
|
||||||
};
|
} catch (error) {
|
||||||
if (this.cache.init) {
|
console.log('cacheInit error', error);
|
||||||
try {
|
}
|
||||||
const cacheData = await this.cache.init();
|
} else {
|
||||||
this.cacheData = cacheData || defaultData;
|
this.cacheData = (await this.getValue()) || defaultData;
|
||||||
} catch (error) {
|
|
||||||
console.log('cacheInit error', error);
|
|
||||||
}
|
}
|
||||||
} else {
|
resolve(this.cacheData);
|
||||||
this.cacheData = (await this.getValue()) || defaultData;
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 设置当前用户
|
* 设置当前用户
|
||||||
* @param user
|
* @param user
|
||||||
*/
|
*/
|
||||||
async setLoginUser(user: CacheLoginUser) {
|
async setLoginUser(loginUser: CacheLoginUser) {
|
||||||
const has = this.cacheData.loginUsers.find((u) => u.id === user.id);
|
const has = this.cacheData.loginUsers.find((u) => u.id === loginUser.id);
|
||||||
if (has) {
|
if (has) {
|
||||||
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
|
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== loginUser.id);
|
||||||
}
|
}
|
||||||
this.cacheData.loginUsers.push(user);
|
this.cacheData.loginUsers.push(loginUser);
|
||||||
this.cacheData.user = user.user;
|
this.cacheData.user = loginUser.user;
|
||||||
this.cacheData.id = user.id;
|
this.cacheData.id = loginUser.id;
|
||||||
this.cacheData.accessToken = user.accessToken;
|
this.cacheData.accessToken = loginUser.accessToken;
|
||||||
this.cacheData.refreshToken = user.refreshToken;
|
this.cacheData.refreshToken = loginUser.refreshToken;
|
||||||
|
this.cacheData.accessTokenExpiresIn = loginUser.accessTokenExpiresIn;
|
||||||
|
this.cacheData.createdAt = loginUser.createdAt;
|
||||||
await this.setValue(this.cacheData);
|
await this.setValue(this.cacheData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +196,18 @@ export class LoginCacheStore implements CacheStore<any> {
|
|||||||
const cacheData = this.cacheData;
|
const cacheData = this.cacheData;
|
||||||
return Promise.resolve(cacheData.accessToken || '');
|
return Promise.resolve(cacheData.accessToken || '');
|
||||||
}
|
}
|
||||||
|
getIsExpired(): Promise<boolean> {
|
||||||
|
const cacheData = this.cacheData;
|
||||||
|
if (!cacheData.accessToken) {
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
if (!cacheData.createdAt || !cacheData.accessTokenExpiresIn) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
const now = Date.now();
|
||||||
|
const expiresIn = cacheData.createdAt + cacheData.accessTokenExpiresIn * 1000;
|
||||||
|
return Promise.resolve(now >= expiresIn);
|
||||||
|
}
|
||||||
|
|
||||||
async clearCurrentUser() {
|
async clearCurrentUser() {
|
||||||
const user = await this.getCurrentUser();
|
const user = await this.getCurrentUser();
|
||||||
@@ -187,18 +215,22 @@ export class LoginCacheStore implements CacheStore<any> {
|
|||||||
if (has) {
|
if (has) {
|
||||||
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
|
this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id);
|
||||||
}
|
}
|
||||||
this.cacheData.user = undefined;
|
const hasOther = this.cacheData.loginUsers.length > 0;
|
||||||
this.cacheData.id = undefined;
|
const current = this.cacheData.loginUsers[this.cacheData.loginUsers.length - 1];
|
||||||
this.cacheData.accessToken = undefined;
|
if (hasOther && current) {
|
||||||
this.cacheData.refreshToken = undefined;
|
this.cacheData.user = current.user;
|
||||||
|
this.cacheData.id = current.id;
|
||||||
|
this.cacheData.accessToken = current.accessToken;
|
||||||
|
this.cacheData.refreshToken = current.refreshToken;
|
||||||
|
this.cacheData.accessTokenExpiresIn = current.accessTokenExpiresIn;
|
||||||
|
this.cacheData.createdAt = current.createdAt;
|
||||||
|
} else {
|
||||||
|
this.cacheData = { ...defaultCacheData };
|
||||||
|
}
|
||||||
await this.setValue(this.cacheData);
|
await this.setValue(this.cacheData);
|
||||||
}
|
}
|
||||||
async clearAll() {
|
async clearAll() {
|
||||||
this.cacheData.loginUsers = [];
|
this.cacheData = { ...defaultCacheData };
|
||||||
this.cacheData.user = undefined;
|
|
||||||
this.cacheData.id = undefined;
|
|
||||||
this.cacheData.accessToken = undefined;
|
|
||||||
this.cacheData.refreshToken = undefined;
|
|
||||||
await this.setValue(this.cacheData);
|
await this.setValue(this.cacheData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import { Cache } from './login-cache.ts';
|
|||||||
import { homedir } from 'node:os';
|
import { homedir } from 'node:os';
|
||||||
import { join, dirname } from 'node:path';
|
import { join, dirname } from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { readFileSync, writeFileSync, accessSync } from 'node:fs';
|
import { readFileSync, writeFileSync, accessSync, unlinkSync, mkdirSync } from 'node:fs';
|
||||||
import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
|
export const fileExists = (
|
||||||
export const fileExists = async (
|
|
||||||
filePath: string,
|
filePath: string,
|
||||||
{ createIfNotExists = true, isFile = true, isDir = false }: { createIfNotExists?: boolean; isFile?: boolean; isDir?: boolean } = {},
|
{ createIfNotExists = true, isFile = true, isDir = false }: { createIfNotExists?: boolean; isFile?: boolean; isDir?: boolean } = {},
|
||||||
) => {
|
) => {
|
||||||
@@ -13,10 +12,10 @@ export const fileExists = async (
|
|||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (createIfNotExists && isDir) {
|
if (createIfNotExists && isDir) {
|
||||||
await mkdir(filePath, { recursive: true });
|
mkdirSync(filePath, { recursive: true });
|
||||||
return true;
|
return true;
|
||||||
} else if (createIfNotExists && isFile) {
|
} else if (createIfNotExists && isFile) {
|
||||||
await mkdir(dirname(filePath), { recursive: true });
|
mkdirSync(dirname(filePath), { recursive: true });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -34,32 +33,50 @@ export const readConfigFile = (filePath: string) => {
|
|||||||
export const writeConfigFile = (filePath: string, data: any) => {
|
export const writeConfigFile = (filePath: string, data: any) => {
|
||||||
writeFileSync(filePath, JSON.stringify(data, null, 2));
|
writeFileSync(filePath, JSON.stringify(data, null, 2));
|
||||||
};
|
};
|
||||||
export const getHostName = () => {
|
/**
|
||||||
|
* 获取主机名,
|
||||||
|
* 例如:https://kevisual.cn 返回 kevisual.cn
|
||||||
|
* 这里是读取默认的配置文件 ~/.config/envision/config.json 中的 baseURL 字段来获取主机名的,如果没有配置 baseURL 则默认使用 https://kevisual.cn
|
||||||
|
* @returns 主机名
|
||||||
|
*/
|
||||||
|
export const getHostName = (baseURL?: string) => {
|
||||||
const configDir = join(homedir(), '.config', 'envision');
|
const configDir = join(homedir(), '.config', 'envision');
|
||||||
const configFile = join(configDir, 'config.json');
|
const configFile = join(configDir, 'config.json');
|
||||||
const config = readConfigFile(configFile);
|
const config = readConfigFile(configFile);
|
||||||
const baseURL = config.baseURL || 'https://kevisual.cn';
|
const _baseURL = baseURL || config.baseURL || 'https://kevisual.cn';
|
||||||
const hostname = new URL(baseURL).hostname;
|
const hostname = new URL(_baseURL).hostname;
|
||||||
return hostname;
|
return hostname;
|
||||||
};
|
};
|
||||||
export class StorageNode implements Storage {
|
export class StorageNode implements Storage {
|
||||||
cacheData: any;
|
cacheData: any;
|
||||||
filePath: string;
|
filePath: string = '';
|
||||||
constructor() {
|
hostname: string = '';
|
||||||
|
constructor(opts?: { baseURL?: string, load?: boolean }) {
|
||||||
this.cacheData = {};
|
this.cacheData = {};
|
||||||
const configDir = join(homedir(), '.config', 'envision');
|
const hostname = getHostName(opts?.baseURL);
|
||||||
const hostname = getHostName();
|
this.setHostName(hostname, { load: opts?.load });
|
||||||
this.filePath = join(configDir, 'config', `${hostname}-storage.json`);
|
|
||||||
fileExists(this.filePath, { isFile: true });
|
|
||||||
}
|
}
|
||||||
async loadCache() {
|
setHostName(hostname: string, opts?: { load?: boolean }) {
|
||||||
|
const load = opts?.load ?? false;
|
||||||
|
if (hostname.startsWith('http')) {
|
||||||
|
hostname = new URL(hostname).hostname;
|
||||||
|
}
|
||||||
|
const configDir = join(homedir(), '.config', 'envision');
|
||||||
|
this.filePath = join(configDir, 'config', `${hostname}-storage.json`);
|
||||||
|
this.hostname = hostname;
|
||||||
|
fileExists(this.filePath, { isFile: true });
|
||||||
|
if (load) {
|
||||||
|
this.loadCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadCache() {
|
||||||
const filePath = this.filePath;
|
const filePath = this.filePath;
|
||||||
try {
|
try {
|
||||||
const data = await readConfigFile(filePath);
|
const data = readConfigFile(filePath);
|
||||||
this.cacheData = data;
|
this.cacheData = data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.cacheData = {};
|
this.cacheData = {};
|
||||||
await writeFile(filePath, JSON.stringify(this.cacheData, null, 2));
|
writeFileSync(filePath, JSON.stringify(this.cacheData, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get length() {
|
get length() {
|
||||||
@@ -70,15 +87,15 @@ export class StorageNode implements Storage {
|
|||||||
}
|
}
|
||||||
setItem(key: string, value: any) {
|
setItem(key: string, value: any) {
|
||||||
this.cacheData[key] = value;
|
this.cacheData[key] = value;
|
||||||
writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||||
}
|
}
|
||||||
removeItem(key: string) {
|
removeItem(key: string) {
|
||||||
delete this.cacheData[key];
|
delete this.cacheData[key];
|
||||||
writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||||
}
|
}
|
||||||
clear() {
|
clear() {
|
||||||
this.cacheData = {};
|
this.cacheData = {};
|
||||||
writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||||
}
|
}
|
||||||
key(index: number) {
|
key(index: number) {
|
||||||
return Object.keys(this.cacheData)[index];
|
return Object.keys(this.cacheData)[index];
|
||||||
@@ -86,10 +103,12 @@ export class StorageNode implements Storage {
|
|||||||
}
|
}
|
||||||
export class LoginNodeCache implements Cache {
|
export class LoginNodeCache implements Cache {
|
||||||
filepath: string;
|
filepath: string;
|
||||||
|
constructor(opts?: { baseURL?: string, load?: boolean }) {
|
||||||
constructor(filepath?: string) {
|
this.filepath = join(homedir(), '.config', 'envision', 'config', `${getHostName(opts?.baseURL)}-login.json`);
|
||||||
this.filepath = filepath || join(homedir(), '.config', 'envision', 'config', `${getHostName()}-login.json`);
|
|
||||||
fileExists(this.filepath, { isFile: true });
|
fileExists(this.filepath, { isFile: true });
|
||||||
|
if (opts?.load) {
|
||||||
|
this.loadCache(this.filepath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async get(_key: string) {
|
async get(_key: string) {
|
||||||
try {
|
try {
|
||||||
@@ -111,11 +130,11 @@ export class LoginNodeCache implements Cache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async del() {
|
async del() {
|
||||||
await unlink(this.filepath);
|
unlinkSync(this.filepath);
|
||||||
}
|
}
|
||||||
async loadCache(filePath: string) {
|
loadCache(filePath: string) {
|
||||||
try {
|
try {
|
||||||
const data = await readFile(filePath, 'utf-8');
|
const data = readFileSync(filePath, 'utf-8');
|
||||||
const jsonData = JSON.parse(data);
|
const jsonData = JSON.parse(data);
|
||||||
return jsonData;
|
return jsonData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -126,7 +145,7 @@ export class LoginNodeCache implements Cache {
|
|||||||
return defaultData;
|
return defaultData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async init() {
|
init() {
|
||||||
return await this.loadCache(this.filepath);
|
return this.loadCache(this.filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { QueryLogin, QueryLoginOpts } from './query-login.ts';
|
import { QueryLogin, QueryLoginOpts } from './query-login.ts';
|
||||||
import { MyCache } from '@kevisual/cache';
|
import { MyCache } from './browser-cache/cache.ts';
|
||||||
type QueryLoginNodeOptsWithoutCache = Omit<QueryLoginOpts, 'cache'>;
|
type QueryLoginNodeOptsWithoutCache = Omit<QueryLoginOpts, 'cache'>;
|
||||||
|
|
||||||
export class QueryLoginBrowser extends QueryLogin {
|
export class QueryLoginBrowser extends QueryLogin {
|
||||||
constructor(opts: QueryLoginNodeOptsWithoutCache) {
|
constructor(opts: QueryLoginNodeOptsWithoutCache) {
|
||||||
super({
|
super({
|
||||||
...opts,
|
...opts,
|
||||||
cache: new MyCache('login'),
|
cache: new MyCache({ key: 'login' }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { QueryLogin, QueryLoginOpts } from './query-login.ts';
|
import { QueryLogin, QueryLoginOpts } from './query-login.ts';
|
||||||
import { LoginNodeCache, StorageNode } from './login-node-cache.ts';
|
import { LoginNodeCache, StorageNode } from './login-node-cache.ts';
|
||||||
type QueryLoginNodeOptsWithoutCache = Omit<QueryLoginOpts, 'cache'>;
|
type QueryLoginNodeOptsWithoutCache = Omit<QueryLoginOpts, 'cache'>;
|
||||||
export const storage = new StorageNode();
|
export { StorageNode }
|
||||||
await storage.loadCache();
|
export const cache = new LoginNodeCache();
|
||||||
export class QueryLoginNode extends QueryLogin {
|
export class QueryLoginNode extends QueryLogin<LoginNodeCache> {
|
||||||
|
declare storage: StorageNode;
|
||||||
constructor(opts: QueryLoginNodeOptsWithoutCache) {
|
constructor(opts: QueryLoginNodeOptsWithoutCache) {
|
||||||
|
const baseURL = opts?.query?.baseURL;
|
||||||
|
const storage = new StorageNode({ baseURL, load: true });
|
||||||
|
const cache = new LoginNodeCache({ baseURL, load: true });
|
||||||
super({
|
super({
|
||||||
...opts,
|
...opts,
|
||||||
|
isBrowser: false,
|
||||||
storage,
|
storage,
|
||||||
cache: new LoginNodeCache(),
|
cache,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Query, BaseQuery } from '@kevisual/query';
|
import { Query, BaseQuery } from '@kevisual/query';
|
||||||
import type { Result, DataOpts } from '@kevisual/query/query';
|
import type { Result, DataOpts } from '@kevisual/query/query';
|
||||||
import { setBaseResponse } from '@kevisual/query/query';
|
import { LoginCacheStore, CacheStore, User } from './login-cache.ts';
|
||||||
import { LoginCacheStore, CacheStore } from './login-cache.ts';
|
|
||||||
import { Cache } from './login-cache.ts';
|
import { Cache } from './login-cache.ts';
|
||||||
import { BaseLoad } from '@kevisual/load';
|
import { BaseLoad } from '@kevisual/load';
|
||||||
export type QueryLoginOpts = {
|
import { EventEmitter } from 'eventemitter3'
|
||||||
|
export type QueryLoginOpts<T extends Cache = Cache> = {
|
||||||
query?: Query;
|
query?: Query;
|
||||||
isBrowser?: boolean;
|
isBrowser?: boolean;
|
||||||
onLoad?: () => void;
|
onLoad?: () => void;
|
||||||
storage?: Storage;
|
storage?: Storage;
|
||||||
cache: Cache;
|
cache: T;
|
||||||
};
|
};
|
||||||
export type QueryLoginData = {
|
export type QueryLoginData = {
|
||||||
username?: string;
|
username?: string;
|
||||||
@@ -21,33 +21,53 @@ export type QueryLoginResult = {
|
|||||||
refreshToken: string;
|
refreshToken: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class QueryLogin extends BaseQuery {
|
export class QueryLogin<T extends Cache = Cache> extends BaseQuery {
|
||||||
/**
|
/**
|
||||||
* query login cache, 非实际操作, 一个cache的包裹模块
|
* query login cache, 非实际操作, 一个cache的包裹模块
|
||||||
*/
|
*/
|
||||||
cacheStore: CacheStore;
|
cacheStore: CacheStore<T>;
|
||||||
isBrowser: boolean;
|
isBrowser: boolean;
|
||||||
load?: boolean;
|
|
||||||
storage: Storage;
|
storage: Storage;
|
||||||
|
load: boolean = false;
|
||||||
|
status: 'init' | 'logining' | 'loginSuccess' | 'loginError' = 'init';
|
||||||
onLoad?: () => void;
|
onLoad?: () => void;
|
||||||
|
emitter = new EventEmitter();
|
||||||
|
|
||||||
constructor(opts?: QueryLoginOpts) {
|
constructor(opts?: QueryLoginOpts<T>) {
|
||||||
super({
|
super({
|
||||||
query: opts?.query || new Query(),
|
query: opts?.query || new Query(),
|
||||||
});
|
});
|
||||||
this.cacheStore = new LoginCacheStore({ name: 'login', cache: opts?.cache! });
|
this.cacheStore = new LoginCacheStore<T>({ name: 'login', cache: opts?.cache! });
|
||||||
this.isBrowser = opts?.isBrowser ?? true;
|
this.isBrowser = opts?.isBrowser ?? true;
|
||||||
this.init();
|
this.init();
|
||||||
this.onLoad = opts?.onLoad;
|
this.onLoad = opts?.onLoad;
|
||||||
this.storage = opts?.storage || localStorage;
|
this.storage = opts?.storage || globalThis?.localStorage;
|
||||||
|
if (!this.storage) {
|
||||||
|
throw new Error('storage is required');
|
||||||
|
}
|
||||||
|
this.cacheStore.init().then(() => {
|
||||||
|
this.onLoad?.();
|
||||||
|
this.load = true;
|
||||||
|
this.emitter.emit('load');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setQuery(query: Query) {
|
setQuery(query: Query) {
|
||||||
this.query = query;
|
this.query = query;
|
||||||
}
|
}
|
||||||
private async init() {
|
async init() {
|
||||||
await this.cacheStore.init();
|
if (this.load) {
|
||||||
this.load = true;
|
return this.cacheStore.cacheData;
|
||||||
this.onLoad?.();
|
}
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
resolve(this.cacheStore.cacheData);
|
||||||
|
}, 1000 * 20); // 20秒超时,避免一直等待
|
||||||
|
const listener = () => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(this.cacheStore.cacheData);
|
||||||
|
}
|
||||||
|
this.emitter.once('load', listener);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
async post<T = any>(data: any, opts?: DataOpts) {
|
async post<T = any>(data: any, opts?: DataOpts) {
|
||||||
try {
|
try {
|
||||||
@@ -67,9 +87,9 @@ export class QueryLogin extends BaseQuery {
|
|||||||
async login(data: QueryLoginData) {
|
async login(data: QueryLoginData) {
|
||||||
const res = await this.post<QueryLoginResult>({ key: 'login', ...data });
|
const res = await this.post<QueryLoginResult>({ key: 'login', ...data });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const { accessToken, refreshToken } = res?.data || {};
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
this.storage.setItem('token', accessToken || '');
|
this.storage.setItem('token', accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken, refreshToken });
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -81,9 +101,9 @@ export class QueryLogin extends BaseQuery {
|
|||||||
async loginByCode(data: { phone: string; code: string }) {
|
async loginByCode(data: { phone: string; code: string }) {
|
||||||
const res = await this.post<QueryLoginResult>({ path: 'sms', key: 'login', data });
|
const res = await this.post<QueryLoginResult>({ path: 'sms', key: 'login', data });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const { accessToken, refreshToken } = res?.data || {};
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
this.storage.setItem('token', accessToken || '');
|
this.storage.setItem('token', accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken, refreshToken });
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -91,17 +111,37 @@ export class QueryLogin extends BaseQuery {
|
|||||||
* 设置token
|
* 设置token
|
||||||
* @param token
|
* @param token
|
||||||
*/
|
*/
|
||||||
async setLoginToken(token: { accessToken: string; refreshToken: string }) {
|
async setLoginToken(token: { accessToken: string; refreshToken: string; accessTokenExpiresIn?: number }) {
|
||||||
const { accessToken, refreshToken } = token;
|
const { accessToken, refreshToken, accessTokenExpiresIn } = token;
|
||||||
this.storage.setItem('token', accessToken || '');
|
this.storage.setItem('token', accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken, refreshToken });
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
}
|
}
|
||||||
async loginByWechat(data: { code: string }) {
|
async loginByWechat(data: { code: string }) {
|
||||||
const res = await this.post<QueryLoginResult>({ path: 'wx', key: 'open-login', code: data.code });
|
const res = await this.post<QueryLoginResult>({ path: 'wx', key: 'open-login', code: data.code });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const { accessToken, refreshToken } = res?.data || {};
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
this.storage.setItem('token', accessToken || '');
|
this.storage.setItem('token', accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken, refreshToken });
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* cnb登录, 适用于cnb的登录方式, 需要后端配合, 传入cnbToken, 后端验证cnbToken的有效性,并返回accessToken和refreshToken
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async loginByCnb(data: { cnbToken: string }) {
|
||||||
|
const res = await this.post<QueryLoginResult>({
|
||||||
|
path: 'user',
|
||||||
|
key: 'cnb-login',
|
||||||
|
payload: {
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
|
this.storage.setItem('token', accessToken || '');
|
||||||
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -126,7 +166,8 @@ export class QueryLogin extends BaseQuery {
|
|||||||
* 登陆成功,需要获取用户信息进行缓存
|
* 登陆成功,需要获取用户信息进行缓存
|
||||||
* @param param0
|
* @param param0
|
||||||
*/
|
*/
|
||||||
async beforeSetLoginUser({ accessToken, refreshToken, check401 }: { accessToken?: string; refreshToken?: string; check401?: boolean }) {
|
async beforeSetLoginUser(opts: { accessTokenExpiresIn?: number, accessToken?: string; refreshToken?: string; check401?: boolean }): Promise<Result<User>> {
|
||||||
|
const { accessToken, refreshToken, check401, accessTokenExpiresIn } = opts;
|
||||||
if (accessToken && refreshToken) {
|
if (accessToken && refreshToken) {
|
||||||
const resUser = await this.getMe(accessToken, check401);
|
const resUser = await this.getMe(accessToken, check401);
|
||||||
if (resUser.code === 200) {
|
if (resUser.code === 200) {
|
||||||
@@ -137,21 +178,50 @@ export class QueryLogin extends BaseQuery {
|
|||||||
id: user.id,
|
id: user.id,
|
||||||
accessToken,
|
accessToken,
|
||||||
refreshToken,
|
refreshToken,
|
||||||
|
accessTokenExpiresIn,
|
||||||
|
createdAt: Date.now(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error('登录失败');
|
console.error('登录失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return resUser;
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
code: 400,
|
||||||
|
message: '登录失败',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 刷新登录用户,获取新的token,并更新用户信息
|
||||||
|
* @param refreshToken 刷新token,如果不传,则从缓存中获取
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async refreshLoginUser(opts?: { refreshToken?: string, accessToken?: string }) {
|
||||||
|
const res = await this.queryRefreshToken(opts);
|
||||||
|
if (res.code === 200) {
|
||||||
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
|
this.storage.setItem('token', accessToken || '');
|
||||||
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn, check401: false });
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 刷新token
|
* 刷新token
|
||||||
* @param refreshToken
|
* @param refreshToken
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async queryRefreshToken(refreshToken?: string) {
|
async queryRefreshToken(opts?: { refreshToken?: string, accessToken?: string }) {
|
||||||
const _refreshToken = refreshToken || this.cacheStore.getRefreshToken();
|
const refreshToken = opts?.refreshToken;
|
||||||
let data = { refreshToken: _refreshToken };
|
let accessToken = opts?.accessToken;
|
||||||
|
const _refreshToken = refreshToken ?? (await this.cacheStore.getRefreshToken());
|
||||||
|
let data: any = {};
|
||||||
|
if (accessToken) {
|
||||||
|
data.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
if (_refreshToken) {
|
||||||
|
data.refreshToken = _refreshToken;
|
||||||
|
}
|
||||||
if (!_refreshToken) {
|
if (!_refreshToken) {
|
||||||
await this.cacheStore.clearCurrentUser();
|
await this.cacheStore.clearCurrentUser();
|
||||||
return {
|
return {
|
||||||
@@ -164,7 +234,6 @@ export class QueryLogin extends BaseQuery {
|
|||||||
{ key: 'refreshToken', data },
|
{ key: 'refreshToken', data },
|
||||||
{
|
{
|
||||||
afterResponse: async (response, ctx) => {
|
afterResponse: async (response, ctx) => {
|
||||||
setBaseResponse(response);
|
|
||||||
return response as any;
|
return response as any;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -183,11 +252,11 @@ export class QueryLogin extends BaseQuery {
|
|||||||
if (response?.code === 401) {
|
if (response?.code === 401) {
|
||||||
const hasRefreshToken = await that.cacheStore.getRefreshToken();
|
const hasRefreshToken = await that.cacheStore.getRefreshToken();
|
||||||
if (hasRefreshToken) {
|
if (hasRefreshToken) {
|
||||||
const res = await that.queryRefreshToken(hasRefreshToken);
|
const res = await that.queryRefreshToken({ refreshToken: hasRefreshToken });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const { accessToken, refreshToken } = res?.data || {};
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
that.storage.setItem('token', accessToken || '');
|
that.storage.setItem('token', accessToken || '');
|
||||||
await that.beforeSetLoginUser({ accessToken, refreshToken, check401: false });
|
await that.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn, check401: false });
|
||||||
if (refetch && ctx && ctx.req && ctx.req.url && ctx.fetch) {
|
if (refetch && ctx && ctx.req && ctx.req.url && ctx.fetch) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||||
const url = ctx.req?.url;
|
const url = ctx.req?.url;
|
||||||
@@ -198,7 +267,6 @@ export class QueryLogin extends BaseQuery {
|
|||||||
body: body,
|
body: body,
|
||||||
headers: { ...headers, Authorization: `Bearer ${accessToken}` },
|
headers: { ...headers, Authorization: `Bearer ${accessToken}` },
|
||||||
});
|
});
|
||||||
setBaseResponse(res);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -303,6 +371,23 @@ export class QueryLogin extends BaseQuery {
|
|||||||
const token = this.storage.getItem('token');
|
const token = this.storage.getItem('token');
|
||||||
return !!token;
|
return !!token;
|
||||||
}
|
}
|
||||||
|
async checkTokenValid(): Promise<null | string> {
|
||||||
|
const token = this.storage.getItem('token');
|
||||||
|
if (!token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const isExpired = await this.cacheStore.getIsExpired();
|
||||||
|
if (isExpired) {
|
||||||
|
console.log('token过期,正在刷新token', this.cacheStore.cacheData);
|
||||||
|
const res = await this.refreshLoginUser()
|
||||||
|
if (res.code === 200) {
|
||||||
|
// 刷新成功,返回新的token
|
||||||
|
return res.data?.accessToken || null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 检查本地用户列表
|
* 检查本地用户列表
|
||||||
* @returns
|
* @returns
|
||||||
@@ -311,6 +396,7 @@ export class QueryLogin extends BaseQuery {
|
|||||||
const token = this.storage.getItem('token');
|
const token = this.storage.getItem('token');
|
||||||
return token || '';
|
return token || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async beforeRequest(opts: any = {}) {
|
async beforeRequest(opts: any = {}) {
|
||||||
const token = this.storage.getItem('token');
|
const token = this.storage.getItem('token');
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -336,12 +422,17 @@ export class QueryLogin extends BaseQuery {
|
|||||||
const user = localUserList.find((userItem) => userItem.user!.username === username);
|
const user = localUserList.find((userItem) => userItem.user!.username === username);
|
||||||
if (user) {
|
if (user) {
|
||||||
this.storage.setItem('token', user.accessToken || '');
|
this.storage.setItem('token', user.accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken: user.accessToken, refreshToken: user.refreshToken });
|
await this.beforeSetLoginUser({
|
||||||
|
accessToken: user.accessToken,
|
||||||
|
refreshToken: user.refreshToken,
|
||||||
|
accessTokenExpiresIn: user.accessTokenExpiresIn
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
data: {
|
data: {
|
||||||
accessToken: user.accessToken,
|
accessToken: user.accessToken,
|
||||||
refreshToken: user.refreshToken,
|
refreshToken: user.refreshToken,
|
||||||
|
accessTokenExpiresIn: user.accessTokenExpiresIn,
|
||||||
},
|
},
|
||||||
success: true,
|
success: true,
|
||||||
message: '切换用户成功',
|
message: '切换用户成功',
|
||||||
@@ -350,9 +441,9 @@ export class QueryLogin extends BaseQuery {
|
|||||||
const res = await this.postSwitchUser(username);
|
const res = await this.postSwitchUser(username);
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const { accessToken, refreshToken } = res?.data || {};
|
const { accessToken, refreshToken, accessTokenExpiresIn } = res?.data || {};
|
||||||
this.storage.setItem('token', accessToken || '');
|
this.storage.setItem('token', accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken, refreshToken });
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -409,9 +500,9 @@ export class QueryLogin extends BaseQuery {
|
|||||||
loginToken: token,
|
loginToken: token,
|
||||||
});
|
});
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const accessToken = res.data?.accessToken;
|
const { accessTokenExpiresIn, accessToken, refreshToken } = res.data;
|
||||||
this.storage.setItem('token', accessToken || '');
|
this.storage.setItem('token', accessToken || '');
|
||||||
await this.beforeSetLoginUser({ accessToken, refreshToken: res.data?.refreshToken });
|
await this.beforeSetLoginUser({ accessToken, refreshToken, accessTokenExpiresIn });
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -421,7 +512,7 @@ export class QueryLogin extends BaseQuery {
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
||||||
import MD5 from 'crypto-js/md5.js';
|
// import MD5 from 'crypto-js/md5.js';
|
||||||
import jsonwebtoken from 'jsonwebtoken';
|
import jsonwebtoken from 'jsonwebtoken';
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
10
query/query-login/test/expire.ts
Normal file
10
query/query-login/test/expire.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const cacheData = {
|
||||||
|
accessTokenExpiresIn: 604800,
|
||||||
|
createdAt: 1771926793545
|
||||||
|
};
|
||||||
|
|
||||||
|
const expiresIn = cacheData.createdAt + cacheData.accessTokenExpiresIn * 1000;
|
||||||
|
console.log('expiresIn', expiresIn);
|
||||||
|
const now = Date.now();
|
||||||
|
console.log('now', now);
|
||||||
|
console.log('isExpired', now >= expiresIn);
|
||||||
154
query/query-mark/index.ts
Normal file
154
query/query-mark/index.ts
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
import { Query } from '@kevisual/query';
|
||||||
|
import type { Result, DataOpts } from '@kevisual/query/query';
|
||||||
|
|
||||||
|
export type SimpleObject = Record<string, any>;
|
||||||
|
export const markType = ['simple', 'md', 'mdx', 'wallnote', 'excalidraw', 'chat'] as const;
|
||||||
|
export type MarkType = (typeof markType)[number];
|
||||||
|
export type MarkData = {
|
||||||
|
nodes?: any[];
|
||||||
|
edges?: any[];
|
||||||
|
elements?: any[];
|
||||||
|
permission?: any;
|
||||||
|
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
export type Mark = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
markType: MarkType;
|
||||||
|
link: string;
|
||||||
|
data?: MarkData;
|
||||||
|
uid: string;
|
||||||
|
puid: string;
|
||||||
|
summary: string;
|
||||||
|
thumbnail?: string;
|
||||||
|
tags: string[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
export type ShowMarkPick = Pick<Mark, 'id' | 'title' | 'description' | 'summary' | 'link' | 'tags' | 'thumbnail' | 'updatedAt'>;
|
||||||
|
|
||||||
|
export type SearchOpts = {
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
search?: string;
|
||||||
|
sort?: string; // DESC, ASC
|
||||||
|
markType?: MarkType; // 类型
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QueryMarkOpts<T extends SimpleObject = SimpleObject> = {
|
||||||
|
query?: Query;
|
||||||
|
isBrowser?: boolean;
|
||||||
|
onLoad?: () => void;
|
||||||
|
} & T;
|
||||||
|
|
||||||
|
export type ResultMarkList = {
|
||||||
|
list: Mark[];
|
||||||
|
pagination: {
|
||||||
|
pageSize: number;
|
||||||
|
current: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type QueryMarkData = {
|
||||||
|
id?: string;
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
export type QueryMarkResult = {
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class QueryMarkBase<T extends SimpleObject = SimpleObject> {
|
||||||
|
query: Query;
|
||||||
|
isBrowser: boolean;
|
||||||
|
load?: boolean;
|
||||||
|
storage?: Storage;
|
||||||
|
onLoad?: () => void;
|
||||||
|
|
||||||
|
constructor(opts?: QueryMarkOpts<T>) {
|
||||||
|
this.query = opts?.query || new Query();
|
||||||
|
this.isBrowser = opts?.isBrowser ?? true;
|
||||||
|
this.init();
|
||||||
|
this.onLoad = opts?.onLoad;
|
||||||
|
}
|
||||||
|
setQuery(query: Query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
private async init() {
|
||||||
|
this.load = true;
|
||||||
|
this.onLoad?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
async post<T = Result<any>>(data: any, opts?: DataOpts): Promise<T> {
|
||||||
|
try {
|
||||||
|
return this.query.post({ path: 'mark', ...data }, opts) as Promise<T>;
|
||||||
|
} catch (error) {
|
||||||
|
console.log('error', error);
|
||||||
|
return {
|
||||||
|
code: 400,
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMarkList(search: SearchOpts, opts?: DataOpts) {
|
||||||
|
return this.post<Result<ResultMarkList>>({ key: 'list', ...search }, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMark(id: string, opts?: DataOpts) {
|
||||||
|
return this.post<Result<Mark>>({ key: 'get', id }, opts);
|
||||||
|
}
|
||||||
|
async getVersion(id: string, opts?: DataOpts) {
|
||||||
|
return this.post<Result<{ version: number; id: string }>>({ key: 'getVersion', id }, opts);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查版本
|
||||||
|
* 当需要更新时,返回true
|
||||||
|
* @param id
|
||||||
|
* @param version
|
||||||
|
* @param opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async checkVersion(id: string, version?: number, opts?: DataOpts) {
|
||||||
|
if (!version) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const res = await this.getVersion(id, opts);
|
||||||
|
if (res.code === 200) {
|
||||||
|
if (res.data!.version > version) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateMark(data: any, opts?: DataOpts) {
|
||||||
|
return this.post<Result<Mark>>({ key: 'update', data }, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteMark(id: string, opts?: DataOpts) {
|
||||||
|
return this.post<Result<Mark>>({ key: 'delete', id }, opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class QueryMark extends QueryMarkBase<SimpleObject> {
|
||||||
|
markType: string;
|
||||||
|
constructor(opts?: QueryMarkOpts & { markType?: MarkType }) {
|
||||||
|
super(opts);
|
||||||
|
this.markType = opts?.markType || 'simple';
|
||||||
|
}
|
||||||
|
async getMarkList(search?: SearchOpts, opts?: DataOpts) {
|
||||||
|
return this.post<Result<ResultMarkList>>({ key: 'list', ...search, markType: this.markType }, opts);
|
||||||
|
}
|
||||||
|
async updateMark(data: any, opts?: DataOpts) {
|
||||||
|
if (!data.id) {
|
||||||
|
data.markType = this.markType || 'simple';
|
||||||
|
}
|
||||||
|
return super.updateMark(data, opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,405 +1,3 @@
|
|||||||
import { Query, Result } from '@kevisual/query/query';
|
export * from './proxy.ts';
|
||||||
import { QueryRouterServer, Route } from '@kevisual/router/src/route.ts';
|
|
||||||
import { filter } from '@kevisual/js-filter'
|
|
||||||
import { EventEmitter } from 'eventemitter3';
|
|
||||||
|
|
||||||
export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const;
|
export { initApi } from './router-api-proxy.ts';
|
||||||
export type RouterViewItem = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
|
|
||||||
|
|
||||||
type RouteViewBase = {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
enabled?: boolean;
|
|
||||||
}
|
|
||||||
export type RouterViewApi = {
|
|
||||||
type: 'api',
|
|
||||||
api: {
|
|
||||||
url: string,
|
|
||||||
// 已初始化的query实例,不需要编辑配置
|
|
||||||
query?: Query
|
|
||||||
}
|
|
||||||
} & RouteViewBase;
|
|
||||||
|
|
||||||
export type RouterViewContext = {
|
|
||||||
type: 'context',
|
|
||||||
context: {
|
|
||||||
key: string,
|
|
||||||
// 从context中获取router,不需要编辑配置
|
|
||||||
router?: QueryRouterServer
|
|
||||||
}
|
|
||||||
} & RouteViewBase;
|
|
||||||
export type RouterViewWorker = {
|
|
||||||
type: 'worker',
|
|
||||||
worker: {
|
|
||||||
type: 'Worker' | 'SharedWorker' | 'serviceWorker',
|
|
||||||
url: string,
|
|
||||||
// 已初始化的worker实例,不需要编辑配置
|
|
||||||
worker?: Worker | SharedWorker | ServiceWorker,
|
|
||||||
/**
|
|
||||||
* worker选项
|
|
||||||
* default: { type: 'module' }
|
|
||||||
*/
|
|
||||||
workerOptions?: {
|
|
||||||
type: 'module' | 'classic'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} & RouteViewBase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注入 js 的url地址,使用importScripts加载
|
|
||||||
*/
|
|
||||||
export type RouteViewPage = {
|
|
||||||
type: 'page',
|
|
||||||
page: {
|
|
||||||
url: string,
|
|
||||||
}
|
|
||||||
} & RouteViewBase;
|
|
||||||
|
|
||||||
export type RouterViewQuery = {
|
|
||||||
id: string,
|
|
||||||
query: string,
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
export type RouterViewData = {
|
|
||||||
data: { items: RouterViewItem[]; }
|
|
||||||
views: RouterViewQuery[];
|
|
||||||
viewId?: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class QueryProxy {
|
|
||||||
router: QueryRouterServer;
|
|
||||||
token?: string;
|
|
||||||
routerViewItems: RouterViewItem[];
|
|
||||||
views: RouterViewQuery[];
|
|
||||||
emitter: EventEmitter;
|
|
||||||
constructor(opts?: { router?: QueryRouterServer, token?: string, routerViewData?: RouterViewData }) {
|
|
||||||
this.router = opts?.router || new QueryRouterServer();
|
|
||||||
this.token = opts?.token || this.getDefulatToken();
|
|
||||||
this.routerViewItems = opts?.routerViewData?.data?.items || [];
|
|
||||||
this.views = opts?.routerViewData?.views || [];
|
|
||||||
this.initRouterViewQuery();
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
}
|
|
||||||
getDefulatToken() {
|
|
||||||
try {
|
|
||||||
if (typeof window !== 'undefined' && typeof window.localStorage !== 'undefined') {
|
|
||||||
return localStorage.getItem('token') || undefined;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async initRouterViewQuery() {
|
|
||||||
this.routerViewItems = this.routerViewItems.map(item => {
|
|
||||||
if (item.type === 'api' && item.api?.url) {
|
|
||||||
const url = item.api.url;
|
|
||||||
if (item?.api?.query) return item;
|
|
||||||
item['api'] = { url: url, query: new Query({ url: url }) };
|
|
||||||
}
|
|
||||||
if (item.type === 'worker' && item.worker?.url) {
|
|
||||||
let viewItem = item as RouterViewWorker;
|
|
||||||
if (!item.worker?.workerOptions?.type) {
|
|
||||||
item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' };
|
|
||||||
}
|
|
||||||
if (item.worker.worker) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined;
|
|
||||||
if (item.worker.type === 'SharedWorker') {
|
|
||||||
worker = new SharedWorker(item.worker.url, item.worker.workerOptions);
|
|
||||||
worker.port.start();
|
|
||||||
} else if (viewItem.worker.type === 'serviceWorker') {
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
|
|
||||||
console.debug('注册serviceWorker成功 ', registration.scope);
|
|
||||||
}, function (err) {
|
|
||||||
console.debug('注册 serviceWorker 失败: ', err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.warn('当前浏览器不支持serviceWorker');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
worker = new Worker(viewItem.worker.url, item.worker.workerOptions);
|
|
||||||
}
|
|
||||||
viewItem['worker']['worker'] = worker;
|
|
||||||
}
|
|
||||||
if (item.type === 'context' && item.context?.key) {
|
|
||||||
if (item.context?.router) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
const context = globalThis['context'] || {}
|
|
||||||
const router = context[item.context.key] as QueryRouterServer;
|
|
||||||
if (router) {
|
|
||||||
item['context']['router'] = router;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}).filter(item => {
|
|
||||||
const enabled = item.enabled ?? true;
|
|
||||||
return enabled;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化路由
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async init() {
|
|
||||||
const routerViewItems = this.routerViewItems || [];
|
|
||||||
if (routerViewItems.length === 0) {
|
|
||||||
// 默认初始化api类型路由
|
|
||||||
await this.initApi();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const item of routerViewItems) {
|
|
||||||
switch (item.type) {
|
|
||||||
case 'api':
|
|
||||||
await this.initApi(item);
|
|
||||||
break;
|
|
||||||
case 'context':
|
|
||||||
await this.initContext(item);
|
|
||||||
break;
|
|
||||||
case 'worker':
|
|
||||||
await this.initWorker(item);
|
|
||||||
break;
|
|
||||||
case 'page':
|
|
||||||
await this.initPage(item);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.emitter.emit('initComplete');
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 监听初始化完成
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async listenInitComplete(): Promise<boolean> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
this.emitter.removeAllListeners('initComplete');
|
|
||||||
resolve(false);
|
|
||||||
}, 3 * 60000); // 3分钟超时
|
|
||||||
const func = () => {
|
|
||||||
clearTimeout(timer);
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
this.emitter.once('initComplete', func);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async initApi(item?: RouterViewApi) {
|
|
||||||
const that = this;
|
|
||||||
const query = item?.api?.query || new Query({ url: item?.api?.url || '/api/router' })
|
|
||||||
const res = await query.post<{ list: RouterItem[] }>({ path: "router", key: 'list', token: this.token });
|
|
||||||
if (res.code !== 200) {
|
|
||||||
console.error('Failed to init query proxy router:', res.message);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const _list = res.data?.list || []
|
|
||||||
for (const r of _list) {
|
|
||||||
if (r.path || r.id) {
|
|
||||||
console.debug(`注册路由: [${r.path}] ${r?.key}`, 'API');
|
|
||||||
let metadata = r.metadata || {};
|
|
||||||
metadata.viewItem = item;
|
|
||||||
this.router.route({
|
|
||||||
path: r.path,
|
|
||||||
key: r.key || '',
|
|
||||||
id: r.id,
|
|
||||||
description: r.description,
|
|
||||||
metadata: metadata,
|
|
||||||
}).define(async (ctx) => {
|
|
||||||
const msg = { ...ctx.query };
|
|
||||||
if (msg.token === undefined && that.token !== undefined) {
|
|
||||||
msg.token = that.token;
|
|
||||||
}
|
|
||||||
const res = await query.post<any>({ path: r.path, key: r.key, ...msg });
|
|
||||||
ctx.forward(res)
|
|
||||||
}).addTo(that.router);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async initContext(item?: RouterViewContext) {
|
|
||||||
// @ts-ignore
|
|
||||||
const context = globalThis['context'] || {}
|
|
||||||
const router = item?.context?.router || context[item?.context?.key] as QueryRouterServer;
|
|
||||||
if (!router) {
|
|
||||||
console.warn(`未发现Context router ${item?.context?.key}`);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const routes = router.getList();
|
|
||||||
for (const r of routes) {
|
|
||||||
console.debug(`注册路由: [${r.path}] ${r?.key}`, 'Context');
|
|
||||||
let metadata = r.metadata || {};
|
|
||||||
metadata.viewItem = item;
|
|
||||||
this.router.route({
|
|
||||||
path: r.path,
|
|
||||||
key: r.key || '',
|
|
||||||
id: r.id,
|
|
||||||
description: r.description,
|
|
||||||
metadata: metadata,
|
|
||||||
}).define(async (ctx) => {
|
|
||||||
const res = await router.run({ path: r.path, key: r.key, ...ctx.query });
|
|
||||||
ctx.forward(res)
|
|
||||||
}).addTo(this.router);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
generateId() {
|
|
||||||
return 'route_' + Math.random().toString(36).substring(2, 9);
|
|
||||||
}
|
|
||||||
async initWorker(item?: RouterViewWorker) {
|
|
||||||
const that = this;
|
|
||||||
if (!item?.worker?.url) {
|
|
||||||
console.warn('Worker URL not provided');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const viewItem = item.worker;
|
|
||||||
const worker = viewItem?.worker;
|
|
||||||
if (!worker) {
|
|
||||||
console.warn('Worker not initialized');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const callResponse = (e: MessageEvent) => {
|
|
||||||
const msg = e.data;
|
|
||||||
if (msg.requestId) {
|
|
||||||
const requestId = msg.requestId;
|
|
||||||
that.emitter.emit(requestId, msg);
|
|
||||||
} else {
|
|
||||||
that.router.run(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (item.worker.type === 'SharedWorker') {
|
|
||||||
const port = (worker as SharedWorker).port;
|
|
||||||
port.onmessage = callResponse;
|
|
||||||
port.start();
|
|
||||||
} else if (item.worker.type === 'serviceWorker') {
|
|
||||||
navigator.serviceWorker.addEventListener('message', callResponse);
|
|
||||||
} else {
|
|
||||||
(worker as Worker).onmessage = callResponse;
|
|
||||||
}
|
|
||||||
const callWorker = async (msg: any, viewItem: RouterViewWorker['worker']): Promise<Result> => {
|
|
||||||
const requestId = this.generateId();
|
|
||||||
const worker = viewItem?.worker;
|
|
||||||
if (!worker) {
|
|
||||||
return { code: 500, message: 'Worker未初始化' };
|
|
||||||
}
|
|
||||||
let port: MessagePort | Worker | ServiceWorker;
|
|
||||||
if (viewItem.type === 'SharedWorker') {
|
|
||||||
port = (worker as SharedWorker).port;
|
|
||||||
} else {
|
|
||||||
port = worker as Worker | ServiceWorker;
|
|
||||||
}
|
|
||||||
port.postMessage({
|
|
||||||
...msg,
|
|
||||||
requestId: requestId,
|
|
||||||
})
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
that.emitter.removeAllListeners(requestId);
|
|
||||||
resolve({ code: 500, message: '请求超时' });
|
|
||||||
}, 3 * 60 * 1000); // 3分钟超时
|
|
||||||
that.emitter.once(requestId, (res: any) => {
|
|
||||||
clearTimeout(timer);
|
|
||||||
resolve(res);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await callWorker({
|
|
||||||
path: "router",
|
|
||||||
key: 'list',
|
|
||||||
token: this.token,
|
|
||||||
}, viewItem);
|
|
||||||
|
|
||||||
if (res.code !== 200) {
|
|
||||||
console.error('Failed to init query proxy router:', res.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const _list = res.data?.list || []
|
|
||||||
for (const r of _list) {
|
|
||||||
if (r.path || r.id) {
|
|
||||||
console.debug(`注册路由: [${r.path}] ${r?.key}`, 'API');
|
|
||||||
let metadata = r.metadata || {};
|
|
||||||
metadata.viewItem = item;
|
|
||||||
this.router.route({
|
|
||||||
path: r.path,
|
|
||||||
key: r.key || '',
|
|
||||||
id: r.id,
|
|
||||||
description: r.description,
|
|
||||||
metadata: metadata,
|
|
||||||
}).define(async (ctx) => {
|
|
||||||
const msg = { ...ctx.query };
|
|
||||||
if (msg.token === undefined && that.token !== undefined) {
|
|
||||||
msg.token = that.token;
|
|
||||||
}
|
|
||||||
const res = await callWorker({ path: r.path, key: r.key, ...msg }, viewItem);
|
|
||||||
ctx.forward(res)
|
|
||||||
}).addTo(that.router);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async initPage(item?: RouteViewPage) {
|
|
||||||
if (!item?.page?.url) {
|
|
||||||
console.warn('Page地址未提供');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const url = item.page.url;
|
|
||||||
try {
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
await import(url).then((module) => { }).catch((err) => {
|
|
||||||
console.error('引入Page脚本失败:', url, err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('引入Page脚本失败:', url, e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 列出路由
|
|
||||||
* @param filter
|
|
||||||
* @param query WHERE metadata.tags CONTAINS 'premium'
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async listRoutes(filterFn?: (item: Route) => boolean, opts?: { viewId?: string, query?: string }) {
|
|
||||||
let query = opts?.query;
|
|
||||||
if (opts?.viewId) {
|
|
||||||
const view = this.views.find(v => v.id === opts.viewId);
|
|
||||||
if (view) {
|
|
||||||
query = view.query;
|
|
||||||
}
|
|
||||||
} if (opts?.query) {
|
|
||||||
query = opts.query;
|
|
||||||
}
|
|
||||||
const routes = this.router.routes.filter(filterFn || (() => true));
|
|
||||||
if (query) {
|
|
||||||
return filter(routes, query);
|
|
||||||
}
|
|
||||||
return routes;
|
|
||||||
}
|
|
||||||
async getViewQuery(viewId: string) {
|
|
||||||
const view = this.views.find(v => v.id === viewId);
|
|
||||||
if (view) {
|
|
||||||
return view.query;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 运行路由
|
|
||||||
* @param msg
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async run(msg: { id?: string, path?: string, key?: string }) {
|
|
||||||
return await this.router.run(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouterItem = {
|
|
||||||
id?: string;
|
|
||||||
path?: string;
|
|
||||||
key?: string;
|
|
||||||
description?: string;
|
|
||||||
middleware?: string[];
|
|
||||||
metadata?: Record<string, any>;
|
|
||||||
}
|
|
||||||
514
query/query-proxy/proxy.ts
Normal file
514
query/query-proxy/proxy.ts
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
import { QueryClient as Query, Result } from '@kevisual/query';
|
||||||
|
import { QueryRouterServer, type App, type Route, fromJSONSchema, toJSONSchema } from '@kevisual/router/browser';
|
||||||
|
import { filter } from '@kevisual/js-filter'
|
||||||
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
import { initApi } from './router-api-proxy.ts';
|
||||||
|
import Fuse from 'fuse.js';
|
||||||
|
import { cloneDeep } from 'es-toolkit';
|
||||||
|
|
||||||
|
export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const;
|
||||||
|
export type RouterViewItemInfo = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
|
||||||
|
export type RouterViewItem<T = {}> = RouterViewItemInfo & T;
|
||||||
|
|
||||||
|
type RouteViewBase = {
|
||||||
|
/**
|
||||||
|
* _id 用于纯本地存储标识
|
||||||
|
*/
|
||||||
|
_id?: string;
|
||||||
|
id?: string;
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
/**
|
||||||
|
* 响应数据
|
||||||
|
*/
|
||||||
|
response?: any;
|
||||||
|
/**
|
||||||
|
* 默认动作配置
|
||||||
|
*/
|
||||||
|
action?: { path?: string; key?: string; id?: string; payload?: any;[key: string]: any };
|
||||||
|
/**
|
||||||
|
* 本地状态,loading、active、error等
|
||||||
|
*/
|
||||||
|
routerStatus?: 'loading' | 'active' | 'inactive' | 'error';
|
||||||
|
}
|
||||||
|
export type RouterViewApi = {
|
||||||
|
type: 'api',
|
||||||
|
api: {
|
||||||
|
url: string,
|
||||||
|
// 已初始化的query实例,不需要编辑配置
|
||||||
|
query?: Query
|
||||||
|
}
|
||||||
|
} & RouteViewBase;
|
||||||
|
|
||||||
|
export type RouterViewContext = {
|
||||||
|
type: 'context',
|
||||||
|
context: {
|
||||||
|
key: string,
|
||||||
|
// 从context中获取router,不需要编辑配置
|
||||||
|
router?: QueryRouterServer
|
||||||
|
}
|
||||||
|
} & RouteViewBase;
|
||||||
|
export type RouterViewWorker = {
|
||||||
|
type: 'worker',
|
||||||
|
worker: {
|
||||||
|
type: 'Worker' | 'SharedWorker' | 'serviceWorker',
|
||||||
|
url: string,
|
||||||
|
// 已初始化的worker实例,不需要编辑配置
|
||||||
|
worker?: Worker | SharedWorker | ServiceWorker,
|
||||||
|
/**
|
||||||
|
* worker选项
|
||||||
|
* default: { type: 'module' }
|
||||||
|
*/
|
||||||
|
workerOptions?: {
|
||||||
|
type: 'module' | 'classic'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} & RouteViewBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去掉不需要保存的服务器的数据
|
||||||
|
* @param item
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const pickRouterViewData = (item: RouterViewItem) => {
|
||||||
|
const { action, response, _id, ...rest } = cloneDeep(item);
|
||||||
|
if (rest.type === 'api') {
|
||||||
|
if (rest.api) {
|
||||||
|
delete rest.api.query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rest.type === 'worker') {
|
||||||
|
if (rest.worker) {
|
||||||
|
delete rest.worker.worker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rest.type === 'context') {
|
||||||
|
if (rest.context) {
|
||||||
|
delete rest.context.router;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete rest.routerStatus;
|
||||||
|
return rest
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 注入 js 的url地址,使用 importScripts 加载
|
||||||
|
*/
|
||||||
|
export type RouteViewPage = {
|
||||||
|
type: 'page',
|
||||||
|
page: {
|
||||||
|
url: string,
|
||||||
|
}
|
||||||
|
} & RouteViewBase;
|
||||||
|
|
||||||
|
export type RouterViewQuery = {
|
||||||
|
id: string,
|
||||||
|
query: string,
|
||||||
|
title: string,
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 后端存储结构
|
||||||
|
*/
|
||||||
|
export type RouterViewData = {
|
||||||
|
data: { items: RouterViewItem[]; }
|
||||||
|
views: RouterViewQuery[];
|
||||||
|
viewId?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryProxy {
|
||||||
|
router: QueryRouterServer;
|
||||||
|
token?: string;
|
||||||
|
routerViewItems: RouterViewItem[];
|
||||||
|
views: RouterViewQuery[];
|
||||||
|
emitter: EventEmitter;
|
||||||
|
constructor(opts?: { router?: QueryRouterServer, token?: string, routerViewData?: RouterViewData }) {
|
||||||
|
this.router = opts?.router || new QueryRouterServer();
|
||||||
|
this.token = opts?.token || this.getDefulatToken();
|
||||||
|
this.routerViewItems = opts?.routerViewData?.data?.items || [];
|
||||||
|
this.views = opts?.routerViewData?.views || [];
|
||||||
|
this.initRouterViewQuery();
|
||||||
|
this.emitter = new EventEmitter();
|
||||||
|
}
|
||||||
|
private getDefulatToken() {
|
||||||
|
try {
|
||||||
|
if (typeof window !== 'undefined' && typeof window.localStorage !== 'undefined') {
|
||||||
|
return localStorage.getItem('token') || undefined;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initRouterViewQuery() {
|
||||||
|
this.routerViewItems = this.routerViewItems.map(item => {
|
||||||
|
return this.initRouterView(item);
|
||||||
|
}).filter(item => {
|
||||||
|
const enabled = item.enabled ?? true;
|
||||||
|
return enabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private initRouterView(item: RouterViewItem) {
|
||||||
|
item.routerStatus = 'loading';
|
||||||
|
if (item.type === 'api' && item.api?.url) {
|
||||||
|
const url = item.api.url;
|
||||||
|
if (item?.api?.query) return item;
|
||||||
|
const query = new Query({ url: url });
|
||||||
|
item['api'] = { url: url, query: query };
|
||||||
|
}
|
||||||
|
if (item.type === 'worker' && item.worker?.url) {
|
||||||
|
let viewItem = item as RouterViewWorker;
|
||||||
|
if (!item.worker?.workerOptions?.type) {
|
||||||
|
item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' };
|
||||||
|
}
|
||||||
|
if (item.worker.worker) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined;
|
||||||
|
if (item.worker.type === 'SharedWorker') {
|
||||||
|
worker = new SharedWorker(item.worker.url, item.worker.workerOptions);
|
||||||
|
worker.port.start();
|
||||||
|
} else if (viewItem.worker.type === 'serviceWorker') {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
|
||||||
|
console.debug('注册serviceWorker成功 ', registration.scope);
|
||||||
|
}, function (err) {
|
||||||
|
console.debug('注册 serviceWorker 失败: ', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('当前浏览器不支持serviceWorker');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
worker = new Worker(viewItem.worker.url, item.worker.workerOptions);
|
||||||
|
}
|
||||||
|
viewItem['worker']['worker'] = worker;
|
||||||
|
}
|
||||||
|
if (item.type === 'context' && item.context?.key) {
|
||||||
|
if (item.context?.router) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
const context = globalThis['context'] || {}
|
||||||
|
const router = context[item.context.key] as QueryRouterServer;
|
||||||
|
if (router) {
|
||||||
|
item['context']['router'] = router;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化路由
|
||||||
|
* main
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async init() {
|
||||||
|
const routerViewItems = this.routerViewItems || [];
|
||||||
|
if (routerViewItems.length === 0) {
|
||||||
|
// 默认初始化api类型路由
|
||||||
|
await this.initApi();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const item of routerViewItems) {
|
||||||
|
switch (item.type) {
|
||||||
|
case 'api':
|
||||||
|
await this.initApi(item);
|
||||||
|
break;
|
||||||
|
case 'context':
|
||||||
|
await this.initContext(item);
|
||||||
|
break;
|
||||||
|
case 'worker':
|
||||||
|
await this.initWorker(item);
|
||||||
|
break;
|
||||||
|
case 'page':
|
||||||
|
await this.initPage(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.emitter.emit('initComplete');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 监听初始化完成
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async listenInitComplete(): Promise<boolean> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
this.emitter.removeAllListeners('initComplete');
|
||||||
|
resolve(false);
|
||||||
|
}, 3 * 60000); // 3分钟超时
|
||||||
|
const func = () => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
this.emitter.once('initComplete', func);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async initApi(item?: RouterViewApi) {
|
||||||
|
initApi({ item: item, router: this.router, token: this.token });
|
||||||
|
}
|
||||||
|
async initContext(item?: RouterViewContext) {
|
||||||
|
// @ts-ignore
|
||||||
|
const context = globalThis['context'] || {}
|
||||||
|
const router = item?.context?.router || context[item?.context?.key] as QueryRouterServer;
|
||||||
|
if (item) {
|
||||||
|
item.routerStatus = router ? 'active' : 'error';
|
||||||
|
}
|
||||||
|
if (!router) {
|
||||||
|
console.warn(`未发现Context router ${item?.context?.key}`);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const routes = router.getList();
|
||||||
|
// TODO: args
|
||||||
|
// const args = fromJSONSchema(r);
|
||||||
|
for (const r of routes) {
|
||||||
|
console.debug(`注册路由: [${r.path}] ${r?.key}`, 'Context');
|
||||||
|
let metadata = r.metadata || {};
|
||||||
|
metadata.viewItem = item;
|
||||||
|
metadata.source = 'query-proxy-context';
|
||||||
|
this.router.route({
|
||||||
|
path: r.path,
|
||||||
|
key: r.key || '',
|
||||||
|
id: r.id,
|
||||||
|
description: r.description,
|
||||||
|
metadata: metadata,
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const res = await router.run({ path: r.path, key: r.key, ...ctx.query });
|
||||||
|
ctx.forward(res)
|
||||||
|
}).addTo(this.router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generateId() {
|
||||||
|
return 'route_' + Math.random().toString(36).substring(2, 9);
|
||||||
|
}
|
||||||
|
private async callWorker(msg: any, viewItem: RouterViewWorker['worker']): Promise<Result> {
|
||||||
|
const that = this;
|
||||||
|
const requestId = this.generateId();
|
||||||
|
const worker = viewItem?.worker;
|
||||||
|
if (!worker) {
|
||||||
|
return { code: 500, message: 'Worker未初始化' };
|
||||||
|
}
|
||||||
|
let port: MessagePort | Worker | ServiceWorker;
|
||||||
|
if (viewItem.type === 'SharedWorker') {
|
||||||
|
port = (worker as SharedWorker).port;
|
||||||
|
} else {
|
||||||
|
port = worker as Worker | ServiceWorker;
|
||||||
|
}
|
||||||
|
port.postMessage({
|
||||||
|
...msg,
|
||||||
|
requestId: requestId,
|
||||||
|
})
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
that.emitter.removeAllListeners(requestId);
|
||||||
|
resolve({ code: 500, message: '请求超时' });
|
||||||
|
}, 3 * 60 * 1000); // 3分钟超时
|
||||||
|
that.emitter.once(requestId, (res: any) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private async initWorker(item?: RouterViewWorker, initRoutes: boolean = true) {
|
||||||
|
const that = this;
|
||||||
|
if (!item?.worker?.url) {
|
||||||
|
console.warn('Worker URL not provided');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const viewItem = item.worker;
|
||||||
|
const worker = viewItem?.worker;
|
||||||
|
if (item) {
|
||||||
|
item.routerStatus = worker ? 'active' : 'error';
|
||||||
|
}
|
||||||
|
if (!worker) {
|
||||||
|
console.warn('Worker not initialized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const callResponse = (e: MessageEvent) => {
|
||||||
|
const msg = e.data;
|
||||||
|
if (msg.requestId) {
|
||||||
|
const requestId = msg.requestId;
|
||||||
|
that.emitter.emit(requestId, msg);
|
||||||
|
} else {
|
||||||
|
that.router.run(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.worker.type === 'SharedWorker') {
|
||||||
|
const port = (worker as SharedWorker).port;
|
||||||
|
port.onmessage = callResponse;
|
||||||
|
port.start();
|
||||||
|
} else if (item.worker.type === 'serviceWorker') {
|
||||||
|
navigator.serviceWorker.addEventListener('message', callResponse);
|
||||||
|
} else {
|
||||||
|
(worker as Worker).onmessage = callResponse;
|
||||||
|
}
|
||||||
|
if (!initRoutes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const callWorker = this.callWorker.bind(this);
|
||||||
|
|
||||||
|
const res = await callWorker({
|
||||||
|
path: "router",
|
||||||
|
key: 'list',
|
||||||
|
token: this.token,
|
||||||
|
}, viewItem);
|
||||||
|
|
||||||
|
if (res.code !== 200) {
|
||||||
|
console.error('Failed to init query proxy router:', res.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const _list = res.data?.list || []
|
||||||
|
for (const r of _list) {
|
||||||
|
if (r.path || r.id) {
|
||||||
|
console.debug(`注册路由: [${r.path}] ${r?.key}`, 'API');
|
||||||
|
let metadata = r.metadata || {};
|
||||||
|
metadata.viewItem = item;
|
||||||
|
metadata.source = 'query-proxy-worker';
|
||||||
|
this.router.route({
|
||||||
|
path: r.path,
|
||||||
|
key: r.key || '',
|
||||||
|
id: r.id,
|
||||||
|
description: r.description,
|
||||||
|
metadata: metadata,
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const msg = { ...ctx.query };
|
||||||
|
if (msg.token === undefined && that.token !== undefined) {
|
||||||
|
msg.token = that.token;
|
||||||
|
}
|
||||||
|
const res = await callWorker({ path: r.path, key: r.key, ...msg }, viewItem);
|
||||||
|
ctx.forward(res)
|
||||||
|
}).addTo(that.router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async initPage(item?: RouteViewPage) {
|
||||||
|
if (!item?.page?.url) {
|
||||||
|
console.warn('Page地址未提供');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const url = item.page.url;
|
||||||
|
try {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
await import(url)
|
||||||
|
if (item) {
|
||||||
|
item.routerStatus = 'active';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (item) {
|
||||||
|
item.routerStatus = 'error';
|
||||||
|
}
|
||||||
|
console.warn('引入Page脚本失败:', url, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private getQueryByViewId(viewId: string): string | undefined {
|
||||||
|
const view = this.views.find(v => v.id === viewId);
|
||||||
|
if (view) {
|
||||||
|
return view.query;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 列出路由
|
||||||
|
* @param filter
|
||||||
|
* @param query WHERE metadata.tags CONTAINS 'premium'
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async listRoutes(filterFn?: (item: Route) => boolean, opts?: { viewId?: string, query?: string }) {
|
||||||
|
let query = opts?.query;
|
||||||
|
if (opts?.viewId && !query) {
|
||||||
|
query = this.getQueryByViewId(opts.viewId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const routes = this.router.routes.filter(filterFn || (() => true));
|
||||||
|
if (query) {
|
||||||
|
if (query.toLocaleUpperCase().startsWith('WHERE')) {
|
||||||
|
return filter(routes, query);
|
||||||
|
} else {
|
||||||
|
const fuse = new Fuse(routes, {
|
||||||
|
keys: ['path', 'key', 'description'],
|
||||||
|
threshold: 0.4,
|
||||||
|
});
|
||||||
|
let findsRoutes = fuse.search(query);
|
||||||
|
const resultRoutes = findsRoutes.map(r => r.item);
|
||||||
|
return resultRoutes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
async getViewQuery(viewId: string) {
|
||||||
|
const view = this.views.find(v => v.id === viewId);
|
||||||
|
if (view) {
|
||||||
|
return view.query;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 运行路由
|
||||||
|
* @param msg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async run(msg: { id?: string, path?: string, key?: string }) {
|
||||||
|
return await this.router.run(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
async runByRouteView(routeView: RouterViewItem) {
|
||||||
|
if (routeView.response) {
|
||||||
|
return routeView;
|
||||||
|
}
|
||||||
|
const item = this.initRouterView(routeView);
|
||||||
|
if (item.type === 'api' && item.api?.url) {
|
||||||
|
const query = item.api.query!;
|
||||||
|
const res = await query.post<any>(item.action || {});
|
||||||
|
item.response = res;
|
||||||
|
return item;
|
||||||
|
} else if (item.type === 'api') {
|
||||||
|
item.response = { code: 500, message: 'API URL未配置' };
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (item.type === 'context' && item.context?.router) {
|
||||||
|
const router = item.context.router;
|
||||||
|
const res = await router.run(item.action || {});
|
||||||
|
item.response = res;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (item.type === 'page') {
|
||||||
|
await this.initPage(item);
|
||||||
|
const res = await this.router.run(item.action || {});
|
||||||
|
item.response = res;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (item.type === 'worker' && item.worker?.worker) {
|
||||||
|
await this.initWorker(item, false);
|
||||||
|
const callWorker = this.callWorker.bind(this);
|
||||||
|
const res = await callWorker(item.action || {}, item.worker);
|
||||||
|
item.response = res;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
item.response = { code: 500, message: '无法处理的路由类型', data: item };
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RouterItem = {
|
||||||
|
id?: string;
|
||||||
|
path?: string;
|
||||||
|
key?: string;
|
||||||
|
description?: string;
|
||||||
|
middleware?: string[];
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createViewData = (routerViewData: RouterViewItem | RouterViewItem[], data?: RouterViewData): RouterViewData => {
|
||||||
|
return {
|
||||||
|
views: [],
|
||||||
|
viewId: undefined,
|
||||||
|
data: {
|
||||||
|
items: Array.isArray(routerViewData) ? routerViewData : [routerViewData],
|
||||||
|
},
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
}
|
||||||
66
query/query-proxy/router-api-proxy.ts
Normal file
66
query/query-proxy/router-api-proxy.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { Query } from "@kevisual/query";
|
||||||
|
import { RouterViewApi, RouterItem } from "./proxy.ts";
|
||||||
|
import { type App, type QueryRouterServer } from "@kevisual/router";
|
||||||
|
import { filter } from "@kevisual/js-filter";
|
||||||
|
import { isBrowser } from "es-toolkit";
|
||||||
|
export const initApi = async (opts: {
|
||||||
|
item?: RouterViewApi,
|
||||||
|
router: QueryRouterServer | App,
|
||||||
|
token?: string,
|
||||||
|
/**
|
||||||
|
* WHERE path = 'auth' OR path = 'router' OR path = 'call'
|
||||||
|
*/
|
||||||
|
exclude?: string;
|
||||||
|
}) => {
|
||||||
|
const router = opts?.router! as QueryRouterServer;
|
||||||
|
const item = opts?.item;
|
||||||
|
const token = opts?.token;
|
||||||
|
const query = item?.api?.query || new Query({ url: item?.api?.url || '/api/router' })
|
||||||
|
const res = await query.post<{ list: RouterItem[] }>({ path: "router", key: 'list', token: token });
|
||||||
|
if (item) {
|
||||||
|
item.routerStatus = res?.code === 200 ? 'active' : 'error';
|
||||||
|
}
|
||||||
|
if (res.code !== 200) {
|
||||||
|
return {
|
||||||
|
code: res.code,
|
||||||
|
message: `初始化路由失败: ${res.message}, url: ${query.url}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _list = res.data?.list || []
|
||||||
|
if (opts?.exclude) {
|
||||||
|
if (opts?.exclude) {
|
||||||
|
let excludeList = filter(_list, opts.exclude);
|
||||||
|
const excludeIds = excludeList.map(i => i.id);
|
||||||
|
_list = _list.filter(i => !excludeIds.includes(i.id!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const _isBrowser = isBrowser();
|
||||||
|
for (const r of _list) {
|
||||||
|
if (r.path || r.id) {
|
||||||
|
_isBrowser && console.debug(`注册路由: [${r.path}] ${r?.key}`, 'API');
|
||||||
|
let metadata = r.metadata || {};
|
||||||
|
metadata.viewItem = item;
|
||||||
|
metadata.url = query.url;
|
||||||
|
metadata.source = 'query-proxy-api';
|
||||||
|
router.route({
|
||||||
|
path: r.path,
|
||||||
|
key: r.key || '',
|
||||||
|
id: r.id,
|
||||||
|
description: r.description,
|
||||||
|
metadata: metadata,
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const msg = { ...ctx.query };
|
||||||
|
if (msg.token === undefined && token !== undefined && !_isBrowser) {
|
||||||
|
msg.token = token;
|
||||||
|
}
|
||||||
|
const res = await query.post<any>({ path: r.path, key: r.key, ...msg });
|
||||||
|
ctx.forward(res)
|
||||||
|
}).addTo(router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
message: '初始化路由成功'
|
||||||
|
}
|
||||||
|
}
|
||||||
5
query/query-remote/index.ts
Normal file
5
query/query-remote/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { RemoteApp } from '@kevisual/remote-app'
|
||||||
|
|
||||||
|
export {
|
||||||
|
RemoteApp
|
||||||
|
}
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
import { adapter, DataOpts, Result } from '@kevisual/query';
|
import { adapter, DataOpts, Result } from '@kevisual/query';
|
||||||
|
import path from 'path-browserify-esm';
|
||||||
|
import { hashContent } from './utils';
|
||||||
|
|
||||||
|
type Process = {}
|
||||||
type QueryResourcesOptions = {
|
type QueryResourcesOptions = {
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
storage?: Storage;
|
storage?: Storage;
|
||||||
username?: string;
|
username?: string;
|
||||||
|
onProcess?: (opts?: Process) => void;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
export class QueryResources {
|
export class QueryResources {
|
||||||
prefix: string; // root/resources
|
prefix: string; // root/resources
|
||||||
storage: Storage;
|
storage: Storage;
|
||||||
|
onProcess?: (opts?: Process) => void;
|
||||||
constructor(opts: QueryResourcesOptions) {
|
constructor(opts: QueryResourcesOptions) {
|
||||||
if (opts.username) {
|
if (opts.username) {
|
||||||
this.prefix = `/${opts.username}/resources/`;
|
this.prefix = `/${opts.username}/resources/`;
|
||||||
@@ -16,10 +21,18 @@ export class QueryResources {
|
|||||||
this.prefix = opts.prefix || '';
|
this.prefix = opts.prefix || '';
|
||||||
}
|
}
|
||||||
this.storage = opts.storage || localStorage;
|
this.storage = opts.storage || localStorage;
|
||||||
|
this.onProcess = opts.onProcess || (() => { });
|
||||||
}
|
}
|
||||||
setUsername(username: string) {
|
setUsername(username: string) {
|
||||||
this.prefix = `/${username}/resources/`;
|
this.prefix = `/${username}/resources/`;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 设置prefix,类似 /{username}/resources/;
|
||||||
|
* @param prefix
|
||||||
|
*/
|
||||||
|
setPrefix(prefix: string) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
header(headers?: Record<string, string>, json = true): Record<string, string> {
|
header(headers?: Record<string, string>, json = true): Record<string, string> {
|
||||||
const token = this.storage.getItem('token');
|
const token = this.storage.getItem('token');
|
||||||
const _headers: Record<string, string> = {
|
const _headers: Record<string, string> = {
|
||||||
@@ -46,26 +59,262 @@ export class QueryResources {
|
|||||||
headers: this.header(opts?.headers),
|
headers: this.header(opts?.headers),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getUrl(prefix: string): string {
|
||||||
|
if (prefix.startsWith('http')) {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
return `${this.prefix}${prefix}`;
|
||||||
|
}
|
||||||
async getList(prefix: string, data?: { recursive?: boolean }, opts?: DataOpts): Promise<Result<any[]>> {
|
async getList(prefix: string, data?: { recursive?: boolean }, opts?: DataOpts): Promise<Result<any[]>> {
|
||||||
return this.get(data, {
|
return this.get(data, {
|
||||||
url: `${this.prefix}${prefix}`,
|
url: this.getUrl(prefix),
|
||||||
body: data,
|
body: data,
|
||||||
...opts,
|
...opts,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async fetchFile(filepath: string, opts?: DataOpts): Promise<Result<any>> {
|
async fetchFile(filepath: string, opts?: DataOpts): Promise<Result<any>> {
|
||||||
return fetch(`${this.prefix}${filepath}`, {
|
const url = this.getUrl(filepath);
|
||||||
method: 'GET',
|
return this.get({}, { url, method: 'GET', ...opts, headers: this.header(opts?.headers, false), isText: true });
|
||||||
headers: this.header(opts?.headers, false),
|
}
|
||||||
}).then(async (res) => {
|
async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts & { chunkSize?: number, maxSize?: number }): Promise<Result<any>> {
|
||||||
if (!res.ok) {
|
const pathname = this.getUrl(filepath);
|
||||||
return {
|
const filename = path.basename(pathname);
|
||||||
code: 500,
|
const type = getContentType(filename);
|
||||||
success: false,
|
const url = new URL(pathname, window.location.origin);
|
||||||
message: `Failed to fetch file: ${res.status} ${res.statusText}`,
|
const hashResult = hashContent(content);
|
||||||
} as Result<any>;
|
// Blob 类型时 hashContent 返回 Promise
|
||||||
|
const hash = hashResult instanceof Promise ? await hashResult : hashResult;
|
||||||
|
url.searchParams.set('hash', hash);
|
||||||
|
const { chunkSize, maxSize, ...restOpts } = opts || {};
|
||||||
|
// 判断是否需要分块上传(文件大于20MB)
|
||||||
|
const isBlob = content instanceof Blob;
|
||||||
|
const fileSize = isBlob ? content.size : new Blob([content]).size;
|
||||||
|
const CHUNK_THRESHOLD = maxSize ?? 20 * 1024 * 1024; // 20MB
|
||||||
|
|
||||||
|
if (fileSize > CHUNK_THRESHOLD && isBlob) {
|
||||||
|
// 使用分块上传
|
||||||
|
return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts });
|
||||||
|
}
|
||||||
|
this.onProcess?.({ type: 'uploadBegin', filename, size: fileSize, process: 0 });
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
if (isBlob) {
|
||||||
|
formData.append('file', content);
|
||||||
|
} else {
|
||||||
|
formData.append('file', new Blob([content], { type }));
|
||||||
|
}
|
||||||
|
const res = await adapter({
|
||||||
|
url: url.toString(),
|
||||||
|
isPostFile: true,
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
timeout: 5 * 60 * 1000, // 5分钟超时
|
||||||
|
...restOpts,
|
||||||
|
headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) },
|
||||||
|
params: {
|
||||||
|
hash: hash,
|
||||||
|
...restOpts?.params,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.onProcess?.({ type: 'uploadFinish', filename, size: fileSize, process: 100 });
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise<Result<any>> {
|
||||||
|
const pathname = this.getUrl(filepath);
|
||||||
|
const filename = path.basename(pathname);
|
||||||
|
const url = new URL(pathname, window.location.origin);
|
||||||
|
url.searchParams.set('hash', hash);
|
||||||
|
url.searchParams.set('chunk', '1');
|
||||||
|
// console.log(`url,`, url, hash);
|
||||||
|
// 预留 eventSource 支持(暂不处理)
|
||||||
|
// const createEventSource = opts?.createEventSource;
|
||||||
|
const { chunkSize: _chunkSize, ...restOpts } = opts || {};
|
||||||
|
const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB
|
||||||
|
const totalChunks = Math.ceil(file.size / chunkSize);
|
||||||
|
this.onProcess?.({ type: 'uploadBegin', filename, size: file.size, process: 0 });
|
||||||
|
|
||||||
|
for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
|
||||||
|
this.onProcess?.({ type: 'uploadChunkedFile', filename, size: file.size, process: 0, totalChunks, currentChunk: currentChunk + 1 });
|
||||||
|
const start = currentChunk * chunkSize;
|
||||||
|
const end = Math.min(start + chunkSize, file.size);
|
||||||
|
const chunkBlob = file.slice(start, end);
|
||||||
|
// 转换为 File 类型
|
||||||
|
const chunkFile = new File([chunkBlob], filename, { type: file.type || 'application/octet-stream' });
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', chunkFile, filename);
|
||||||
|
formData.append('chunkIndex', currentChunk.toString());
|
||||||
|
formData.append('totalChunks', totalChunks.toString());
|
||||||
|
console.log(`Uploading chunk ${currentChunk + 1}/${totalChunks}`, url.toString());
|
||||||
|
try {
|
||||||
|
const res = await adapter({
|
||||||
|
url: url.toString(),
|
||||||
|
isPostFile: true,
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
timeout: 5 * 60 * 1000, // 5分钟超时
|
||||||
|
...restOpts,
|
||||||
|
headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) },
|
||||||
|
params: {
|
||||||
|
hash: hash,
|
||||||
|
chunk: '1',
|
||||||
|
chunkIndex: currentChunk,
|
||||||
|
totalChunks,
|
||||||
|
...restOpts?.params,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.code !== 200) {
|
||||||
|
throw new Error(`Chunk 上传失败 code ${res!.code}, 错误信息是: ${res!.message}`);
|
||||||
|
}
|
||||||
|
console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
|
||||||
|
this.onProcess?.({ type: 'uploadChunkedFile', filename, size: file.size, process: Math.round(((currentChunk + 1) / totalChunks) * 100), totalChunks, currentChunk: currentChunk + 1 });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error);
|
||||||
|
return { code: 500, message: `分块上传失败: ${(error as Error).message}` };
|
||||||
}
|
}
|
||||||
return { code: 200, data: await res.text(), success: true } as Result<any>;
|
}
|
||||||
|
this.onProcess?.({ type: 'uploadFinish', filename, size: file.size, process: 100 });
|
||||||
|
return { code: 200, message: '上传成功' };
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 移除 prefix,获取相对路径
|
||||||
|
* @param filepath
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getRelativePath(filepath: string): string {
|
||||||
|
if (filepath.startsWith(this.prefix)) {
|
||||||
|
return filepath.slice(this.prefix.length);
|
||||||
|
}
|
||||||
|
return filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStat(filepath: string, opts?: DataOpts): Promise<Result<Stat>> {
|
||||||
|
const url = this.getUrl(filepath);
|
||||||
|
return adapter({
|
||||||
|
url,
|
||||||
|
params: {
|
||||||
|
stat: '1',
|
||||||
|
},
|
||||||
|
method: 'GET' as any,
|
||||||
|
headers: this.header(opts?.headers),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @deprecated use getStat instead
|
||||||
|
* @param filepath
|
||||||
|
* @param opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async getState(filepath: string, opts?: DataOpts): Promise<Result<Stat>> {
|
||||||
|
return this.getStat(filepath, opts);
|
||||||
|
}
|
||||||
|
async createFolder(folderpath: string, opts?: DataOpts): Promise<Result<any>> {
|
||||||
|
const filepath = folderpath.endsWith('/') ? `${folderpath}keep.txt` : `${folderpath}/keep.txt`;
|
||||||
|
return this.uploadFile(filepath, '文件夹占位,其他文件不存在,文件夹不存在,如果有其他文件夹,删除当前文件夹占位文件即可', opts);
|
||||||
|
}
|
||||||
|
async rename(oldpath: string, newpath: string, opts?: DataOpts): Promise<Result<any>> {
|
||||||
|
const pathname = this.getUrl(oldpath);
|
||||||
|
const newName = this.getUrl(newpath);
|
||||||
|
const params = {
|
||||||
|
newName: newName,
|
||||||
|
};
|
||||||
|
const url = pathname
|
||||||
|
return adapter({
|
||||||
|
url,
|
||||||
|
method: 'PUT' as any,
|
||||||
|
headers: this.header(opts?.headers),
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async deleteFile(filepath: string, opts?: DataOpts): Promise<Result<any>> {
|
||||||
|
const url = this.getUrl(filepath);
|
||||||
|
return adapter({
|
||||||
|
url,
|
||||||
|
method: 'DELETE' as any,
|
||||||
|
headers: this.header(opts?.headers),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getContentType = (filename: string): string => {
|
||||||
|
const ext = path.extname(filename);
|
||||||
|
let type = 'text/plain';
|
||||||
|
|
||||||
|
switch (ext) {
|
||||||
|
case '':
|
||||||
|
type = 'application/octet-stream';
|
||||||
|
break;
|
||||||
|
case '.json':
|
||||||
|
type = 'application/json';
|
||||||
|
break;
|
||||||
|
case '.txt':
|
||||||
|
type = 'text/plain';
|
||||||
|
break;
|
||||||
|
case '.csv':
|
||||||
|
type = 'text/csv';
|
||||||
|
break;
|
||||||
|
case '.md':
|
||||||
|
type = 'text/markdown';
|
||||||
|
break;
|
||||||
|
case '.html':
|
||||||
|
case '.htm':
|
||||||
|
type = 'text/html';
|
||||||
|
break;
|
||||||
|
case '.xml':
|
||||||
|
type = 'application/xml';
|
||||||
|
break;
|
||||||
|
case '.js':
|
||||||
|
type = 'application/javascript';
|
||||||
|
break;
|
||||||
|
case '.css':
|
||||||
|
type = 'text/css';
|
||||||
|
break;
|
||||||
|
case '.ts':
|
||||||
|
type = 'application/typescript';
|
||||||
|
break;
|
||||||
|
case '.pdf':
|
||||||
|
type = 'application/pdf';
|
||||||
|
break;
|
||||||
|
case '.zip':
|
||||||
|
type = 'application/zip';
|
||||||
|
break;
|
||||||
|
case '.docx':
|
||||||
|
type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
||||||
|
break;
|
||||||
|
case '.xlsx':
|
||||||
|
type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||||
|
break;
|
||||||
|
case '.mp3':
|
||||||
|
type = 'audio/mpeg';
|
||||||
|
break;
|
||||||
|
case '.mp4':
|
||||||
|
type = 'video/mp4';
|
||||||
|
break;
|
||||||
|
case '.png':
|
||||||
|
case '.jpg':
|
||||||
|
case '.jpeg':
|
||||||
|
case '.gif':
|
||||||
|
case '.webp':
|
||||||
|
type = `image/${ext.slice(1)}`;
|
||||||
|
break;
|
||||||
|
case '.svg':
|
||||||
|
type = 'image/svg+xml';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Stat = {
|
||||||
|
"standardHeaders": any,
|
||||||
|
"size": string,
|
||||||
|
"etag": string,
|
||||||
|
"lastModified": string,
|
||||||
|
"metaData": {
|
||||||
|
"app-source": string,
|
||||||
|
"cache-control": string,
|
||||||
|
"content-type": string,
|
||||||
|
"share"?: string
|
||||||
|
},
|
||||||
|
"versionId": null
|
||||||
|
}
|
||||||
|
|||||||
31
query/query-resources/utils.ts
Normal file
31
query/query-resources/utils.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import SparkMD5 from 'spark-md5';
|
||||||
|
|
||||||
|
export const hashContent = (str: string | Blob | Buffer): Promise<string> | string => {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
return SparkMD5.hash(str);
|
||||||
|
} else if (str instanceof Blob) {
|
||||||
|
return hashBlob(str);
|
||||||
|
} else if (Buffer.isBuffer(str)) {
|
||||||
|
return SparkMD5.hash(str.toString());
|
||||||
|
}
|
||||||
|
console.error('hashContent error: input must be a string, Blob, or Buffer');
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 直接计算整个 Blob 的 MD5
|
||||||
|
export const hashBlob = (blob: Blob): Promise<string> => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const spark = new SparkMD5.ArrayBuffer();
|
||||||
|
spark.append(await blob.arrayBuffer());
|
||||||
|
resolve(spark.end());
|
||||||
|
} catch (error) {
|
||||||
|
console.error('hashBlob error', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hashFile = (file: File): Promise<string> => {
|
||||||
|
return hashBlob(file);
|
||||||
|
};
|
||||||
1
query/query-secret/index.ts
Normal file
1
query/query-secret/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-secret.ts'
|
||||||
1
query/query-shop/index.ts
Normal file
1
query/query-shop/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-shop.ts'
|
||||||
1
query/query-upload/index.ts
Normal file
1
query/query-upload/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './query-upload-browser.ts';
|
||||||
1
query/utils/index.ts
Normal file
1
query/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './random.ts';
|
||||||
44
query/utils/random.ts
Normal file
44
query/utils/random.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
import { createId } from '@paralleldrive/cuid2';
|
||||||
|
|
||||||
|
export const letter = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
export const number = '0123456789';
|
||||||
|
const alphanumeric = `${letter}${number}`;
|
||||||
|
export const alphanumericWithDash = `${alphanumeric}-`;
|
||||||
|
|
||||||
|
export const cuid2 = createId;
|
||||||
|
/**
|
||||||
|
* 创建一个随机的字母字符串
|
||||||
|
*/
|
||||||
|
export const uuid = customAlphabet(letter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个随机的 id,包含字母和数字
|
||||||
|
*/
|
||||||
|
export const nanoid = customAlphabet(alphanumeric, 16);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个随机的 id,包含字母、数字和短横线
|
||||||
|
*/
|
||||||
|
export const nanoidWithDash = customAlphabet(alphanumericWithDash, 16);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个随机的 id,以字母开头的字符串
|
||||||
|
* @param number
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const randomId = (number: number) => {
|
||||||
|
const _letter = uuid(1);
|
||||||
|
return `${_letter}${nanoid(number)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个随机的字母字符串
|
||||||
|
* @param number
|
||||||
|
* @param opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const randomLetter = (number: number = 8, opts?: { before?: string; after?: string }) => {
|
||||||
|
const { before = '', after = '' } = opts || {};
|
||||||
|
return `${before}${uuid(number)}${after}`;
|
||||||
|
};
|
||||||
37
src/scripts/get-query-list.ts
Normal file
37
src/scripts/get-query-list.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import glob from 'fast-glob';
|
||||||
|
|
||||||
|
const lists = glob.sync('query/*/index.ts', {
|
||||||
|
absolute: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const queryList = lists.map((filePath) => {
|
||||||
|
const segments = filePath.split('/');
|
||||||
|
const queryName = segments[segments.length - 2];
|
||||||
|
return {
|
||||||
|
name: queryName,
|
||||||
|
pkgs: `"./${queryName}": "./dist/${queryName}.js",`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log('Query List:', queryList);
|
||||||
|
|
||||||
|
const pkgs = queryList.map(q => q.pkgs).join('\n');
|
||||||
|
console.log('Package Entries:\n\r', pkgs);
|
||||||
|
|
||||||
|
const storeLists = glob.sync('store/*/index.ts', {
|
||||||
|
absolute: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const storeList = storeLists.map((filePath) => {
|
||||||
|
const segments = filePath.split('/');
|
||||||
|
const storeName = segments[segments.length - 2];
|
||||||
|
return {
|
||||||
|
name: storeName,
|
||||||
|
pkgs: `"./${storeName}": "./dist/${storeName}.js",`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log('Store List:', storeList);
|
||||||
|
|
||||||
|
const storePkgs = storeList.map(s => s.pkgs).join('\n');
|
||||||
|
console.log('Store Entries:\n\r', storePkgs);
|
||||||
66
store/store-auth/index.ts
Normal file
66
store/store-auth/index.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
'use strict';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
import { type QueryLoginBrowser } from '@/query/query-login/index.ts'
|
||||||
|
const queryLogin = useContextKey<QueryLoginBrowser>('queryLogin');
|
||||||
|
|
||||||
|
type Me = {
|
||||||
|
id?: string;
|
||||||
|
username?: string;
|
||||||
|
nickname?: string | null;
|
||||||
|
needChangePassword?: boolean;
|
||||||
|
role?: string;
|
||||||
|
description?: string | null;
|
||||||
|
type?: 'user' | 'org';
|
||||||
|
orgs?: string[];
|
||||||
|
avatar?: string;
|
||||||
|
};
|
||||||
|
export type LayoutStore = {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
me: Me;
|
||||||
|
setMe: (me: Me) => void;
|
||||||
|
getMe: () => Promise<void>;
|
||||||
|
openUser: boolean;
|
||||||
|
setOpenUser: (openUser: boolean) => void;
|
||||||
|
switchOrg: (username?: string, type?: 'user' | 'org') => Promise<void>;
|
||||||
|
isAdmin: boolean;
|
||||||
|
setIsAdmin: (isAdmin: boolean) => void;
|
||||||
|
checkHasOrg: () => boolean;
|
||||||
|
};
|
||||||
|
export const useLayoutStore = create<LayoutStore>((set, get) => ({
|
||||||
|
open: false,
|
||||||
|
setOpen: (open) => set({ open }),
|
||||||
|
me: {},
|
||||||
|
setMe: (me) => set({ me }),
|
||||||
|
getMe: async () => {
|
||||||
|
const res = await queryLogin.getMe();
|
||||||
|
if (res.code === 200) {
|
||||||
|
set({ me: res.data });
|
||||||
|
set({ isAdmin: res.data.orgs?.includes('admin') });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openUser: false,
|
||||||
|
setOpenUser: (openUser) => set({ openUser }),
|
||||||
|
switchOrg: async (username?: string, type?: string) => {
|
||||||
|
const res = await queryLogin.switchUser(username || '');
|
||||||
|
if (res.code === 200) {
|
||||||
|
toast.success('Switch success');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
toast.error(res.message || 'Request failed');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isAdmin: false,
|
||||||
|
setIsAdmin: (isAdmin) => set({ isAdmin }),
|
||||||
|
checkHasOrg: () => {
|
||||||
|
const user = get().me || {};
|
||||||
|
if (!user.orgs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return user?.orgs?.length > 0;
|
||||||
|
},
|
||||||
|
}));
|
||||||
132
store/store-mark/index.ts
Normal file
132
store/store-mark/index.ts
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { type Result } from '@kevisual/query/query';
|
||||||
|
import { MarkType, Mark, QueryMark } from '@kevisual/api/query-mark';
|
||||||
|
import { uniqBy } from 'es-toolkit';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
import { type QueryLoginBrowser } from '@/query/query-login/index.ts'
|
||||||
|
const queryClient = useContextKey<QueryLoginBrowser>('queryLogin');
|
||||||
|
|
||||||
|
type ManagerStore = {
|
||||||
|
/** 当前选中的Mark */
|
||||||
|
currentMarkId: string;
|
||||||
|
setCurrentMarkId: (markId: string) => void;
|
||||||
|
markData?: Mark | undefined;
|
||||||
|
setMarkData: (mark?: Partial<Mark>) => void;
|
||||||
|
/** 获取Mark列表 */
|
||||||
|
getList: () => Promise<any>;
|
||||||
|
getMarkFromList: (markId: string) => Mark | undefined;
|
||||||
|
updateMark: (mark: Mark) => Promise<any>;
|
||||||
|
getMark: (markId: string) => Promise<Result<Mark>>;
|
||||||
|
deleteMark: (markId: string) => Promise<any>;
|
||||||
|
/** Mark列表 */
|
||||||
|
list: Mark[];
|
||||||
|
setList: (list: Mark[]) => void;
|
||||||
|
pagination: {
|
||||||
|
current: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
setPagination: (pagination: { current: number; pageSize: number; total: number }) => void;
|
||||||
|
/** 搜索 */
|
||||||
|
search: string;
|
||||||
|
setSearch: (search: string) => void;
|
||||||
|
/** 初始化 */
|
||||||
|
init: (markType: MarkType) => Promise<void>;
|
||||||
|
queryMark?: QueryMark;
|
||||||
|
markType?: MarkType;
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
};
|
||||||
|
export const useMarkStore = create<ManagerStore>((set, get) => {
|
||||||
|
return {
|
||||||
|
currentMarkId: '',
|
||||||
|
setCurrentMarkId: (markId: string) => set(() => ({ currentMarkId: markId })),
|
||||||
|
open: false,
|
||||||
|
setOpen: (open: boolean) => set(() => ({ open })),
|
||||||
|
getList: async () => {
|
||||||
|
const queryMark = get().queryMark!;
|
||||||
|
const { search, pagination } = get();
|
||||||
|
const res = await queryMark.getMarkList({ page: pagination.current, pageSize: pagination.pageSize, search });
|
||||||
|
const oldList = get().list;
|
||||||
|
if (res.code === 200) {
|
||||||
|
const { pagination, list } = res.data || {};
|
||||||
|
const newList = [...oldList, ...list!];
|
||||||
|
const uniqueList = uniqBy(newList, (item) => item.id);
|
||||||
|
set(() => ({ list: uniqueList }));
|
||||||
|
set(() => ({ pagination: { current: pagination!.current, pageSize: pagination!.pageSize, total: pagination!.total } }));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getMarkFromList: (markId: string) => {
|
||||||
|
return get().list.find((item) => item.id === markId);
|
||||||
|
},
|
||||||
|
updateMark: async (mark: Mark) => {
|
||||||
|
const queryMark = get().queryMark!;
|
||||||
|
const res = await queryMark.updateMark(mark);
|
||||||
|
if (res.code === 200) {
|
||||||
|
set((state) => {
|
||||||
|
const oldList = state.list;
|
||||||
|
const resMark = res.data!;
|
||||||
|
const newList = oldList.map((item) => (item.id === mark.id ? mark : item));
|
||||||
|
if (!mark.id) {
|
||||||
|
newList.unshift(resMark);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
list: newList,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
getMark: async (markId: string) => {
|
||||||
|
const queryMark = get().queryMark!;
|
||||||
|
const res = await queryMark.getMark(markId);
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
list: [],
|
||||||
|
setList: (list: any[]) => set(() => ({ list })),
|
||||||
|
init: async (markType: MarkType = 'wallnote') => {
|
||||||
|
// await get().getList();
|
||||||
|
console.log('init', set, get);
|
||||||
|
const queryMark = new QueryMark({
|
||||||
|
query: queryClient as any,
|
||||||
|
markType,
|
||||||
|
});
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const pageSize = url.searchParams.get('pageSize') || '10';
|
||||||
|
set({ queryMark, markType, list: [], pagination: { current: 1, pageSize: parseInt(pageSize), total: 0 }, currentMarkId: '', markData: undefined });
|
||||||
|
setTimeout(async () => {
|
||||||
|
console.log('get', get);
|
||||||
|
get().getList();
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
deleteMark: async (markId: string) => {
|
||||||
|
const queryMark = get().queryMark!;
|
||||||
|
const res = await queryMark.deleteMark(markId);
|
||||||
|
const currentMarkId = get().currentMarkId;
|
||||||
|
if (res.code === 200) {
|
||||||
|
// get().getList();
|
||||||
|
set((state) => ({
|
||||||
|
list: state.list.filter((item) => item.id !== markId),
|
||||||
|
}));
|
||||||
|
if (currentMarkId === markId) {
|
||||||
|
set(() => ({ currentMarkId: '', markData: undefined }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
queryMark: undefined,
|
||||||
|
markType: 'simple',
|
||||||
|
markData: undefined,
|
||||||
|
setMarkData: (mark?: Partial<Mark>) => set(() => ({ markData: mark as Mark })),
|
||||||
|
pagination: {
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
setPagination: (pagination: { current: number; pageSize: number; total: number }) => set(() => ({ pagination })),
|
||||||
|
/** 搜索 */
|
||||||
|
search: '',
|
||||||
|
setSearch: (search: string) => set(() => ({ search, list: [], pagination: { current: 1, pageSize: 10, total: 0 } })),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
23
tsconfig.json
Normal file
23
tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"extends": "@kevisual/types/json/frontend.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"paths": {
|
||||||
|
"@/query*": [
|
||||||
|
"query/*"
|
||||||
|
],
|
||||||
|
"@/store*": [
|
||||||
|
"store/*"
|
||||||
|
],
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src",
|
||||||
|
"query",
|
||||||
|
"store",
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user