@kevisual/router 0.0.50 → 0.0.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/auto.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { loadTS, getMatchFiles } from './src/auto/load-ts.ts';
2
+ import { listenSocket } from './src/auto/listen-sock.ts';
3
+ import { Route, QueryRouter, QueryRouterServer } from './src/route.ts';
4
+
5
+ export { Route, QueryRouter, QueryRouterServer };
6
+
7
+ export const App = QueryRouterServer;
8
+
9
+ export { createSchema } from './src/validator/index.ts';
10
+ export type { Rule } from './src/validator/rule.ts';
11
+ export type { RouteContext, RouteOpts } from './src/route.ts';
12
+
13
+ export type { Run } from './src/route.ts';
14
+
15
+ export { CustomError } from './src/result/error.ts';
16
+
17
+ export { listenSocket, loadTS, getMatchFiles };
18
+
19
+ export { autoCall } from './src/auto/call-sock.ts';
@@ -297,6 +297,8 @@ declare class QueryRouter {
297
297
  emitter?: any;
298
298
  timeout?: number;
299
299
  getList?: boolean;
300
+ force?: boolean;
301
+ filter?: (route: Route) => boolean;
300
302
  }): Promise<void>;
301
303
  }
302
304
  type QueryRouterServerOpts = {
@@ -627,7 +627,7 @@ class QueryRouter {
627
627
  description: '列出当前应用下的所有的路由信息',
628
628
  run: async (ctx) => {
629
629
  const list = this.getList(filter);
630
- ctx.body = list;
630
+ ctx.body = { list };
631
631
  },
632
632
  });
633
633
  this.add(listRoute);
@@ -644,7 +644,7 @@ class QueryRouter {
644
644
  wait(params, opts) {
645
645
  const getList = opts?.getList ?? true;
646
646
  if (getList) {
647
- this.createRouteList();
647
+ this.createRouteList(opts?.force ?? false, opts?.filter);
648
648
  }
649
649
  return listenProcess({ app: this, params, ...opts });
650
650
  }
@@ -13469,14 +13469,132 @@ function requireSelfsigned () {
13469
13469
  }
13470
13470
  }
13471
13471
 
