Compare commits
5 Commits
fda55061a0
...
2a0d508cf4
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a0d508cf4 | |||
| 3f8b9c2c4a | |||
| c97e246ba7 | |||
| 15fd2d3dc8 | |||
| 885abd8c46 |
@@ -30,4 +30,12 @@ await buildWithBun({
|
||||
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=="],
|
||||
}
|
||||
}
|
||||
13
package.json
13
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kevisual/api",
|
||||
"version": "0.0.52",
|
||||
"version": "0.0.58",
|
||||
"description": "",
|
||||
"main": "mod.ts",
|
||||
"scripts": {
|
||||
@@ -18,25 +18,25 @@
|
||||
"keywords": [],
|
||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||
"license": "MIT",
|
||||
"packageManager": "pnpm@10.30.0",
|
||||
"packageManager": "pnpm@10.30.1",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@kevisual/cache": "^0.0.5",
|
||||
"@kevisual/code-builder": "^0.0.6",
|
||||
"@kevisual/query": "^0.0.47",
|
||||
"@kevisual/query": "^0.0.49",
|
||||
"@kevisual/remote-app": "^0.0.4",
|
||||
"@kevisual/router": "^0.0.75",
|
||||
"@kevisual/router": "^0.0.83",
|
||||
"@kevisual/types": "^0.0.12",
|
||||
"@kevisual/use-config": "^1.0.30",
|
||||
"@types/bun": "^1.3.9",
|
||||
"@types/node": "^25.2.3",
|
||||
"@types/node": "^25.3.0",
|
||||
"@types/spark-md5": "^3.0.5",
|
||||
"dotenv": "^17.3.1",
|
||||
"fast-glob": "^3.3.3",
|
||||
"ws": "npm:@kevisual/ws"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kevisual/context": "^0.0.6",
|
||||
"@kevisual/context": "^0.0.8",
|
||||
"@kevisual/js-filter": "^0.0.5",
|
||||
"@kevisual/load": "^0.0.6",
|
||||
"@paralleldrive/cuid2": "^3.3.0",
|
||||
@@ -58,6 +58,7 @@
|
||||
"./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",
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface Cache {
|
||||
*/
|
||||
init?: () => Promise<any>;
|
||||
}
|
||||
type User = {
|
||||
export type User = {
|
||||
avatar?: string;
|
||||
description?: string;
|
||||
id?: string;
|
||||
@@ -38,7 +38,7 @@ type CacheLogin = {
|
||||
loginUsers: CacheLoginUser[];
|
||||
} & CacheLoginUser;
|
||||
|
||||
export type CacheStore<T = Cache> = {
|
||||
export type CacheStore<T extends Cache = Cache> = {
|
||||
name: string;
|
||||
/**
|
||||
* 缓存数据
|
||||
@@ -82,18 +82,19 @@ export type CacheStore<T = Cache> = {
|
||||
getValue(): Promise<CacheLogin>;
|
||||
setValue(value: CacheLogin): Promise<CacheLogin>;
|
||||
delValue(): Promise<void>;
|
||||
init(): Promise<any>;
|
||||
init(): Promise<CacheLogin>;
|
||||
getIsExpired(): Promise<boolean>;
|
||||
};
|
||||
|
||||
export type LoginCacheStoreOpts = {
|
||||
export type LoginCacheStoreOpts<T extends Cache = Cache> = {
|
||||
name: string;
|
||||
cache: Cache;
|
||||
cache: T;
|
||||
};
|
||||
export class LoginCacheStore implements CacheStore<any> {
|
||||
cache: Cache;
|
||||
export class LoginCacheStore<T extends Cache = Cache> implements CacheStore<T> {
|
||||
cache: T;
|
||||
name: string;
|
||||
cacheData: CacheLogin;
|
||||
constructor(opts: LoginCacheStoreOpts) {
|
||||
constructor(opts: LoginCacheStoreOpts<T>) {
|
||||
if (!opts.cache) {
|
||||
throw new Error('cache is required');
|
||||
}
|
||||
@@ -124,6 +125,13 @@ export class LoginCacheStore implements CacheStore<any> {
|
||||
*/
|
||||
async delValue() {
|
||||
await this.cache.del();
|
||||
this.cacheData = {
|
||||
loginUsers: [],
|
||||
user: undefined,
|
||||
id: undefined,
|
||||
accessToken: undefined,
|
||||
refreshToken: undefined,
|
||||
};
|
||||
}
|
||||
getValue(): Promise<CacheLogin> {
|
||||
return this.cache.get(this.name);
|
||||
@@ -132,12 +140,14 @@ export class LoginCacheStore implements CacheStore<any> {
|
||||
* 初始化,设置默认值
|
||||
*/
|
||||
async init() {
|
||||
const defaultData = {
|
||||
const defaultData: CacheLogin = {
|
||||
loginUsers: [],
|
||||
user: null,
|
||||
id: null,
|
||||
accessToken: null,
|
||||
refreshToken: null,
|
||||
user: undefined,
|
||||
id: undefined,
|
||||
accessToken: undefined,
|
||||
refreshToken: undefined,
|
||||
accessTokenExpiresIn: undefined,
|
||||
createdAt: undefined,
|
||||
};
|
||||
if (this.cache.init) {
|
||||
try {
|
||||
@@ -149,6 +159,7 @@ export class LoginCacheStore implements CacheStore<any> {
|
||||
} else {
|
||||
this.cacheData = (await this.getValue()) || defaultData;
|
||||
}
|
||||
return this.cacheData;
|
||||
}
|
||||
/**
|
||||
* 设置当前用户
|
||||
@@ -184,6 +195,18 @@ export class LoginCacheStore implements CacheStore<any> {
|
||||
const cacheData = this.cacheData;
|
||||
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() {
|
||||
const user = await this.getCurrentUser();
|
||||
@@ -195,6 +218,8 @@ export class LoginCacheStore implements CacheStore<any> {
|
||||
this.cacheData.id = undefined;
|
||||
this.cacheData.accessToken = undefined;
|
||||
this.cacheData.refreshToken = undefined;
|
||||
this.cacheData.accessTokenExpiresIn = undefined;
|
||||
this.cacheData.createdAt = undefined;
|
||||
await this.setValue(this.cacheData);
|
||||
}
|
||||
async clearAll() {
|
||||
@@ -203,6 +228,8 @@ export class LoginCacheStore implements CacheStore<any> {
|
||||
this.cacheData.id = undefined;
|
||||
this.cacheData.accessToken = undefined;
|
||||
this.cacheData.refreshToken = undefined;
|
||||
this.cacheData.accessTokenExpiresIn = undefined;
|
||||
this.cacheData.createdAt = undefined;
|
||||
await this.setValue(this.cacheData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ import { Cache } from './login-cache.ts';
|
||||
import { homedir } from 'node:os';
|
||||
import { join, dirname } from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { readFileSync, writeFileSync, accessSync } from 'node:fs';
|
||||
import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
|
||||
export const fileExists = async (
|
||||
import { readFileSync, writeFileSync, accessSync, unlinkSync, mkdirSync } from 'node:fs';
|
||||
export const fileExists = (
|
||||
filePath: string,
|
||||
{ createIfNotExists = true, isFile = true, isDir = false }: { createIfNotExists?: boolean; isFile?: boolean; isDir?: boolean } = {},
|
||||
) => {
|
||||
@@ -13,10 +12,10 @@ export const fileExists = async (
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (createIfNotExists && isDir) {
|
||||
await mkdir(filePath, { recursive: true });
|
||||
mkdirSync(filePath, { recursive: true });
|
||||
return true;
|
||||
} else if (createIfNotExists && isFile) {
|
||||
await mkdir(dirname(filePath), { recursive: true });
|
||||
mkdirSync(dirname(filePath), { recursive: true });
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -34,32 +33,50 @@ export const readConfigFile = (filePath: string) => {
|
||||
export const writeConfigFile = (filePath: string, data: any) => {
|
||||
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 configFile = join(configDir, 'config.json');
|
||||
const config = readConfigFile(configFile);
|
||||
const baseURL = config.baseURL || 'https://kevisual.cn';
|
||||
const hostname = new URL(baseURL).hostname;
|
||||
const _baseURL = baseURL || config.baseURL || 'https://kevisual.cn';
|
||||
const hostname = new URL(_baseURL).hostname;
|
||||
return hostname;
|
||||
};
|
||||
export class StorageNode implements Storage {
|
||||
cacheData: any;
|
||||
filePath: string;
|
||||
constructor() {
|
||||
filePath: string = '';
|
||||
hostname: string = '';
|
||||
constructor(opts?: { baseURL?: string, load?: boolean }) {
|
||||
this.cacheData = {};
|
||||
const configDir = join(homedir(), '.config', 'envision');
|
||||
const hostname = getHostName();
|
||||
this.filePath = join(configDir, 'config', `${hostname}-storage.json`);
|
||||
fileExists(this.filePath, { isFile: true });
|
||||
const hostname = getHostName(opts?.baseURL);
|
||||
this.setHostName(hostname, { load: opts?.load });
|
||||
}
|
||||
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;
|
||||
try {
|
||||
const data = await readConfigFile(filePath);
|
||||
const data = readConfigFile(filePath);
|
||||
this.cacheData = data;
|
||||
} catch (error) {
|
||||
this.cacheData = {};
|
||||
await writeFile(filePath, JSON.stringify(this.cacheData, null, 2));
|
||||
writeFileSync(filePath, JSON.stringify(this.cacheData, null, 2));
|
||||
}
|
||||
}
|
||||
get length() {
|
||||
@@ -70,15 +87,15 @@ export class StorageNode implements Storage {
|
||||
}
|
||||
setItem(key: string, value: any) {
|
||||
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) {
|
||||
delete this.cacheData[key];
|
||||
writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||
writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||
}
|
||||
clear() {
|
||||
this.cacheData = {};
|
||||
writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||
writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2));
|
||||
}
|
||||
key(index: number) {
|
||||
return Object.keys(this.cacheData)[index];
|
||||
@@ -86,10 +103,12 @@ export class StorageNode implements Storage {
|
||||
}
|
||||
export class LoginNodeCache implements Cache {
|
||||
filepath: string;
|
||||
|
||||
constructor(filepath?: string) {
|
||||
this.filepath = filepath || join(homedir(), '.config', 'envision', 'config', `${getHostName()}-login.json`);
|
||||
constructor(opts?: { baseURL?: string, load?: boolean }) {
|
||||
this.filepath = join(homedir(), '.config', 'envision', 'config', `${getHostName(opts?.baseURL)}-login.json`);
|
||||
fileExists(this.filepath, { isFile: true });
|
||||
if (opts?.load) {
|
||||
this.loadCache(this.filepath);
|
||||
}
|
||||
}
|
||||
async get(_key: string) {
|
||||
try {
|
||||
@@ -111,11 +130,11 @@ export class LoginNodeCache implements Cache {
|
||||
}
|
||||
}
|
||||
async del() {
|
||||
await unlink(this.filepath);
|
||||
unlinkSync(this.filepath);
|
||||
}
|
||||
async loadCache(filePath: string) {
|
||||
loadCache(filePath: string) {
|
||||
try {
|
||||
const data = await readFile(filePath, 'utf-8');
|
||||
const data = readFileSync(filePath, 'utf-8');
|
||||
const jsonData = JSON.parse(data);
|
||||
return jsonData;
|
||||
} catch (error) {
|
||||
@@ -126,7 +145,7 @@ export class LoginNodeCache implements Cache {
|
||||
return defaultData;
|
||||
}
|
||||
}
|
||||
async init() {
|
||||
return await this.loadCache(this.filepath);
|
||||
init() {
|
||||
return this.loadCache(this.filepath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { QueryLogin, QueryLoginOpts } from './query-login.ts';
|
||||
import { LoginNodeCache, StorageNode } from './login-node-cache.ts';
|
||||
type QueryLoginNodeOptsWithoutCache = Omit<QueryLoginOpts, 'cache'>;
|
||||
export const storage = new StorageNode();
|
||||
await storage.loadCache();
|
||||
export class QueryLoginNode extends QueryLogin {
|
||||
export { StorageNode }
|
||||
export const cache = new LoginNodeCache();
|
||||
export class QueryLoginNode extends QueryLogin<LoginNodeCache> {
|
||||
declare storage: StorageNode;
|
||||
constructor(opts: QueryLoginNodeOptsWithoutCache) {
|
||||
const baseURL = opts?.query?.baseURL;
|
||||
const storage = new StorageNode({ baseURL, load: true });
|
||||
const cache = new LoginNodeCache({ baseURL, load: true });
|
||||
super({
|
||||
...opts,
|
||||
isBrowser: false,
|
||||
storage,
|
||||
cache: new LoginNodeCache(),
|
||||
cache,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Query, BaseQuery } from '@kevisual/query';
|
||||
import type { Result, DataOpts } from '@kevisual/query/query';
|
||||
import { LoginCacheStore, CacheStore } from './login-cache.ts';
|
||||
import { LoginCacheStore, CacheStore, User } from './login-cache.ts';
|
||||
import { Cache } from './login-cache.ts';
|
||||
import { BaseLoad } from '@kevisual/load';
|
||||
export type QueryLoginOpts = {
|
||||
export type QueryLoginOpts<T extends Cache = Cache> = {
|
||||
query?: Query;
|
||||
isBrowser?: boolean;
|
||||
onLoad?: () => void;
|
||||
storage?: Storage;
|
||||
cache: Cache;
|
||||
cache: T;
|
||||
};
|
||||
export type QueryLoginData = {
|
||||
username?: string;
|
||||
@@ -20,25 +20,28 @@ export type QueryLoginResult = {
|
||||
refreshToken: string;
|
||||
};
|
||||
|
||||
export class QueryLogin extends BaseQuery {
|
||||
export class QueryLogin<T extends Cache = Cache> extends BaseQuery {
|
||||
/**
|
||||
* query login cache, 非实际操作, 一个cache的包裹模块
|
||||
*/
|
||||
cacheStore: CacheStore;
|
||||
cacheStore: CacheStore<T>;
|
||||
isBrowser: boolean;
|
||||
load?: boolean;
|
||||
storage: Storage;
|
||||
onLoad?: () => void;
|
||||
|
||||
constructor(opts?: QueryLoginOpts) {
|
||||
constructor(opts?: QueryLoginOpts<T>) {
|
||||
super({
|
||||
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.init();
|
||||
this.onLoad = opts?.onLoad;
|
||||
this.storage = opts?.storage || globalThis?.localStorage;
|
||||
if (!this.storage) {
|
||||
throw new Error('storage is required');
|
||||
}
|
||||
}
|
||||
setQuery(query: Query) {
|
||||
this.query = query;
|
||||
@@ -104,6 +107,26 @@ export class QueryLogin extends BaseQuery {
|
||||
}
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* 检测微信登录,登陆成功后,调用onSuccess,否则调用onError
|
||||
* @param param0
|
||||
@@ -125,7 +148,8 @@ export class QueryLogin extends BaseQuery {
|
||||
* 登陆成功,需要获取用户信息进行缓存
|
||||
* @param param0
|
||||
*/
|
||||
async beforeSetLoginUser({ accessToken, refreshToken, check401, accessTokenExpiresIn }: { accessTokenExpiresIn?: number, 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) {
|
||||
const resUser = await this.getMe(accessToken, check401);
|
||||
if (resUser.code === 200) {
|
||||
@@ -143,7 +167,26 @@ export class QueryLogin extends BaseQuery {
|
||||
console.error('登录失败');
|
||||
}
|
||||
}
|
||||
return resUser;
|
||||
}
|
||||
return {
|
||||
code: 400,
|
||||
message: '登录失败',
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 刷新登录用户,获取新的token,并更新用户信息
|
||||
* @param refreshToken 刷新token,如果不传,则从缓存中获取
|
||||
* @returns
|
||||
*/
|
||||
async refreshLoginUser(refreshToken?: string) {
|
||||
const res = await this.queryRefreshToken(refreshToken);
|
||||
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
|
||||
@@ -151,7 +194,7 @@ export class QueryLogin extends BaseQuery {
|
||||
* @returns
|
||||
*/
|
||||
async queryRefreshToken(refreshToken?: string) {
|
||||
const _refreshToken = refreshToken || this.cacheStore.getRefreshToken();
|
||||
const _refreshToken = refreshToken || (await this.cacheStore.getRefreshToken());
|
||||
let data = { refreshToken: _refreshToken };
|
||||
if (!_refreshToken) {
|
||||
await this.cacheStore.clearCurrentUser();
|
||||
@@ -302,6 +345,22 @@ export class QueryLogin extends BaseQuery {
|
||||
const token = this.storage.getItem('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) {
|
||||
const res = await this.refreshLoginUser()
|
||||
if (res.code === 200) {
|
||||
// 刷新成功,返回新的token
|
||||
return res.data?.accessToken || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
/**
|
||||
* 检查本地用户列表
|
||||
* @returns
|
||||
@@ -310,6 +369,7 @@ export class QueryLogin extends BaseQuery {
|
||||
const token = this.storage.getItem('token');
|
||||
return token || '';
|
||||
}
|
||||
|
||||
async beforeRequest(opts: any = {}) {
|
||||
const token = this.storage.getItem('token');
|
||||
if (token) {
|
||||
|
||||
Reference in New Issue
Block a user