@lytjs/http-server 6.8.0 → 6.9.0

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/dist/index.cjs CHANGED
@@ -351,8 +351,9 @@ var Server = class {
351
351
  let index = this.middlewares.length;
352
352
  const next = async () => {
353
353
  index--;
354
- if (index >= 0 && this.middlewares[index]) {
355
- await this.middlewares[index](ctx, next);
354
+ const middleware = this.middlewares[index];
355
+ if (index >= 0 && middleware) {
356
+ await middleware(ctx, next);
356
357
  } else {
357
358
  await handler();
358
359
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer","parseQueryStringWithArrays"],"mappings":";;;;;;;;AA6BA,IAAM,QAAA,GAAW,yBAAA;AACjB,IAAM,WAAA,GAAc,MAAA;AAKpB,SAAS,aAAa,IAAA,EAA2B;AAC/C,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC/B,EAAA,MAAM,SAAsB,EAAC;AAE7B,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA;AACzC,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,MAAM,GAAG,IAAA,EAAM,QAAA,EAAU,UAAU,CAAA,GAAI,UAAA;AACvC,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACV,IAAA,EAAM,OAAA;AAAA,UACN,IAAA;AAAA,UACA,YAAY,UAAA,KAAe,KAAA;AAAA,UAC3B,UAAU,QAAA,KAAa;AAAA,SACxB,CAAA;AAAA,MACH;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA,EAAG;AAC7B,MAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,UAAA,EAAY,KAAA,EAAO,KAAK,CAAA;AAC5C,MAAA;AAAA,IACF;AAEA,IAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,SAAS,CAAA;AAAA,EAChD;AAEA,EAAA,OAAO,MAAA;AACT;AAOA,SAAS,WAAW,MAAA,EAA6B;AAC/C,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,QAAQ,MAAM,IAAA;AAAM,MAClB,KAAK,QAAA;AACH,QAAA,KAAA,IAAS,CAAA;AACT,QAAA;AAAA,MACF,KAAK,OAAA;AACH,QAAA,KAAA,IAAS,KAAA,CAAM,WAAW,CAAA,GAAI,CAAA;AAC9B,QAAA;AAAA,MACF,KAAK,UAAA;AACH,QAAA,KAAA,IAAS,CAAA;AACT,QAAA;AAAA;AACJ,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAcA,SAAS,SAAA,CACP,QAAA,EACA,MAAA,EACA,MAAA,GAAkB,KAAA,EACD;AACjB,EAAA,MAAM,eAAe,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AACvD,EAAA,MAAM,SAA4C,EAAC;AACnD,EAAA,IAAI,OAAA,GAAU,IAAA;AACd,EAAA,IAAI,CAAA,GAAI,CAAA;AAER,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAI,CAAA,IAAK,aAAa,MAAA,EAAQ;AAC5B,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,KAAA,CAAM,QAAA,EAAU;AAC9C,MAAA,IAAI,KAAA,CAAM,SAAS,UAAA,EAAY;AAC/B,MAAA,OAAA,GAAU,KAAA;AACV,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,aAAa,CAAC,CAAA;AAE9B,IAAA,QAAQ,MAAM,IAAA;AAAM,MAClB,KAAK,QAAA;AACH,QAAA,IAAI,OAAA,KAAY,MAAM,KAAA,EAAO;AAC3B,UAAA,OAAA,GAAU,KAAA;AAAA,QACZ;AACA,QAAA,CAAA,EAAA;AACA,QAAA;AAAA,MAEF,KAAK,OAAA;AACH,QAAA,IAAI,MAAM,UAAA,EAAY;AACpB,UAAA,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,GAAI,YAAA,CAAa,MAAM,CAAC,CAAA;AACzC,UAAA,CAAA,GAAI,YAAA,CAAa,MAAA;AAAA,QACnB,CAAA,MAAA,IAAW,YAAY,MAAA,EAAW;AAChC,UAAA,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,GAAI,OAAA;AACrB,UAAA,CAAA,EAAA;AAAA,QACF;AACA,QAAA;AAAA,MAEF,KAAK,UAAA;AACH,QAAA,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA,GAAI,YAAA,CAAa,MAAM,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA;AACpD,QAAA,CAAA,GAAI,YAAA,CAAa,MAAA;AACjB,QAAA;AAAA;AAGJ,IAAA,IAAI,CAAC,OAAA,EAAS;AAAA,EAChB;AAGA,EAAA,IAAI,OAAA,IAAW,CAAA,GAAI,YAAA,CAAa,MAAA,EAAQ;AACtC,IAAA,OAAA,GAAU,KAAA;AAAA,EACZ;AAGA,EAAA,IAAI,CAAC,UAAU,OAAA,IAAW,YAAA,CAAa,WAAW,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AAC1E,IAAA,OAAA,GAAU,IAAA;AAAA,EACZ;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,MAAA;AAAA,IACA,IAAA,EAAM,MAAM,YAAA,CAAa,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,IAC7C,KAAA,EAAO,WAAW,MAAM;AAAA,GAC1B;AACF;AAKO,IAAM,SAAN,MAAa;AAAA,EAAb,WAAA,GAAA;AAEL;AAAA,IAAA,IAAA,CAAQ,SAKH,EAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUN,EAAA,CAAG,MAAA,EAAoB,IAAA,EAAc,OAAA,EAAwB;AAC3D,IAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,EAAE,QAAQ,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAA;AAClD,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,GAAA,CAAI,MAAc,OAAA,EAAwB;AACxC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAA,CAAK,MAAc,OAAA,EAAwB;AACzC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,GAAA,CAAI,MAAc,OAAA,EAAwB;AACxC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAA,CAAM,MAAc,OAAA,EAAwB;AAC1C,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,OAAA,EAAS,IAAA,EAAM,OAAO,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,CAAO,MAAc,OAAA,EAAwB;AAC3C,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,QAAA,EAAU,IAAA,EAAM,OAAO,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAA,CACE,QACA,IAAA,EACwE;AACxE,IAAA,MAAM,UAAA,GAAa,KAAK,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,MAAM,CAAA;AAEhE,IAAA,IAAI,SAAA,GAAoF,IAAA;AACxF,IAAA,IAAI,SAAA,GAAY,EAAA;AAEhB,IAAA,KAAA,MAAW,SAAS,UAAA,EAAY;AAC9B,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,IAAA,EAAM,KAAA,CAAM,MAAM,CAAA;AAC3C,MAAA,IAAI,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,KAAA,GAAQ,SAAA,EAAW;AAC9C,QAAA,SAAA,GAAY,MAAA,CAAO,KAAA;AACnB,QAAA,SAAA,GAAY,EAAE,OAAA,EAAS,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,OAAO,MAAA,EAAO;AAAA,MAC9D;AAAA,IACF;AAEA,IAAA,OAAO,SAAA;AAAA,EACT;AACF;AAOO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,IAAI,MAAA,EAAO;AACpB;ACzQO,IAAM,SAAN,MAAa;AAAA;AAAA;AAAA;AAAA,EAWlB,WAAA,GAAc;AAPd;AAAA,IAAA,IAAA,CAAQ,cAA8E,EAAC;AAQrF,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,MAAA,EAAO;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,UAAA,EAA8E;AAChF,IAAA,IAAA,CAAK,WAAA,CAAY,KAAK,UAAU,CAAA;AAChC,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,EAAA,CAAG,MAAA,EAAoB,IAAA,EAAc,OAAA,EAAwB;AAC3D,IAAA,IAAA,CAAK,MAAA,CAAO,EAAA,CAAG,MAAA,EAAQ,IAAA,EAAM,OAAO,CAAA;AACpC,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,GAAA,CAAI,MAAc,OAAA,EAAwB;AACxC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAA,CAAK,MAAc,OAAA,EAAwB;AACzC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,IAAA,EAAM,OAAO,CAAA;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,GAAA,CAAI,MAAc,OAAA,EAAwB;AACxC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,KAAA,CAAM,MAAc,OAAA,EAAwB;AAC1C,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,OAAA,EAAS,IAAA,EAAM,OAAO,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,CAAO,MAAc,OAAA,EAAwB;AAC3C,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,QAAA,EAAU,IAAA,EAAM,OAAO,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,CAAO,MAAc,QAAA,EAAkC;AACrD,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,IAAA,CAAK,SAASA,iBAAA,CAAiB,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,IAAI,CAAC,CAAA;AAC5D,MAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,QAAA,EAAU,MAAM;AACvC,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAA,GAAuB;AACrB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,IAAI,KAAK,MAAA,EAAQ;AACf,QAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAC,GAAA,KAAQ;AACzB,UAAA,IAAI,GAAA,EAAK;AACP,YAAA,MAAA,CAAO,GAAG,CAAA;AAAA,UACZ,CAAA,MAAO;AACL,YAAA,OAAA,EAAQ;AAAA,UACV;AAAA,QACF,CAAC,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,aAAA,CAAc,GAAA,EAAsB,GAAA,EAAoC;AACpF,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,IAAO,GAAA;AACvB,IAAA,MAAM,OAAO,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,GAAA;AAClC,IAAA,MAAM,MAAA,GAAU,IAAI,MAAA,IAAU,KAAA;AAE9B,IAAA,MAAM,OAAA,GAAmB;AAAA,MACvB,MAAA;AAAA,MACA,GAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,KAAA,EAAOC,uCAA2B,GAAG,CAAA;AAAA,MACrC,QAAQ,EAAC;AAAA,MACT,EAAA,EAAI,IAAI,MAAA,CAAO;AAAA,KACjB;AAEA,IAAA,MAAM,QAAA,GAAqB;AAAA,MACzB,MAAA,EAAQ,GAAA;AAAA,MACR,SAAS;AAAC,KACZ;AAEA,IAAA,MAAM,GAAA,GAAe;AAAA,MACnB,OAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,QAAQ,IAAI,CAAA;AAE5C,IAAA,IAAI,KAAA,EAAO;AAET,MAAA,GAAA,CAAI,OAAA,CAAQ,SAAS,EAAC;AACtB,MAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,KAAA,CAAM,MAAM,CAAA,EAAG;AACvD,QAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAExB,UAAA,GAAA,CAAI,QAAQ,MAAA,CAAO,GAAG,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAAA,QACxC,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAA,GAAI,KAAA;AAAA,QAC5B;AAAA,MACF;AAEA,MAAA,MAAM,UAAU,YAAY;AAC1B,QAAA,MAAM,KAAA,CAAM,QAAQ,GAAG,CAAA;AAAA,MACzB,CAAA;AAEA,MAAA,IAAI,KAAA,GAAQ,KAAK,WAAA,CAAY,MAAA;AAC7B,MAAA,MAAM,OAAO,YAAY;AACvB,QAAA,KAAA,EAAA;AACA,QAAA,IAAI,KAAA,IAAS,CAAA,IAAK,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA,EAAG;AACzC,UAAA,MAAM,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA,CAAE,KAAK,IAAI,CAAA;AAAA,QACzC,CAAA,MAAO;AACL,UAAA,MAAM,OAAA,EAAQ;AAAA,QAChB;AAAA,MACF,CAAA;AAEA,MAAA,MAAM,IAAA,EAAK;AAAA,IACb,CAAA,MAAO;AACL,MAAA,IAAI,IAAI,QAAA,EAAU;AAChB,QAAA,GAAA,CAAI,SAAS,MAAA,GAAS,GAAA;AACtB,QAAA,GAAA,CAAI,QAAA,CAAS,IAAA,GAAO,EAAE,KAAA,EAAO,oBAAA,EAAM;AAAA,MACrC;AAAA,IACF;AAEA,IAAA,IAAI,IAAI,QAAA,EAAU;AAChB,MAAA,IAAA,CAAK,YAAA,CAAa,GAAA,EAAK,GAAA,CAAI,QAAQ,CAAA;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAA,CAAa,KAAqB,QAAA,EAA0B;AAClE,IAAA,GAAA,CAAI,aAAa,QAAA,CAAS,MAAA;AAE1B,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA,EAAG;AAC3D,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,QAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,UAAA,GAAA,CAAI,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,QACtB;AAAA,MACF,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,SAAA,CAAU,KAAK,KAAK,CAAA;AAAA,MAC1B;AAAA,IACF;AAEA,IAAA,IAAI,QAAA,CAAS,SAAS,MAAA,EAAW;AAC/B,MAAA,MAAM,IAAA,GACJ,OAAO,QAAA,CAAS,IAAA,KAAS,QAAA,GAAW,SAAS,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,QAAA,CAAS,IAAI,CAAA;AAElF,MAAA,IAAI,CAAC,QAAA,CAAS,OAAA,CAAQ,cAAc,CAAA,EAAG;AACrC,QAAA,GAAA,CAAI,SAAA;AAAA,UACF,cAAA;AAAA,UACA,OAAO,QAAA,CAAS,IAAA,KAAS,QAAA,GAAW,YAAA,GAAe;AAAA,SACrD;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,IAAI,IAAI,CAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,GAAA,CAAI,GAAA,EAAI;AAAA,IACV;AAAA,EACF;AACF;AAOO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,IAAI,MAAA,EAAO;AACpB","file":"index.cjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler } from './types';\nimport type { HttpMethod } from '@lytjs/shared-types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler } from './types';\nimport type {\n HttpMethod,\n HttpContext as Context,\n HttpRequest as Request,\n HttpResponse as Response,\n} from '@lytjs/shared-types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: ((ctx: Context, next: () => Promise<void>) => Promise<void>)[] = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n if (index >= 0 && this.middlewares[index]) {\n await this.middlewares[index](ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v);\n }\n } else {\n res.setHeader(key, value);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
1
+ {"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer","parseQueryStringWithArrays"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler, HttpMethod } from './types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler, Context, Request, Response, HttpMethod } from './types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: Array<(ctx: Context, next: () => Promise<void>) => Promise<void>> = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n const middleware = this.middlewares[index];\n if (index >= 0 && middleware) {\n await middleware(ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v as string | number | string[]);\n }\n } else {\n res.setHeader(key, value as string | number | string[]);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
@@ -0,0 +1,219 @@
1
+ import { HttpMethod as HttpMethod$1 } from '@lytjs/shared-types';
2
+
3
+ /**
4
+ * HTTP 服务器类型定义
5
+ */
6
+
7
+ type HttpMethod = HttpMethod$1;
8
+ interface Context {
9
+ request: Request;
10
+ response: Response;
11
+ [key: string]: unknown;
12
+ }
13
+ interface Request {
14
+ method: HttpMethod;
15
+ url: string;
16
+ path: string;
17
+ headers: Record<string, string | string[] | undefined>;
18
+ query: Record<string, string | string[]>;
19
+ params: Record<string, string>;
20
+ ip?: string;
21
+ [key: string]: unknown;
22
+ }
23
+ interface Response {
24
+ status: number;
25
+ headers: Record<string, string | string[] | undefined>;
26
+ body?: unknown;
27
+ [key: string]: unknown;
28
+ }
29
+ type Route = unknown;
30
+ /**
31
+ * 请求处理器函数
32
+ */
33
+ type Handler = (ctx: Context) => Promise<void> | void;
34
+
35
+ /**
36
+ * HTTP 服务器类
37
+ */
38
+ declare class Server {
39
+ /** 路由实例 */
40
+ private router;
41
+ /** 中间件列表 */
42
+ private middlewares;
43
+ /** Node.js 服务器实例 */
44
+ private server?;
45
+ /**
46
+ * 构造函数
47
+ */
48
+ constructor();
49
+ /**
50
+ * 添加中间件
51
+ *
52
+ * @param middleware - 中间件函数
53
+ * @returns 服务器实例
54
+ */
55
+ use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this;
56
+ /**
57
+ * 添加路由
58
+ *
59
+ * @param method - HTTP 方法
60
+ * @param path - 路径
61
+ * @param handler - 处理器
62
+ * @returns 服务器实例
63
+ */
64
+ on(method: HttpMethod, path: string, handler: Handler): this;
65
+ /**
66
+ * 添加 GET 路由
67
+ *
68
+ * @param path - 路径
69
+ * @param handler - 处理器
70
+ * @returns 服务器实例
71
+ */
72
+ get(path: string, handler: Handler): this;
73
+ /**
74
+ * 添加 POST 路由
75
+ *
76
+ * @param path - 路径
77
+ * @param handler - 处理器
78
+ * @returns 服务器实例
79
+ */
80
+ post(path: string, handler: Handler): this;
81
+ /**
82
+ * 添加 PUT 路由
83
+ *
84
+ * @param path - 路径
85
+ * @param handler - 处理器
86
+ * @returns 服务器实例
87
+ */
88
+ put(path: string, handler: Handler): this;
89
+ /**
90
+ * 添加 PATCH 路由
91
+ *
92
+ * @param path - 路径
93
+ * @param handler - 处理器
94
+ * @returns 服务器实例
95
+ */
96
+ patch(path: string, handler: Handler): this;
97
+ /**
98
+ * 添加 DELETE 路由
99
+ *
100
+ * @param path - 路径
101
+ * @param handler - 处理器
102
+ * @returns 服务器实例
103
+ */
104
+ delete(path: string, handler: Handler): this;
105
+ /**
106
+ * 启动服务器监听
107
+ *
108
+ * @param port - 端口
109
+ * @param hostname - 主机名
110
+ * @returns Promise
111
+ */
112
+ listen(port: number, hostname?: string): Promise<void>;
113
+ /**
114
+ * 关闭服务器
115
+ *
116
+ * @returns Promise
117
+ */
118
+ close(): Promise<void>;
119
+ /**
120
+ * 处理请求
121
+ *
122
+ * @param req - Node.js 请求对象
123
+ * @param res - Node.js 响应对象
124
+ */
125
+ private handleRequest;
126
+ /**
127
+ * 发送响应
128
+ *
129
+ * @param res - Node.js 响应对象
130
+ * @param response - 响应对象
131
+ */
132
+ private sendResponse;
133
+ }
134
+ /**
135
+ * 创建 HTTP 服务器
136
+ *
137
+ * @returns 服务器实例
138
+ */
139
+ declare function createServer(): Server;
140
+
141
+ /**
142
+ * HTTP 路由实现
143
+ */
144
+
145
+ /**
146
+ * 路由类
147
+ */
148
+ declare class Router {
149
+ /** 路由列表 */
150
+ private routes;
151
+ /**
152
+ * 添加路由
153
+ *
154
+ * @param method - HTTP 方法
155
+ * @param path - 路径
156
+ * @param handler - 处理器
157
+ * @returns 路由实例
158
+ */
159
+ on(method: HttpMethod, path: string, handler: Handler): this;
160
+ /**
161
+ * 添加 GET 路由
162
+ *
163
+ * @param path - 路径
164
+ * @param handler - 处理器
165
+ * @returns 路由实例
166
+ */
167
+ get(path: string, handler: Handler): this;
168
+ /**
169
+ * 添加 POST 路由
170
+ *
171
+ * @param path - 路径
172
+ * @param handler - 处理器
173
+ * @returns 路由实例
174
+ */
175
+ post(path: string, handler: Handler): this;
176
+ /**
177
+ * 添加 PUT 路由
178
+ *
179
+ * @param path - 路径
180
+ * @param handler - 处理器
181
+ * @returns 路由实例
182
+ */
183
+ put(path: string, handler: Handler): this;
184
+ /**
185
+ * 添加 PATCH 路由
186
+ *
187
+ * @param path - 路径
188
+ * @param handler - 处理器
189
+ * @returns 路由实例
190
+ */
191
+ patch(path: string, handler: Handler): this;
192
+ /**
193
+ * 添加 DELETE 路由
194
+ *
195
+ * @param path - 路径
196
+ * @param handler - 处理器
197
+ * @returns 路由实例
198
+ */
199
+ delete(path: string, handler: Handler): this;
200
+ /**
201
+ * 匹配路由
202
+ *
203
+ * @param method - HTTP 方法
204
+ * @param path - 路径
205
+ * @returns 匹配结果或 null
206
+ */
207
+ match(method: HttpMethod, path: string): {
208
+ handler: Handler;
209
+ params: Record<string, string | string[]>;
210
+ } | null;
211
+ }
212
+ /**
213
+ * 创建路由
214
+ *
215
+ * @returns 路由实例
216
+ */
217
+ declare function createRouter(): Router;
218
+
219
+ export { type Context, type Handler, type HttpMethod, type Request, type Response, type Route, Router, Server, createRouter, createServer };
@@ -0,0 +1,219 @@
1
+ import { HttpMethod as HttpMethod$1 } from '@lytjs/shared-types';
2
+
3
+ /**
4
+ * HTTP 服务器类型定义
5
+ */
6
+
7
+ type HttpMethod = HttpMethod$1;
8
+ interface Context {
9
+ request: Request;
10
+ response: Response;
11
+ [key: string]: unknown;
12
+ }
13
+ interface Request {
14
+ method: HttpMethod;
15
+ url: string;
16
+ path: string;
17
+ headers: Record<string, string | string[] | undefined>;
18
+ query: Record<string, string | string[]>;
19
+ params: Record<string, string>;
20
+ ip?: string;
21
+ [key: string]: unknown;
22
+ }
23
+ interface Response {
24
+ status: number;
25
+ headers: Record<string, string | string[] | undefined>;
26
+ body?: unknown;
27
+ [key: string]: unknown;
28
+ }
29
+ type Route = unknown;
30
+ /**
31
+ * 请求处理器函数
32
+ */
33
+ type Handler = (ctx: Context) => Promise<void> | void;
34
+
35
+ /**
36
+ * HTTP 服务器类
37
+ */
38
+ declare class Server {
39
+ /** 路由实例 */
40
+ private router;
41
+ /** 中间件列表 */
42
+ private middlewares;
43
+ /** Node.js 服务器实例 */
44
+ private server?;
45
+ /**
46
+ * 构造函数
47
+ */
48
+ constructor();
49
+ /**
50
+ * 添加中间件
51
+ *
52
+ * @param middleware - 中间件函数
53
+ * @returns 服务器实例
54
+ */
55
+ use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this;
56
+ /**
57
+ * 添加路由
58
+ *
59
+ * @param method - HTTP 方法
60
+ * @param path - 路径
61
+ * @param handler - 处理器
62
+ * @returns 服务器实例
63
+ */
64
+ on(method: HttpMethod, path: string, handler: Handler): this;
65
+ /**
66
+ * 添加 GET 路由
67
+ *
68
+ * @param path - 路径
69
+ * @param handler - 处理器
70
+ * @returns 服务器实例
71
+ */
72
+ get(path: string, handler: Handler): this;
73
+ /**
74
+ * 添加 POST 路由
75
+ *
76
+ * @param path - 路径
77
+ * @param handler - 处理器
78
+ * @returns 服务器实例
79
+ */
80
+ post(path: string, handler: Handler): this;
81
+ /**
82
+ * 添加 PUT 路由
83
+ *
84
+ * @param path - 路径
85
+ * @param handler - 处理器
86
+ * @returns 服务器实例
87
+ */
88
+ put(path: string, handler: Handler): this;
89
+ /**
90
+ * 添加 PATCH 路由
91
+ *
92
+ * @param path - 路径
93
+ * @param handler - 处理器
94
+ * @returns 服务器实例
95
+ */
96
+ patch(path: string, handler: Handler): this;
97
+ /**
98
+ * 添加 DELETE 路由
99
+ *
100
+ * @param path - 路径
101
+ * @param handler - 处理器
102
+ * @returns 服务器实例
103
+ */
104
+ delete(path: string, handler: Handler): this;
105
+ /**
106
+ * 启动服务器监听
107
+ *
108
+ * @param port - 端口
109
+ * @param hostname - 主机名
110
+ * @returns Promise
111
+ */
112
+ listen(port: number, hostname?: string): Promise<void>;
113
+ /**
114
+ * 关闭服务器
115
+ *
116
+ * @returns Promise
117
+ */
118
+ close(): Promise<void>;
119
+ /**
120
+ * 处理请求
121
+ *
122
+ * @param req - Node.js 请求对象
123
+ * @param res - Node.js 响应对象
124
+ */
125
+ private handleRequest;
126
+ /**
127
+ * 发送响应
128
+ *
129
+ * @param res - Node.js 响应对象
130
+ * @param response - 响应对象
131
+ */
132
+ private sendResponse;
133
+ }
134
+ /**
135
+ * 创建 HTTP 服务器
136
+ *
137
+ * @returns 服务器实例
138
+ */
139
+ declare function createServer(): Server;
140
+
141
+ /**
142
+ * HTTP 路由实现
143
+ */
144
+
145
+ /**
146
+ * 路由类
147
+ */
148
+ declare class Router {
149
+ /** 路由列表 */
150
+ private routes;
151
+ /**
152
+ * 添加路由
153
+ *
154
+ * @param method - HTTP 方法
155
+ * @param path - 路径
156
+ * @param handler - 处理器
157
+ * @returns 路由实例
158
+ */
159
+ on(method: HttpMethod, path: string, handler: Handler): this;
160
+ /**
161
+ * 添加 GET 路由
162
+ *
163
+ * @param path - 路径
164
+ * @param handler - 处理器
165
+ * @returns 路由实例
166
+ */
167
+ get(path: string, handler: Handler): this;
168
+ /**
169
+ * 添加 POST 路由
170
+ *
171
+ * @param path - 路径
172
+ * @param handler - 处理器
173
+ * @returns 路由实例
174
+ */
175
+ post(path: string, handler: Handler): this;
176
+ /**
177
+ * 添加 PUT 路由
178
+ *
179
+ * @param path - 路径
180
+ * @param handler - 处理器
181
+ * @returns 路由实例
182
+ */
183
+ put(path: string, handler: Handler): this;
184
+ /**
185
+ * 添加 PATCH 路由
186
+ *
187
+ * @param path - 路径
188
+ * @param handler - 处理器
189
+ * @returns 路由实例
190
+ */
191
+ patch(path: string, handler: Handler): this;
192
+ /**
193
+ * 添加 DELETE 路由
194
+ *
195
+ * @param path - 路径
196
+ * @param handler - 处理器
197
+ * @returns 路由实例
198
+ */
199
+ delete(path: string, handler: Handler): this;
200
+ /**
201
+ * 匹配路由
202
+ *
203
+ * @param method - HTTP 方法
204
+ * @param path - 路径
205
+ * @returns 匹配结果或 null
206
+ */
207
+ match(method: HttpMethod, path: string): {
208
+ handler: Handler;
209
+ params: Record<string, string | string[]>;
210
+ } | null;
211
+ }
212
+ /**
213
+ * 创建路由
214
+ *
215
+ * @returns 路由实例
216
+ */
217
+ declare function createRouter(): Router;
218
+
219
+ export { type Context, type Handler, type HttpMethod, type Request, type Response, type Route, Router, Server, createRouter, createServer };
package/dist/index.mjs CHANGED
@@ -349,8 +349,9 @@ var Server = class {
349
349
  let index = this.middlewares.length;
350
350
  const next = async () => {
351
351
  index--;
352
- if (index >= 0 && this.middlewares[index]) {
353
- await this.middlewares[index](ctx, next);
352
+ const middleware = this.middlewares[index];
353
+ if (index >= 0 && middleware) {
354
+ await middleware(ctx, next);
354
355
  } else {
355
356
  await handler();
356
357
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler } from './types';\nimport type { HttpMethod } from '@lytjs/shared-types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler } from './types';\nimport type {\n HttpMethod,\n HttpContext as Context,\n HttpRequest as Request,\n HttpResponse as Response,\n} from '@lytjs/shared-types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: ((ctx: Context, next: () => Promise<void>) => Promise<void>)[] = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n if (index >= 0 && this.middlewares[index]) {\n await this.middlewares[index](ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v);\n }\n } else {\n res.setHeader(key, value);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
1
+ {"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler, HttpMethod } from './types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler, Context, Request, Response, HttpMethod } from './types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: Array<(ctx: Context, next: () => Promise<void>) => Promise<void>> = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n const middleware = this.middlewares[index];\n if (index >= 0 && middleware) {\n await middleware(ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v as string | number | string[]);\n }\n } else {\n res.setHeader(key, value as string | number | string[]);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lytjs/http-server",
3
- "version": "6.8.0",
3
+ "version": "6.9.0",
4
4
  "description": "LytJS HTTP 服务器",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -31,10 +31,10 @@
31
31
  "clean": "rm -rf dist node_modules .turbo"
32
32
  },
33
33
  "dependencies": {
34
- "@lytjs/common-is": "^6.8.0",
35
- "@lytjs/common-query": "^6.8.0",
36
- "@lytjs/middleware": "^6.8.0",
37
- "@lytjs/shared-types": "^6.8.0"
34
+ "@lytjs/common-is": "^6.9.0",
35
+ "@lytjs/common-query": "^6.9.0",
36
+ "@lytjs/middleware": "^6.9.0",
37
+ "@lytjs/shared-types": "^6.9.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "tsup": "^8.3.6",