13472
- function getSigningAlgorithm(key) {
13473
- const hashAlg = getAlgorithmName(key);
13472
+ function getSigningAlgorithm(hashKey, keyType) {
13473
+ const hashAlg = getAlgorithmName(hashKey);
13474
+ if (keyType === 'ec') {
13475
+ return {
13476
+ name: "ECDSA",
13477
+ hash: hashAlg
13478
+ };
13479
+ }
13480
+ return {
13481
+ name: "RSASSA-PKCS1-v1_5",
13482
+ hash: hashAlg
13483
+ };
13484
+ }
13485
+
13486
+ function getKeyAlgorithm(options) {
13487
+ const keyType = options.keyType || 'rsa';
13488
+ const hashAlg = getAlgorithmName(options.algorithm || 'sha1');
13489
+
13490
+ if (keyType === 'ec') {
13491
+ const curve = options.curve || 'P-256';
13492
+ return {
13493
+ name: "ECDSA",
13494
+ namedCurve: curve
13495
+ };
13496
+ }
13497
+
13474
13498
  return {
13475
13499
  name: "RSASSA-PKCS1-v1_5",
13500
+ modulusLength: options.keySize || 2048,
13501
+ publicExponent: new Uint8Array([1, 0, 1]),
13476
13502
  hash: hashAlg
13477
13503
  };
13478
13504
  }
13479
13505
 
13506
+ // Build extensions array from options or use defaults
13507
+ // Supports the old node-forge extension format for backwards compatibility
13508
+ function buildExtensions(userExtensions, commonName) {
13509
+ if (!userExtensions || userExtensions.length === 0) {
13510
+ // Default extensions
13511
+ return [
13512
+ new BasicConstraintsExtension(false, undefined, true),
13513
+ new KeyUsagesExtension(KeyUsageFlags.digitalSignature | KeyUsageFlags.keyEncipherment, true),
13514
+ new ExtendedKeyUsageExtension([ExtendedKeyUsage.serverAuth, ExtendedKeyUsage.clientAuth], false),
13515
+ new SubjectAlternativeNameExtension([
13516
+ { type: 'dns', value: commonName },
13517
+ ...(commonName === 'localhost' ? [{ type: 'ip', value: '127.0.0.1' }] : [])
13518
+ ], false)
13519
+ ];
13520
+ }
13521
+
13522
+ // Convert user extensions from node-forge format to @peculiar/x509 format
13523
+ const extensions = [];
13524
+
13525
+ for (const ext of userExtensions) {
13526
+ const critical = ext.critical || false;
13527
+
13528
+ switch (ext.name) {
13529
+ case 'basicConstraints':
13530
+ extensions.push(new BasicConstraintsExtension(
13531
+ ext.cA || false,
13532
+ ext.pathLenConstraint,
13533
+ critical
13534
+ ));
13535
+ break;
13536
+
13537
+ case 'keyUsage':
13538
+ let flags = 0;
13539
+ if (ext.digitalSignature) flags |= KeyUsageFlags.digitalSignature;
13540
+ if (ext.nonRepudiation || ext.contentCommitment) flags |= KeyUsageFlags.nonRepudiation;
13541
+ if (ext.keyEncipherment) flags |= KeyUsageFlags.keyEncipherment;
13542
+ if (ext.dataEncipherment) flags |= KeyUsageFlags.dataEncipherment;
13543
+ if (ext.keyAgreement) flags |= KeyUsageFlags.keyAgreement;
13544
+ if (ext.keyCertSign) flags |= KeyUsageFlags.keyCertSign;
13545
+ if (ext.cRLSign) flags |= KeyUsageFlags.cRLSign;
13546
+ if (ext.encipherOnly) flags |= KeyUsageFlags.encipherOnly;
13547
+ if (ext.decipherOnly) flags |= KeyUsageFlags.decipherOnly;
13548
+ extensions.push(new KeyUsagesExtension(flags, critical));
13549
+ break;
13550
+
13551
+ case 'extKeyUsage':
13552
+ const usages = [];
13553
+ if (ext.serverAuth) usages.push(ExtendedKeyUsage.serverAuth);
13554
+ if (ext.clientAuth) usages.push(ExtendedKeyUsage.clientAuth);
13555
+ if (ext.codeSigning) usages.push(ExtendedKeyUsage.codeSigning);
13556
+ if (ext.emailProtection) usages.push(ExtendedKeyUsage.emailProtection);
13557
+ if (ext.timeStamping) usages.push(ExtendedKeyUsage.timeStamping);
13558
+ extensions.push(new ExtendedKeyUsageExtension(usages, critical));
13559
+ break;
13560
+
13561
+ case 'subjectAltName':
13562
+ const altNames = (ext.altNames || []).map(alt => {
13563
+ // node-forge type values:
13564
+ // 1 = email (rfc822Name)
13565
+ // 2 = DNS
13566
+ // 6 = URI
13567
+ // 7 = IP
13568
+ switch (alt.type) {
13569
+ case 1: // email
13570
+ return { type: 'email', value: alt.value };
13571
+ case 2: // DNS
13572
+ return { type: 'dns', value: alt.value };
13573
+ case 6: // URI
13574
+ return { type: 'url', value: alt.value };
13575
+ case 7: // IP
13576
+ return { type: 'ip', value: alt.ip || alt.value };
13577
+ default:
13578
+ // Try to infer type from properties
13579
+ if (alt.ip) return { type: 'ip', value: alt.ip };
13580
+ if (alt.dns) return { type: 'dns', value: alt.dns };
13581
+ if (alt.email) return { type: 'email', value: alt.email };
13582
+ if (alt.uri || alt.url) return { type: 'url', value: alt.uri || alt.url };
13583
+ return { type: 'dns', value: alt.value };
13584
+ }
13585
+ });
13586
+ extensions.push(new SubjectAlternativeNameExtension(altNames, critical));
13587
+ break;
13588
+
13589
+ default:
13590
+ // Skip unknown extensions with a warning
13591
+ console.warn(`Unknown extension "${ext.name}" ignored`);
13592
+ }
13593
+ }
13594
+
13595
+ return extensions;
13596
+ }
13597
+
13480
13598
  // Convert attributes from node-forge format to X509 name format
13481
13599
  function convertAttributes(attrs) {
13482
13600
  const nameMap = {
@@ -13495,50 +13613,67 @@ function requireSelfsigned () {
13495
13613
  }).join(', ');
13496
13614
  }
13497
13615
 
13616
+ // Map Node.js curve names to Web Crypto curve names
13617
+ function normalizeECCurve(curveName) {
13618
+ const curveMap = {
13619
+ 'prime256v1': 'P-256',
13620
+ 'secp384r1': 'P-384',
13621
+ 'secp521r1': 'P-521',
13622
+ 'P-256': 'P-256',
13623
+ 'P-384': 'P-384',
13624
+ 'P-521': 'P-521'
13625
+ };
13626
+ return curveMap[curveName] || curveName;
13627
+ }
13628
+
13629
+ // Get EC curve from key object
13630
+ function getECCurve(keyObject) {
13631
+ const details = keyObject.asymmetricKeyDetails;
13632
+ if (details && details.namedCurve) {
13633
+ return normalizeECCurve(details.namedCurve);
13634
+ }
13635
+ return 'P-256'; // default
13636
+ }
13637
+
13498
13638
  // Convert PEM key to CryptoKey
13499
- async function importPrivateKey(pemKey, algorithm) {
13500
- // Support both PKCS#8 and PKCS#1 (RSA) formats
13501
- const pkcs8Match = pemKey.match(/-----BEGIN PRIVATE KEY-----([\s\S]*?)-----END PRIVATE KEY-----/);
13502
- const rsaMatch = pemKey.match(/-----BEGIN RSA PRIVATE KEY-----([\s\S]*?)-----END RSA PRIVATE KEY-----/);
13503
-
13504
- if (pkcs8Match) {
13505
- const pemContents = pkcs8Match[1].replace(/\s/g, '');
13506
- const binaryDer = Buffer.from(pemContents, 'base64');
13507
- return await crypto.subtle.importKey(
13508
- 'pkcs8',
13509
- binaryDer,
13510
- {
13511
- name: 'RSASSA-PKCS1-v1_5',
13512
- hash: getAlgorithmName(algorithm),
13513
- },
13514
- true,
13515
- ['sign']
13516
- );
13517
- } else if (rsaMatch) {
13518
- // PKCS#1 RSA key - need to convert using Node.js crypto
13519
- const keyObject = nodeCrypto.createPrivateKey(pemKey);
13520
- const pkcs8Pem = keyObject.export({ type: 'pkcs8', format: 'pem' });
13521
- const pemContents = pkcs8Pem
13522
- .replace(/-----BEGIN PRIVATE KEY-----/, '')
13523
- .replace(/-----END PRIVATE KEY-----/, '')
13524
- .replace(/\s/g, '');
13525
- const binaryDer = Buffer.from(pemContents, 'base64');
13526
- return await crypto.subtle.importKey(
13527
- 'pkcs8',
13528
- binaryDer,
13529
- {
13530
- name: 'RSASSA-PKCS1-v1_5',
13531
- hash: getAlgorithmName(algorithm),
13532
- },
13533
- true,
13534
- ['sign']
13535
- );
13639
+ async function importPrivateKey(pemKey, algorithm, keyType) {
13640
+ // Auto-detect key type if not provided
13641
+ const keyObject = nodeCrypto.createPrivateKey(pemKey);
13642
+ const detectedKeyType = keyObject.asymmetricKeyType;
13643
+ const actualKeyType = keyType || detectedKeyType;
13644
+
13645
+ // Convert to PKCS#8 format
13646
+ const pkcs8Pem = keyObject.export({ type: 'pkcs8', format: 'pem' });
13647
+ const pemContents = pkcs8Pem
13648
+ .replace(/-----BEGIN PRIVATE KEY-----/, '')
13649
+ .replace(/-----END PRIVATE KEY-----/, '')
13650
+ .replace(/\s/g, '');
13651
+ const binaryDer = Buffer.from(pemContents, 'base64');
13652
+
13653
+ let importAlgorithm;
13654
+ if (actualKeyType === 'ec') {
13655
+ const curve = getECCurve(keyObject);
13656
+ importAlgorithm = {
13657
+ name: 'ECDSA',
13658
+ namedCurve: curve
13659
+ };
13536
13660
  } else {
13537
- throw new Error('Unsupported private key format. Expected PKCS#8 or PKCS#1 RSA key.');
13661
+ importAlgorithm = {
13662
+ name: 'RSASSA-PKCS1-v1_5',
13663
+ hash: getAlgorithmName(algorithm)
13664
+ };
13538
13665
  }
13666
+
13667
+ return await crypto.subtle.importKey(
13668
+ 'pkcs8',
13669
+ binaryDer,
13670
+ importAlgorithm,
13671
+ true,
13672
+ ['sign']
13673
+ );
13539
13674
  }
13540
13675
 
13541
- async function importPublicKey(pemKey, algorithm) {
13676
+ async function importPublicKey(pemKey, algorithm, keyType, curve) {
13542
13677
  const pemContents = pemKey
13543
13678
  .replace(/-----BEGIN PUBLIC KEY-----/, '')
13544
13679
  .replace(/-----END PUBLIC KEY-----/, '')
@@ -13546,13 +13681,23 @@ function requireSelfsigned () {
13546
13681
 
13547
13682
  const binaryDer = Buffer.from(pemContents, 'base64');
13548
13683
 
13684
+ let importAlgorithm;
13685
+ if (keyType === 'ec') {
13686
+ importAlgorithm = {
13687
+ name: 'ECDSA',
13688
+ namedCurve: curve
13689
+ };
13690
+ } else {
13691
+ importAlgorithm = {
13692
+ name: 'RSASSA-PKCS1-v1_5',
13693
+ hash: getAlgorithmName(algorithm)
13694
+ };
13695
+ }
13696
+
13549
13697
  return await crypto.subtle.importKey(
13550
13698
  'spki',
13551
13699
  binaryDer,
13552
- {
13553
- name: 'RSASSA-PKCS1-v1_5',
13554
- hash: getAlgorithmName(algorithm),
13555
- },
13700
+ importAlgorithm,
13556
13701
  true,
13557
13702
  ['verify']
13558
13703
  );
@@ -13604,29 +13749,22 @@ function requireSelfsigned () {
13604
13749
  ];
13605
13750
 
13606
13751
  const subjectName = convertAttributes(attrs);
13607
- const signingAlg = getSigningAlgorithm(options.algorithm);
13752
+ const keyType = options.keyType || 'rsa';
13753
+ const signingAlg = getSigningAlgorithm(options.algorithm, keyType);
13608
13754
 
13609
13755
  // Extract common name for SAN extension
13610
13756
  const commonNameAttr = attrs.find(attr => attr.name === 'commonName' || attr.shortName === 'CN');
13611
13757
  const commonName = commonNameAttr ? commonNameAttr.value : 'localhost';
13612
13758
 
13613
13759
  // Build extensions array
13614
- const extensions = [
13615
- new BasicConstraintsExtension(false, undefined, true),
13616
- new KeyUsagesExtension(KeyUsageFlags.digitalSignature | KeyUsageFlags.keyEncipherment, true),
13617
- new ExtendedKeyUsageExtension([ExtendedKeyUsage.serverAuth, ExtendedKeyUsage.clientAuth], false),
13618
- new SubjectAlternativeNameExtension([
13619
- { type: 'dns', value: commonName },
13620
- ...(commonName === 'localhost' ? [{ type: 'ip', value: '127.0.0.1' }] : [])
13621
- ], false)
13622
- ];
13760
+ const extensions = buildExtensions(options.extensions, commonName);
13623
13761
 
13624
13762
  let cert;
13625
13763
 
13626
13764
  if (ca) {
13627
13765
  // Generate certificate signed by CA
13628
13766
  const caCert = new X509Certificate(ca.cert);
13629
- const caPrivateKey = await importPrivateKey(ca.key, options.algorithm || "sha256");
13767
+ const caPrivateKey = await importPrivateKey(ca.key, options.algorithm || "sha256", keyType);
13630
13768
 
13631
13769
  cert = await X509CertificateGenerator.create({
13632
13770
  serialNumber: serialHex,
@@ -13711,14 +13849,19 @@ function requireSelfsigned () {
13711
13849
  const clientKeySize = clientOpts.keySize || options.clientCertificateKeySize || 2048;
13712
13850
  const clientAlgorithm = clientOpts.algorithm || options.algorithm || "sha1";
13713
13851
  const clientCN = clientOpts.cn || options.clientCertificateCN || "John Doe jdoe123";
13852
+ // Client cert uses same key type and curve as main cert by default
13853
+ const clientKeyType = clientOpts.keyType || keyType;
13854
+ const clientCurve = clientOpts.curve || options.curve || 'P-256';
13855
+
13856
+ const clientKeyAlg = getKeyAlgorithm({
13857
+ keyType: clientKeyType,
13858
+ keySize: clientKeySize,
13859
+ algorithm: clientAlgorithm,
13860
+ curve: clientCurve
13861
+ });
13714
13862
 
13715
13863
  const clientKeyPair = await crypto.subtle.generateKey(
13716
- {
13717
- name: "RSASSA-PKCS1-v1_5",
13718
- modulusLength: clientKeySize,
13719
- publicExponent: new Uint8Array([1, 0, 1]),
13720
- hash: getAlgorithmName(clientAlgorithm),
13721
- },
13864
+ clientKeyAlg,
13722
13865
  true,
13723
13866
  ["sign", "verify"]
13724
13867
  );
@@ -13749,8 +13892,8 @@ function requireSelfsigned () {
13749
13892
  const clientSubjectName = convertAttributes(clientAttrs);
13750
13893
  const issuerName = convertAttributes(attrs);
13751
13894
 
13752
- // Signing algorithm for client cert (can differ from main cert)
13753
- const clientSigningAlg = getSigningAlgorithm(clientAlgorithm);
13895
+ // Signing algorithm for client cert - uses main key type since signed by root
13896
+ const clientSigningAlg = getSigningAlgorithm(clientAlgorithm, keyType);
13754
13897
 
13755
13898
  // Create client cert signed by root key
13756
13899
  const clientCertRaw = await X509CertificateGenerator.create({
@@ -13808,13 +13951,17 @@ function requireSelfsigned () {
13808
13951
  *
13809
13952
  * @param {CertificateField[]} attrs Attributes used for subject.
13810
13953
  * @param {object} options
13811
- * @param {number} [options.keySize=2048] the size for the private key in bits
13954
+ * @param {string} [options.keyType="rsa"] Key type: "rsa" or "ec" (elliptic curve)
13955
+ * @param {number} [options.keySize=2048] the size for the private key in bits (RSA only)
13956
+ * @param {string} [options.curve="P-256"] The elliptic curve to use: "P-256", "P-384", or "P-521" (EC only)
13812
13957
  * @param {object} [options.extensions] additional extensions for the certificate
13813
13958
  * @param {string} [options.algorithm="sha1"] The signature algorithm sha256, sha384, sha512 or sha1
13814
13959
  * @param {Date} [options.notBeforeDate=new Date()] The date before which the certificate should not be valid
13815
13960
  * @param {Date} [options.notAfterDate] The date after which the certificate should not be valid (default: notBeforeDate + 365 days)
13816
13961
  * @param {boolean|object} [options.clientCertificate=false] Generate client cert signed by the original key. Can be `true` for defaults or an options object.
13817
- * @param {number} [options.clientCertificate.keySize=2048] Key size for the client certificate in bits
13962
+ * @param {number} [options.clientCertificate.keySize=2048] Key size for the client certificate in bits (RSA only)
13963
+ * @param {string} [options.clientCertificate.keyType] Key type for client cert (defaults to main keyType)
13964
+ * @param {string} [options.clientCertificate.curve] Elliptic curve for client cert (EC only)
13818
13965
  * @param {string} [options.clientCertificate.algorithm] Signature algorithm for client cert (defaults to options.algorithm or "sha1")
13819
13966
  * @param {string} [options.clientCertificate.cn="John Doe jdoe123"] Client certificate's common name
13820
13967
  * @param {Date} [options.clientCertificate.notBeforeDate=new Date()] The date before which the client certificate should not be valid
@@ -13831,25 +13978,22 @@ function requireSelfsigned () {
13831
13978
  attrs = attrs || undefined;
13832
13979
  options = options || {};
13833
13980
 
13834
- const keySize = options.keySize || 2048;
13981
+ const keyType = options.keyType || 'rsa';
13982
+ const curve = options.curve || 'P-256';
13835
13983
 
13836
13984
  let keyPair;
13837
13985
 
13838
13986
  if (options.keyPair) {
13839
13987
  // Import existing key pair
13840
13988
  keyPair = {
13841
- privateKey: await importPrivateKey(options.keyPair.privateKey, options.algorithm || "sha1"),
13842
- publicKey: await importPublicKey(options.keyPair.publicKey, options.algorithm || "sha1")
13989
+ privateKey: await importPrivateKey(options.keyPair.privateKey, options.algorithm || "sha1", keyType),
13990
+ publicKey: await importPublicKey(options.keyPair.publicKey, options.algorithm || "sha1", keyType, curve)
13843
13991
  };
13844
13992
  } else {
13845
- // Generate new key pair
13993
+ // Generate new key pair using appropriate algorithm
13994
+ const keyAlg = getKeyAlgorithm(options);
13846
13995
  keyPair = await crypto.subtle.generateKey(
13847
- {
13848
- name: "RSASSA-PKCS1-v1_5",
13849
- modulusLength: keySize,
13850
- publicExponent: new Uint8Array([1, 0, 1]),
13851
- hash: getAlgorithmName(options.algorithm || "sha1"),
13852
- },
13996
+ keyAlg,
13853
13997
  true,
13854
13998
  ["sign", "verify"]
13855
13999
  );
package/dist/router.d.ts CHANGED
@@ -2,8 +2,7 @@ import * as http from 'node:http';
2
2
  import http__default, { IncomingMessage, ServerResponse } from 'node:http';
3
3
  import https from 'node:https';
4
4
  import http2 from 'node:http2';
5
- import EventEmitter from 'node:events';
6
- import { EventEmitter as EventEmitter$1 } from 'events';
5
+ import { EventEmitter } from 'eventemitter3';
7
6
  import { WebSocketServer } from 'ws';
8
7
  import { z } from 'zod';
9
8
  import { IncomingMessage as IncomingMessage$1, ServerResponse as ServerResponse$1 } from 'http';
@@ -303,6 +302,8 @@ declare class QueryRouter {
303
302
  emitter?: any;
304
303
  timeout?: number;
305
304
  getList?: boolean;
305
+ force?: boolean;
306
+ filter?: (route: Route) => boolean;
306
307
  }): Promise<void>;
307
308
  }
308
309
  type QueryRouterServerOpts = {
@@ -624,7 +625,7 @@ declare class ServerBase implements ServerType {
624
625
  _callback: any;
625
626
  cors: Cors$1;
626
627
  listeners: Listener[];
627
- emitter: EventEmitter$1<any>;
628
+ emitter: EventEmitter<string | symbol, any>;
628
629
  showConnected: boolean;
629
630
  constructor(opts?: ServerOpts);
630
631
  listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
@@ -652,6 +653,10 @@ declare class ServerBase implements ServerType {
652
653
  createCallback(): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
653
654
  on(listener: OnListener): void;
654
655
  onWebSocket({ ws, message, pathname, token, id }: OnWebSocketOptions): Promise<void>;
656
+ /**
657
+ * 根据emitter提醒关闭ws连接
658
+ * @param ws
659
+ */
655
660
  onWsClose(ws: WS): Promise<void>;
656
661
  sendConnected(ws: WS): Promise<void>;
657
662
  }
package/dist/router.js CHANGED
@@ -3,7 +3,7 @@ import require$$2 from 'node:http';
3
3
  import require$$1$1 from 'node:https';
4
4
  import http2 from 'node:http2';
5
5
  import url from 'node:url';
6
- import require$$0$3, { EventEmitter } from 'node:events';
6
+ import require$$0$3 from 'node:events';
7
7
  import require$$3 from 'node:net';
8
8
  import require$$4 from 'node:tls';
9
9
  import require$$0$2 from 'node:stream';
@@ -649,7 +649,7 @@ class QueryRouter {
649
649
  description: '列出当前应用下的所有的路由信息',
650
650
  run: async (ctx) => {
651
651
  const list = this.getList(filter);
652
- ctx.body = list;
652
+ ctx.body = { list };
653
653
  },
654
654
  });
655
655
  this.add(listRoute);
@@ -666,7 +666,7 @@ class QueryRouter {
666
666
  wait(params, opts) {
667
667
  const getList = opts?.getList ?? true;
668
668
  if (getList) {
669
- this.createRouteList();
669
+ this.createRouteList(opts?.force ?? false, opts?.filter);
670
670
  }
671
671
  return listenProcess({ app: this, params, ...opts });
672
672
  }
@@ -1174,6 +1174,360 @@ const parseIfJson = (input) => {
1174
1174
  return str;
1175
1175
  };
1176
1176
 
1177
+ function getDefaultExportFromCjs (x) {
1178
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1179
+ }
1180
+
1181
+ var eventemitter3 = {exports: {}};
1182
+
1183
+ var hasRequiredEventemitter3;
1184
+
1185
+ function requireEventemitter3 () {
1186
+ if (hasRequiredEventemitter3) return eventemitter3.exports;
1187
+ hasRequiredEventemitter3 = 1;
1188
+ (function (module) {
1189
+
1190
+ var has = Object.prototype.hasOwnProperty
1191
+ , prefix = '~';
1192
+
1193
+ /**
1194
+ * Constructor to create a storage for our `EE` objects.
1195
+ * An `Events` instance is a plain object whose properties are event names.
1196
+ *
1197
+ * @constructor
1198
+ * @private
1199
+ */
1200
+ function Events() {}
1201
+
1202
+ //
1203
+ // We try to not inherit from `Object.prototype`. In some engines creating an
1204
+ // instance in this way is faster than calling `Object.create(null)` directly.
1205
+ // If `Object.create(null)` is not supported we prefix the event names with a
1206
+ // character to make sure that the built-in object properties are not
1207
+ // overridden or used as an attack vector.
1208
+ //
1209
+ if (Object.create) {
1210
+ Events.prototype = Object.create(null);
1211
+
1212
+ //
1213
+ // This hack is needed because the `__proto__` property is still inherited in
1214
+ // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
1215
+ //
1216
+ if (!new Events().__proto__) prefix = false;
1217
+ }
1218
+
1219
+ /**
1220
+ * Representation of a single event listener.
1221
+ *
1222
+ * @param {Function} fn The listener function.
1223
+ * @param {*} context The context to invoke the listener with.
1224
+ * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
1225
+ * @constructor
1226
+ * @private
1227
+ */
1228
+ function EE(fn, context, once) {
1229
+ this.fn = fn;
1230
+ this.context = context;
1231
+ this.once = once || false;
1232
+ }
1233
+
1234
+ /**
1235
+ * Add a listener for a given event.
1236
+ *
1237
+ * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
1238
+ * @param {(String|Symbol)} event The event name.
1239
+ * @param {Function} fn The listener function.
1240
+ * @param {*} context The context to invoke the listener with.
1241
+ * @param {Boolean} once Specify if the listener is a one-time listener.
1242
+ * @returns {EventEmitter}
1243
+ * @private
1244
+ */
1245
+ function addListener(emitter, event, fn, context, once) {
1246
+ if (typeof fn !== 'function') {
1247
+ throw new TypeError('The listener must be a function');
1248
+ }
1249
+
1250
+ var listener = new EE(fn, context || emitter, once)
1251
+ , evt = prefix ? prefix + event : event;
1252
+
1253
+ if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
1254
+ else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
1255
+ else emitter._events[evt] = [emitter._events[evt], listener];
1256
+
1257
+ return emitter;
1258
+ }
1259
+
1260
+ /**
1261
+ * Clear event by name.
1262
+ *
1263
+ * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
1264
+ * @param {(String|Symbol)} evt The Event name.
1265
+ * @private
1266
+ */
1267
+ function clearEvent(emitter, evt) {
1268
+ if (--emitter._eventsCount === 0) emitter._events = new Events();
1269
+ else delete emitter._events[evt];
1270
+ }
1271
+
1272
+ /**
1273
+ * Minimal `EventEmitter` interface that is molded against the Node.js
1274
+ * `EventEmitter` interface.
1275
+ *
1276
+ * @constructor
1277
+ * @public
1278
+ */
1279
+ function EventEmitter() {
1280
+ this._events = new Events();
1281
+ this._eventsCount = 0;
1282
+ }
1283
+
1284
+ /**
1285
+ * Return an array listing the events for which the emitter has registered
1286
+ * listeners.
1287
+ *
1288
+ * @returns {Array}
1289
+ * @public
1290
+ */
1291
+ EventEmitter.prototype.eventNames = function eventNames() {
1292
+ var names = []
1293
+ , events
1294
+ , name;
1295
+
1296
+ if (this._eventsCount === 0) return names;
1297
+
1298
+ for (name in (events = this._events)) {
1299
+ if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
1300
+ }
1301
+
1302
+ if (Object.getOwnPropertySymbols) {
1303
+ return names.concat(Object.getOwnPropertySymbols(events));
1304
+ }
1305
+
1306
+ return names;
1307
+ };
1308
+
1309
+ /**
1310
+ * Return the listeners registered for a given event.
1311
+ *
1312
+ * @param {(String|Symbol)} event The event name.
1313
+ * @returns {Array} The registered listeners.
1314
+ * @public
1315
+ */
1316
+ EventEmitter.prototype.listeners = function listeners(event) {
1317
+ var evt = prefix ? prefix + event : event
1318
+ , handlers = this._events[evt];
1319
+
1320
+ if (!handlers) return [];
1321
+ if (handlers.fn) return [handlers.fn];
1322
+
1323
+ for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
1324
+ ee[i] = handlers[i].fn;
1325
+ }
1326
+
1327
+ return ee;
1328
+ };
1329
+
1330
+ /**
1331
+ * Return the number of listeners listening to a given event.
1332
+ *
1333
+ * @param {(String|Symbol)} event The event name.
1334
+ * @returns {Number} The number of listeners.
1335
+ * @public
1336
+ */
1337
+ EventEmitter.prototype.listenerCount = function listenerCount(event) {
1338
+ var evt = prefix ? prefix + event : event
1339
+ , listeners = this._events[evt];
1340
+
1341
+ if (!listeners) return 0;
1342
+ if (listeners.fn) return 1;
1343
+ return listeners.length;
1344
+ };
1345
+
1346
+ /**
1347
+ * Calls each of the listeners registered for a given event.
1348
+ *
1349
+ * @param {(String|Symbol)} event The event name.
1350
+ * @returns {Boolean} `true` if the event had listeners, else `false`.
1351
+ * @public
1352
+ */
1353
+ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
1354
+ var evt = prefix ? prefix + event : event;
1355
+
1356
+ if (!this._events[evt]) return false;
1357
+
1358
+ var listeners = this._events[evt]
1359
+ , len = arguments.length
1360
+ , args
1361
+ , i;
1362
+
1363
+ if (listeners.fn) {
1364
+ if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
1365
+
1366
+ switch (len) {
1367
+ case 1: return listeners.fn.call(listeners.context), true;
1368
+ case 2: return listeners.fn.call(listeners.context, a1), true;
1369
+ case 3: return listeners.fn.call(listeners.context, a1, a2), true;
1370
+ case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
1371
+ case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
1372
+ case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
1373
+ }
1374
+
1375
+ for (i = 1, args = new Array(len -1); i < len; i++) {
1376
+ args[i - 1] = arguments[i];
1377
+ }
1378
+
1379
+ listeners.fn.apply(listeners.context, args);
1380
+ } else {
1381
+ var length = listeners.length
1382
+ , j;
1383
+
1384
+ for (i = 0; i < length; i++) {
1385
+ if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
1386
+
1387
+ switch (len) {
1388
+ case 1: listeners[i].fn.call(listeners[i].context); break;
1389
+ case 2: listeners[i].fn.call(listeners[i].context, a1); break;
1390
+ case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
1391
+ case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
1392
+ default:
1393
+ if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
1394
+ args[j - 1] = arguments[j];
1395
+ }
1396
+
1397
+ listeners[i].fn.apply(listeners[i].context, args);
1398
+ }
1399
+ }
1400
+ }
1401
+
1402
+ return true;
1403
+ };
1404
+
1405
+ /**
1406
+ * Add a listener for a given event.
1407
+ *
1408
+ * @param {(String|Symbol)} event The event name.
1409
+ * @param {Function} fn The listener function.
1410
+ * @param {*} [context=this] The context to invoke the listener with.
1411
+ * @returns {EventEmitter} `this`.
1412
+ * @public
1413
+ */
1414
+ EventEmitter.prototype.on = function on(event, fn, context) {
1415
+ return addListener(this, event, fn, context, false);
1416
+ };
1417
+
1418
+ /**
1419
+ * Add a one-time listener for a given event.
1420
+ *
1421
+ * @param {(String|Symbol)} event The event name.
1422
+ * @param {Function} fn The listener function.
1423
+ * @param {*} [context=this] The context to invoke the listener with.
1424
+ * @returns {EventEmitter} `this`.
1425
+ * @public
1426
+ */
1427
+ EventEmitter.prototype.once = function once(event, fn, context) {
1428
+ return addListener(this, event, fn, context, true);
1429
+ };
1430
+
1431
+ /**
1432
+ * Remove the listeners of a given event.
1433
+ *
1434
+ * @param {(String|Symbol)} event The event name.
1435
+ * @param {Function} fn Only remove the listeners that match this function.
1436
+ * @param {*} context Only remove the listeners that have this context.
1437
+ * @param {Boolean} once Only remove one-time listeners.
1438
+ * @returns {EventEmitter} `this`.
1439
+ * @public
1440
+ */
1441
+ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
1442
+ var evt = prefix ? prefix + event : event;
1443
+
1444
+ if (!this._events[evt]) return this;
1445
+ if (!fn) {
1446
+ clearEvent(this, evt);
1447
+ return this;
1448
+ }
1449
+
1450
+ var listeners = this._events[evt];
1451
+
1452
+ if (listeners.fn) {
1453
+ if (
1454
+ listeners.fn === fn &&
1455
+ (!once || listeners.once) &&
1456
+ (!context || listeners.context === context)
1457
+ ) {
1458
+ clearEvent(this, evt);
1459
+ }
1460
+ } else {
1461
+ for (var i = 0, events = [], length = listeners.length; i < length; i++) {
1462
+ if (
1463
+ listeners[i].fn !== fn ||
1464
+ (once && !listeners[i].once) ||
1465
+ (context && listeners[i].context !== context)
1466
+ ) {
1467
+ events.push(listeners[i]);
1468
+ }
1469
+ }
1470
+
1471
+ //
1472
+ // Reset the array, or remove it completely if we have no more listeners.
1473
+ //
1474
+ if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
1475
+ else clearEvent(this, evt);
1476
+ }
1477
+
1478
+ return this;
1479
+ };
1480
+
1481
+ /**
1482
+ * Remove all listeners, or those of the specified event.
1483
+ *
1484
+ * @param {(String|Symbol)} [event] The event name.
1485
+ * @returns {EventEmitter} `this`.
1486
+ * @public
1487
+ */
1488
+ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
1489
+ var evt;
1490
+
1491
+ if (event) {
1492
+ evt = prefix ? prefix + event : event;
1493
+ if (this._events[evt]) clearEvent(this, evt);
1494
+ } else {
1495
+ this._events = new Events();
1496
+ this._eventsCount = 0;
1497
+ }
1498
+
1499
+ return this;
1500
+ };
1501
+
1502
+ //
1503
+ // Alias methods names because people roll like that.
1504
+ //
1505
+ EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
1506
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
1507
+
1508
+ //
1509
+ // Expose the prefix.
1510
+ //
1511
+ EventEmitter.prefixed = prefix;
1512
+
1513
+ //
1514
+ // Allow `EventEmitter` to be imported as module namespace.
1515
+ //
1516
+ EventEmitter.EventEmitter = EventEmitter;
1517
+
1518
+ //
1519
+ // Expose the module.
1520
+ //
1521
+ {
1522
+ module.exports = EventEmitter;
1523
+ }
1524
+ } (eventemitter3));
1525
+ return eventemitter3.exports;
1526
+ }
1527
+
1528
+ var eventemitter3Exports = requireEventemitter3();
1529
+ var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
1530
+
1177
1531
  // 实现函数
1178
1532
  function createHandleCtx(req, res) {
1179
1533
  // 用于存储所有的 Set-Cookie 字符串
@@ -1419,6 +1773,10 @@ class ServerBase {
1419
1773
  end({ code: 500, message: `${type} server is error` });
1420
1774
  }
1421
1775
  }
1776
+ /**
1777
+ * 根据emitter提醒关闭ws连接
1778
+ * @param ws
1779
+ */
1422
1780
  async onWsClose(ws) {
1423
1781
  const id = ws?.data?.id || '';
1424
1782
  if (id) {
@@ -1436,10 +1794,6 @@ class ServerBase {
1436
1794
  }
1437
1795
  }
1438
1796
 
1439
- function getDefaultExportFromCjs (x) {
1440
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1441
- }
1442
-
1443
1797
  var constants;
1444
1798
  var hasRequiredConstants;
1445
1799
 
@@ -6390,6 +6744,8 @@ class WsServerBase {
6390
6744
  });
6391
6745
  this.server.sendConnected(ws);
6392
6746
  this.wss.on('close', () => {
6747
+ // @ts-ignore
6748
+ ws?.data?.close?.();
6393
6749
  this.server.onWsClose(ws);
6394
6750
  });
6395
6751
  });
@@ -6731,6 +7087,7 @@ class BunServer extends ServerBase {
6731
7087
  },
6732
7088
  close: (ws) => {
6733
7089
  // WebSocket 连接关闭
7090
+ ws?.data?.close?.();
6734
7091
  this.onWsClose(ws);
6735
7092
  },
6736
7093
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@kevisual/router",
4
- "version": "0.0.50",
4
+ "version": "0.0.52",
5
5
  "description": "",
6
6
  "type": "module",
7
7
  "main": "./dist/router.js",
@@ -15,15 +15,16 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "src",
18
+ "auto.ts",
18
19
  "mod.ts"
19
20
  ],
20
21
  "keywords": [],
21
22
  "author": "abearxiong",
22
23
  "license": "MIT",
23
- "packageManager": "pnpm@10.26.0",
24
+ "packageManager": "pnpm@10.26.2",
24
25
  "devDependencies": {
25
26
  "@kevisual/local-proxy": "^0.0.8",
26
- "@kevisual/query": "^0.0.32",
27
+ "@kevisual/query": "^0.0.33",
27
28
  "@rollup/plugin-alias": "^6.0.0",
28
29
  "@rollup/plugin-commonjs": "29.0.0",
29
30
  "@rollup/plugin-node-resolve": "^16.0.3",
@@ -31,28 +32,28 @@
31
32
  "@types/bun": "^1.3.5",
32
33
  "@types/node": "^25.0.3",
33
34
  "@types/send": "^1.2.1",
34
- "@types/ws": "^8.18.1",
35
35
  "@types/xml2js": "^0.4.14",
36
- "cookie": "^1.1.1",
36
+ "@types/ws": "^8.18.1",
37
37
  "nanoid": "^5.1.6",
38
- "rollup": "^4.53.5",
38
+ "rollup": "^4.54.0",
39
39
  "rollup-plugin-dts": "^6.3.0",
40
40
  "ts-loader": "^9.5.4",
41
41
  "ts-node": "^10.9.2",
42
42
  "tslib": "^2.8.1",
43
43
  "tsx": "^4.21.0",
44
44
  "typescript": "^5.9.3",
45
- "ws": "npm:@kevisual/ws",
46
45
  "xml2js": "^0.6.2",
47
- "zod": "^4.2.1"
46
+ "zod": "^4.2.1",
47
+ "ws": "npm:@kevisual/ws"
48
48
  },
49
49
  "repository": {
50
50
  "type": "git",
51
51
  "url": "git+https://github.com/abearxiong/kevisual-router.git"
52
52
  },
53
53
  "dependencies": {
54
+ "eventemitter3": "^5.0.1",
54
55
  "path-to-regexp": "^8.3.0",
55
- "selfsigned": "^5.2.0",
56
+ "selfsigned": "^5.4.0",
56
57
  "send": "^1.2.1"
57
58
  },
58
59
  "publishConfig": {
@@ -94,4 +95,4 @@
94
95
  "require": "./src/*"
95
96
  }
96
97
  }
97
- }
98
+ }
package/src/route.ts CHANGED
@@ -562,7 +562,7 @@ export class QueryRouter {
562
562
  description: '列出当前应用下的所有的路由信息',
563
563
  run: async (ctx: RouteContext) => {
564
564
  const list = this.getList(filter);
565
- ctx.body = list;
565
+ ctx.body = { list };
566
566
  },
567
567
  });
568
568
  this.add(listRoute);
@@ -576,10 +576,16 @@ export class QueryRouter {
576
576
  * -- .on
577
577
  * -- .send
578
578
  */
579
- wait(params?: { path?: string; key?: string; payload?: any }, opts?: { emitter?: any, timeout?: number, getList?: boolean }) {
579
+ wait(params?: { path?: string; key?: string; payload?: any }, opts?: {
580
+ emitter?: any,
581
+ timeout?: number,
582
+ getList?: boolean
583
+ force?: boolean
584
+ filter?: (route: Route) => boolean
585
+ }) {
580
586
  const getList = opts?.getList ?? true;
581
587
  if (getList) {
582
- this.createRouteList();
588
+ this.createRouteList(opts?.force ?? false, opts?.filter);
583
589
  }
584
590
  return listenProcess({ app: this, params, ...opts });
585
591
  }
@@ -1,6 +1,34 @@
1
1
  import xml2js from 'xml2js';
2
-
3
- export const parseXml = async (req: any): Promise<any> => {
2
+ import { isBun } from '../utils/is-engine.ts';
3
+ import http from 'http';
4
+ export const xms2jsParser = async (data: string): Promise<any> => {
5
+ try {
6
+ // 使用xml2js解析XML
7
+ const xml = await xml2js.parseStringPromise(data);
8
+ return xml;
9
+ } catch (error) {
10
+ console.error('XML解析错误:', error);
11
+ return null;
12
+ }
13
+ }
14
+ export const parseXml = async (req: http.IncomingMessage): Promise<any> => {
15
+ if (isBun) {
16
+ // @ts-ignore
17
+ const body = req.body;
18
+ let xmlString = '';
19
+ if (body) {
20
+ xmlString = body;
21
+ }
22
+ if (!xmlString) {
23
+ // @ts-ignore
24
+ xmlString = await req.bun?.request?.text?.();
25
+ }
26
+ if (xmlString) {
27
+ return await xms2jsParser(xmlString)
28
+ }
29
+ console.error('没有读取到请求体');
30
+ return null;
31
+ }
4
32
  return await new Promise((resolve) => {
5
33
  // 读取请求数据
6
34
  let data = '';
@@ -12,15 +40,8 @@ export const parseXml = async (req: any): Promise<any> => {
12
40
  // 当请求结束时处理数据
13
41
  req.on('end', () => {
14
42
  try {
15
- // 使用xml2js解析XML
16
- xml2js.parseString(data, function (err, result) {
17
- if (err) {
18
- console.error('XML解析错误:', err);
19
- resolve(null);
20
- } else {
21
- const jsonString = JSON.stringify(result);
22
- resolve(jsonString);
23
- }
43
+ xms2jsParser(data).then((result) => {
44
+ resolve(result);
24
45
  });
25
46
  } catch (error) {
26
47
  console.error('处理请求时出错:', error);
@@ -3,7 +3,7 @@ import { handleServer } from './handle-server.ts';
3
3
  import * as cookie from './cookie.ts';
4
4
  import { ServerType, Listener, OnListener, ServerOpts, OnWebSocketOptions, OnWebSocketFn, WebSocketListenerFun, ListenerFun, HttpListenerFun, WS } from './server-type.ts';
5
5
  import { parseIfJson } from '../utils/parse.ts';
6
- import { EventEmitter } from 'events';
6
+ import { EventEmitter } from 'eventemitter3';
7
7
  type CookieFn = (name: string, value: string, options?: cookie.SerializeOptions, end?: boolean) => void;
8
8
 
9
9
  export type HandleCtx = {
@@ -273,6 +273,10 @@ export class ServerBase implements ServerType {
273
273
  end({ code: 500, message: `${type} server is error` });
274
274
  }
275
275
  }
276
+ /**
277
+ * 根据emitter提醒关闭ws连接
278
+ * @param ws
279
+ */
276
280
  async onWsClose(ws: WS) {
277
281
  const id = ws?.data?.id || '';
278
282
  if (id) {
@@ -253,6 +253,7 @@ export class BunServer extends ServerBase implements ServerType {
253
253
  },
254
254
  close: (ws: any) => {
255
255
  // WebSocket 连接关闭
256
+ ws?.data?.close?.();
256
257
  this.onWsClose(ws);
257
258
  },
258
259
  },
@@ -1,4 +1,4 @@
1
- import EventEmitter from 'node:events';
1
+ import { EventEmitter } from 'eventemitter3';
2
2
  import * as http from 'node:http';
3
3
 
4
4
 
@@ -2,7 +2,6 @@
2
2
  import { WebSocketServer } from 'ws';
3
3
  import type { WebSocket } from 'ws';
4
4
  import { ServerType } from './server-type.ts'
5
- import { parseIfJson } from '../utils/parse.ts';
6
5
  import { isBun } from '../utils/is-engine.ts';
7
6
 
8
7
 
@@ -62,6 +61,8 @@ export class WsServerBase {
62
61
  });
63
62
  this.server.sendConnected(ws);
64
63
  this.wss.on('close', () => {
64
+ // @ts-ignore
65
+ ws?.data?.close?.();
65
66
  this.server.onWsClose(ws);
66
67
  });
67
68
  });