diff --git a/package.json b/package.json index 11f97df..328ddaf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/api", - "version": "0.0.26", + "version": "0.0.27", "description": "", "main": "mod.ts", "scripts": { @@ -23,11 +23,11 @@ "devDependencies": { "@kevisual/cache": "^0.0.5", "@kevisual/query": "^0.0.38", - "@kevisual/router": "^0.0.60", - "@kevisual/types": "^0.0.11", + "@kevisual/router": "^0.0.62", + "@kevisual/types": "^0.0.12", "@kevisual/use-config": "^1.0.28", "@types/bun": "^1.3.6", - "@types/node": "^25.0.9", + "@types/node": "^25.0.10", "dotenv": "^17.2.3", "fast-glob": "^3.3.3" }, @@ -36,6 +36,7 @@ "@kevisual/load": "^0.0.6", "es-toolkit": "^1.44.0", "eventemitter3": "^5.0.4", + "fuse.js": "^7.1.0", "nanoid": "^5.1.6" }, "exports": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c2ad37c..172ccf0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: eventemitter3: specifier: ^5.0.4 version: 5.0.4 + fuse.js: + specifier: ^7.1.0 + version: 7.1.0 nanoid: specifier: ^5.1.6 version: 5.1.6 @@ -28,14 +31,14 @@ importers: specifier: ^0.0.5 version: 0.0.5 '@kevisual/query': - specifier: ^0.0.36 - version: 0.0.36 + specifier: ^0.0.38 + version: 0.0.38 '@kevisual/router': - specifier: ^0.0.60 - version: 0.0.60 + specifier: ^0.0.62 + version: 0.0.62 '@kevisual/types': - specifier: ^0.0.11 - version: 0.0.11 + specifier: ^0.0.12 + version: 0.0.12 '@kevisual/use-config': specifier: ^1.0.28 version: 1.0.28(dotenv@17.2.3) @@ -43,8 +46,8 @@ importers: specifier: ^1.3.6 version: 1.3.6 '@types/node': - specifier: ^25.0.9 - version: 25.0.9 + specifier: ^25.0.10 + version: 25.0.10 dotenv: specifier: ^17.2.3 version: 17.2.3 @@ -86,20 +89,20 @@ packages: '@kevisual/query@0.0.18': resolution: {integrity: sha512-I2vHTu0I6AyD9PJyr+vxyp9jIJ6rd2EZqLVHTv/+zrVKVc2SS76Tg7aGNkmAFqqLSCB8kLLsmMGtSJU1Qb8VVg==} - '@kevisual/query@0.0.36': - resolution: {integrity: sha512-TnwA0yh9EmaJ3cfETwwMJs2oPkvwrHEKfR3+1afg1R/6oINA6JtcVy1Cvd37O4mFUaGs+RPtsqFyA0r2yaQxJg==} + '@kevisual/query@0.0.38': + resolution: {integrity: sha512-bfvbSodsZyMfwY+1T2SvDeOCKsT/AaIxlVe0+B1R/fNhlg2MDq2CP0L9HKiFkEm+OXrvXcYDMKPUituVUM5J6Q==} '@kevisual/router@0.0.20': resolution: {integrity: sha512-uSwDYWh+kvAu6i0m0SJVgcLR/CYz7WvIWGz0nSF8Vg6smJuAgI+laHR4ESO8Fbz+Xn8bPHuSwmM//HHLMLx2FA==} - '@kevisual/router@0.0.60': - resolution: {integrity: sha512-2v/ZzUstsaq+Uqo+tZX9ys5E+/2erPggCtljv9jTb3NA88ZdHsYUAsd5wUFvLtf9QucpJCzyWEt+InDV/98FKw==} + '@kevisual/router@0.0.62': + resolution: {integrity: sha512-kKQFYkJ/qemGAygGSKkM/TujvreoU9HxL7/2vx2RYDMRyRuZOYUuvrTF92XIffFnZHugFbs8uEt+Z8I11SrFUg==} '@kevisual/types@0.0.10': resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==} - '@kevisual/types@0.0.11': - resolution: {integrity: sha512-idNLDTEKVdNXZHFQq8PTN62nflh94kvGtx+v8YDcMxt0Zo+HWVZTFElm+dMQxAs/vn4wo8F2r3VwzWNX/vcqwQ==} + '@kevisual/types@0.0.12': + resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==} '@kevisual/use-config@1.0.28': resolution: {integrity: sha512-ngF+LDbjxpXWrZNmnShIKF/jPpAa+ezV+DcgoZIIzHlRnIjE+rr9sLkN/B7WJbiH9C/j1tQXOILY8ujBqILrow==} @@ -133,8 +136,8 @@ packages: '@types/node@22.15.27': resolution: {integrity: sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==} - '@types/node@25.0.9': - resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} + '@types/node@25.0.10': + resolution: {integrity: sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==} abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} @@ -225,6 +228,10 @@ packages: function-bind@1.1.2: 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: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -410,7 +417,7 @@ snapshots: - ws - zod - '@kevisual/query@0.0.36': + '@kevisual/query@0.0.38': dependencies: tslib: 2.8.1 @@ -419,13 +426,13 @@ snapshots: path-to-regexp: 8.2.0 selfsigned: 2.4.1 - '@kevisual/router@0.0.60': + '@kevisual/router@0.0.62': dependencies: hono: 4.11.4 '@kevisual/types@0.0.10': {} - '@kevisual/types@0.0.11': {} + '@kevisual/types@0.0.12': {} '@kevisual/use-config@1.0.28(dotenv@17.2.3)': dependencies: @@ -465,7 +472,7 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@25.0.9': + '@types/node@25.0.10': dependencies: undici-types: 7.16.0 @@ -485,7 +492,7 @@ snapshots: bun-types@1.3.6: dependencies: - '@types/node': 25.0.9 + '@types/node': 25.0.10 call-bind-apply-helpers@1.0.2: dependencies: @@ -559,6 +566,8 @@ snapshots: function-bind@1.1.2: {} + fuse.js@7.1.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 diff --git a/query/query-proxy/proxy.ts b/query/query-proxy/proxy.ts index 0e1546f..7d198e2 100644 --- a/query/query-proxy/proxy.ts +++ b/query/query-proxy/proxy.ts @@ -3,6 +3,7 @@ import { QueryRouterServer, App, Route } from '@kevisual/router'; import { filter } from '@kevisual/js-filter' import { EventEmitter } from 'eventemitter3'; import { initApi } from './router-api-proxy.ts'; +import Fuse from 'fuse.js'; export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const; export type RouterViewItemInfo = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage; @@ -395,7 +396,17 @@ export class QueryProxy { } const routes = this.router.routes.filter(filterFn || (() => true)); if (query) { - return filter(routes, 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; }