chore: update package version and dependencies

- Bump version from 0.1.1 to 0.1.2 in package.json
- Update dependencies:
  - @kevisual/js-filter from ^0.0.5 to ^0.0.6
  - @opencode-ai/plugin from ^1.2.24 to ^1.2.26
  - @types/node from ^25.4.0 to ^25.5.0
  - hono from ^4.12.7 to ^4.12.8
  - Add crypto-js and es-toolkit as new dependencies
- Remove unused AddOpts import in src/app.ts
- Enhance commander.ts to support remote application connection
- Modify route.ts to use hashIdMd5Sync for ID generation
- Add hashIdMd5Sync function in utils/random.ts for deterministic ID generation
This commit is contained in:
xiongxiao
2026-03-15 04:59:42 +08:00
committed by cnb
parent e18233fdcb
commit 151586f98c
6 changed files with 227 additions and 166 deletions

View File

@@ -1,4 +1,4 @@
import { AddOpts, QueryRouter, QueryRouterServer, Route, RouteContext, RouteOpts } from './route.ts';
import { QueryRouterServer, Route, RouteContext, RouteOpts } from './route.ts';
import { ServerNode, ServerNodeOpts } from './server/server.ts';
import { HandleCtx } from './server/server-base.ts';
import { ServerType } from './server/server-type.ts';

View File

@@ -1,6 +1,6 @@
import { Command, program } from 'commander';
import { App, QueryRouterServer } from './app.ts';
import { RemoteApp } from '@kevisual/remote-app'
export const groupByPath = (routes: App['routes']) => {
return routes.reduce((acc, route) => {
const path = route.path || 'default';
@@ -66,8 +66,9 @@ export const parseDescription = (route: App['routes'][number]) => {
}
return desc;
}
export const createCommand = (opts: { app: App, program: Command }) => {
const { app, program } = opts;
export const createCommand = (opts: { app: any, program: Command }) => {
const { program } = opts;
const app = opts.app as App;
const routes = app.routes;
@@ -113,11 +114,61 @@ export const createCommand = (opts: { app: App, program: Command }) => {
}
}
export const parse = (opts: { app: QueryRouterServer, description?: string, parse?: boolean, program?: Command }) => {
const { app, description, parse = true, } = opts;
export const parse = async (opts: {
app: any,
description?: string,
parse?: boolean,
version?: string,
program?: Command,
remote?: {
token?: string,
username?: string,
id?: string,
}
}) => {
const { description, parse = true, version } = opts;
const app = opts.app as App;
const _program = opts.program || program;
_program.description(description || 'Router 命令行工具');
if (version) {
_program.version(version);
}
app.createRouteList();
app.route({
path: 'cli',
key: 'list'
}).define(async () => {
const routes = app.routes.map(route => {
return {
path: route.path,
key: route.key,
description: route?.metadata?.summary || route.description || '',
};
});
// 输出为表格格式
const table = routes.map(route => {
return `${route.path} ${route.key} - ${route.description}`;
}).join('\n');
console.log(table);
}).addTo(app, { overwrite: false })
createCommand({ app: app as App, program: _program });
if (opts.remote) {
const { token, username, id } = opts.remote;
const remoteApp = new RemoteApp({
token,
username,
id,
});
const isConnect = await remoteApp.isConnect();
if (isConnect) {
remoteApp.listenProxy();
console.log('已连接到远程应用,正在监听命令...');
}
return
}
if (parse) {
_program.parse(process.argv);
}

View File

@@ -2,7 +2,7 @@ import { CustomError, throwError, CustomErrorOptions } from './result/error.ts';
import { pick } from './utils/pick.ts';
import { listenProcess, MockProcess } from './utils/listen-process.ts';
import { z } from 'zod';
import { randomId } from './utils/random.ts';
import { hashIdMd5Sync, randomId } from './utils/random.ts';
import * as schema from './validator/schema.ts';
export type RouterContextT = { code?: number;[key: string]: any };
@@ -96,14 +96,6 @@ export type RouteOpts<U = {}, T = SimpleObject> = {
metadata?: T;
middleware?: RouteMiddleware[]; // middleware
type?: 'route' | 'middleware' | 'compound'; // compound表示这个 route 作为一个聚合体,没有实际的 run而是一个 router 的聚合列表
/**
* $#$ will be used to split path and key
*/
idUsePath?: boolean;
/**
* id 合并的分隔符,默认为 $#$
*/
delimiter?: string;
isDebug?: boolean;
};
export type DefineRouteOpts = Omit<RouteOpts, 'idUsePath' | 'nextRoute'>;
@@ -170,12 +162,9 @@ export class Route<M extends SimpleObject = SimpleObject, U extends SimpleObject
key = key.trim();
this.path = path;
this.key = key;
const pathKey = `${path}$$${key}`;
if (opts) {
this.id = opts.id || randomId(12, 'rand-');
if (!opts.id && opts.idUsePath) {
const delimiter = opts.delimiter ?? '$$';
this.id = path + delimiter + key;
}
this.id = opts.id || hashIdMd5Sync(pathKey);
this.run = opts.run as Run<BuildRouteContext<M, U>>;
this.nextRoute = opts.nextRoute;
this.description = opts.description;
@@ -186,7 +175,9 @@ export class Route<M extends SimpleObject = SimpleObject, U extends SimpleObject
this.path = opts.path || path;
} else {
this.middleware = [];
this.id = randomId(12, 'rand-');
}
if (!this.id) {
this.id = hashIdMd5Sync(pathKey);
}
this.isDebug = opts?.isDebug ?? false;
}

View File

@@ -1,8 +1,17 @@
import { customAlphabet } from 'nanoid';
import Md5 from 'crypto-js/md5.js';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 16);
export const randomId = (length: number = 8, affix: string = '') => {
return affix + nanoid(length);
}
export { nanoid };
export { nanoid };
/**
* 基于 MD5 的确定性 ID 生成 (同步版本)
* 浏览器和 Node.js 都支持
* 相同的 pathKey 永远返回相同的 16 位 ID
*/
export const hashIdMd5Sync = (pathKey: string): string => {
return Md5(pathKey).toString().substring(0, 16);
}