index.cjs 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
  9. var __export = (target, all) => {
  10. for (var name in all)
  11. __defProp(target, name, { get: all[name], enumerable: true });
  12. };
  13. var __copyProps = (to, from, except, desc) => {
  14. if (from && typeof from === "object" || typeof from === "function") {
  15. for (let key of __getOwnPropNames(from))
  16. if (!__hasOwnProp.call(to, key) && key !== except)
  17. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  18. }
  19. return to;
  20. };
  21. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  22. // If the importer is in node compatibility mode or this is not an ESM
  23. // file that has been converted to a CommonJS file using a Babel-
  24. // compatible transform (i.e. "__esModule" has not been set), then set
  25. // "default" to the CommonJS "module.exports" for node compatibility.
  26. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  27. mod
  28. ));
  29. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  30. // src/index.js
  31. var index_exports = {};
  32. __export(index_exports, {
  33. BodyParser: () => BodyParser,
  34. CHARACTER_ENCODING_LIST: () => CHARACTER_ENCODING_LIST,
  35. CookiesParser: () => CookiesParser,
  36. DataSender: () => DataSender,
  37. EXPOSED_ERROR_PROPERTIES: () => EXPOSED_ERROR_PROPERTIES,
  38. ErrorSender: () => ErrorSender,
  39. HookInvoker: () => HookInvoker,
  40. HookRegistry: () => HookRegistry,
  41. HttpMethod: () => HttpMethod,
  42. METHODS_WITH_BODY: () => METHODS_WITH_BODY,
  43. QueryParser: () => QueryParser,
  44. RequestContext: () => RequestContext,
  45. RequestParser: () => RequestParser,
  46. Route: () => Route,
  47. RouteRegistry: () => RouteRegistry,
  48. RouterHookType: () => RouterHookType,
  49. RouterOptions: () => RouterOptions,
  50. TrieRouter: () => TrieRouter,
  51. UNPARSABLE_MEDIA_TYPES: () => UNPARSABLE_MEDIA_TYPES,
  52. cloneDeep: () => cloneDeep,
  53. createCookieString: () => createCookieString,
  54. createError: () => createError,
  55. createRequestMock: () => createRequestMock,
  56. createResponseMock: () => createResponseMock,
  57. createRouteMock: () => createRouteMock,
  58. fetchRequestBody: () => fetchRequestBody,
  59. getRequestPathname: () => getRequestPathname,
  60. isPromise: () => isPromise,
  61. isReadableStream: () => isReadableStream,
  62. isResponseSent: () => isResponseSent,
  63. isWritableStream: () => isWritableStream,
  64. parseContentType: () => parseContentType,
  65. parseCookieString: () => parseCookieString,
  66. parseJsonBody: () => parseJsonBody,
  67. toCamelCase: () => toCamelCase,
  68. validateRouteDefinition: () => validateRouteDefinition
  69. });
  70. module.exports = __toCommonJS(index_exports);
  71. // src/route/route.js
  72. var import_js_debug = require("@e22m4u/js-debug");
  73. // src/hooks/hook-invoker.js
  74. var import_js_format11 = require("@e22m4u/js-format");
  75. // src/debuggable-service.js
  76. var import_js_service = require("@e22m4u/js-service");
  77. var MODULE_DEBUG_NAMESPACE = "jsTrieRouter";
  78. var _DebuggableService = class _DebuggableService extends import_js_service.DebuggableService {
  79. /**
  80. * Constructor.
  81. *
  82. * @param {ServiceContainer} container
  83. */
  84. constructor(container = void 0) {
  85. super(container, {
  86. namespace: MODULE_DEBUG_NAMESPACE,
  87. noEnvironmentNamespace: true
  88. });
  89. }
  90. };
  91. __name(_DebuggableService, "DebuggableService");
  92. var DebuggableService = _DebuggableService;
  93. // src/utils/clone-deep.js
  94. function cloneDeep(value) {
  95. if (value == null || typeof value !== "object") {
  96. return value;
  97. }
  98. if (value instanceof Date) {
  99. return new Date(value.getTime());
  100. }
  101. if (Array.isArray(value)) {
  102. return value.map((item) => cloneDeep(item));
  103. }
  104. const proto = Object.getPrototypeOf(value);
  105. if (proto === Object.prototype || proto === null) {
  106. const newObj = proto === null ? /* @__PURE__ */ Object.create(null) : {};
  107. for (const key in value) {
  108. if (Object.prototype.hasOwnProperty.call(value, key)) {
  109. newObj[key] = cloneDeep(value[key]);
  110. }
  111. }
  112. return newObj;
  113. }
  114. return value;
  115. }
  116. __name(cloneDeep, "cloneDeep");
  117. // src/utils/is-promise.js
  118. function isPromise(value) {
  119. if (!value) {
  120. return false;
  121. }
  122. if (typeof value !== "object") {
  123. return false;
  124. }
  125. return typeof value.then === "function";
  126. }
  127. __name(isPromise, "isPromise");
  128. // src/utils/create-error.js
  129. var import_js_format = require("@e22m4u/js-format");
  130. function createError(errorCtor, message, ...args) {
  131. if (typeof errorCtor !== "function") {
  132. throw new import_js_format.InvalidArgumentError(
  133. 'The first parameter of "createError" must be a constructor, but %v was given.',
  134. errorCtor
  135. );
  136. }
  137. if (message != null && typeof message !== "string") {
  138. throw new import_js_format.InvalidArgumentError(
  139. 'The second parameter of "createError" must be a String, but %v was given.',
  140. message
  141. );
  142. }
  143. if (message == null) {
  144. return new errorCtor();
  145. }
  146. const interpolatedMessage = (0, import_js_format.format)(message, ...args);
  147. return new errorCtor(interpolatedMessage);
  148. }
  149. __name(createError, "createError");
  150. // src/utils/to-camel-case.js
  151. var import_js_format2 = require("@e22m4u/js-format");
  152. function toCamelCase(input) {
  153. if (typeof input !== "string") {
  154. throw new import_js_format2.InvalidArgumentError(
  155. 'The first parameter of "toCamelCase" must be a String, but %v was given.',
  156. input
  157. );
  158. }
  159. return input.replace(/(^\w|[A-Z]|\b\w)/g, (c) => c.toUpperCase()).replace(/\W+/g, "").replace(/(^\w)/g, (c) => c.toLowerCase());
  160. }
  161. __name(toCamelCase, "toCamelCase");
  162. // src/utils/is-response-sent.js
  163. var import_js_format3 = require("@e22m4u/js-format");
  164. function isResponseSent(response) {
  165. if (!response || typeof response !== "object" || Array.isArray(response) || typeof response.headersSent !== "boolean") {
  166. throw new import_js_format3.InvalidArgumentError(
  167. 'The first parameter of "isResponseSent" must be an instance of ServerResponse, but %v was given.',
  168. response
  169. );
  170. }
  171. return response.headersSent;
  172. }
  173. __name(isResponseSent, "isResponseSent");
  174. // src/utils/create-route-mock.js
  175. function createRouteMock(options = {}) {
  176. return new Route({
  177. method: options.method || HttpMethod.GET,
  178. path: options.path || "/",
  179. handler: options.handler || (() => "OK")
  180. });
  181. }
  182. __name(createRouteMock, "createRouteMock");
  183. // src/utils/is-readable-stream.js
  184. function isReadableStream(value) {
  185. if (!value || typeof value !== "object") {
  186. return false;
  187. }
  188. return typeof value.pipe === "function";
  189. }
  190. __name(isReadableStream, "isReadableStream");
  191. // src/utils/parse-content-type.js
  192. var import_js_format4 = require("@e22m4u/js-format");
  193. function parseContentType(input) {
  194. if (typeof input !== "string") {
  195. throw new import_js_format4.InvalidArgumentError(
  196. "The first parameter of `parseContentType` must be a String, but %v was given.",
  197. input
  198. );
  199. }
  200. const res = { mediaType: void 0, charset: void 0, boundary: void 0 };
  201. const re = /^\s*([^\s;/]+\/[^\s;/]+)(?:;\s*charset=([^\s;]+))?(?:;\s*boundary=([^\s;]+))?.*$/i;
  202. const matches = re.exec(input);
  203. if (matches && matches[1]) {
  204. res.mediaType = matches[1];
  205. if (matches[2]) {
  206. res.charset = matches[2];
  207. }
  208. if (matches[3]) {
  209. res.boundary = matches[3];
  210. }
  211. }
  212. return res;
  213. }
  214. __name(parseContentType, "parseContentType");
  215. // src/utils/is-writable-stream.js
  216. function isWritableStream(value) {
  217. if (!value || typeof value !== "object") {
  218. return false;
  219. }
  220. return typeof value.end === "function";
  221. }
  222. __name(isWritableStream, "isWritableStream");
  223. // src/utils/fetch-request-body.js
  224. var import_http_errors = __toESM(require("http-errors"), 1);
  225. var import_http = require("http");
  226. var import_js_format5 = require("@e22m4u/js-format");
  227. var CHARACTER_ENCODING_LIST = [
  228. "ascii",
  229. "utf8",
  230. "utf-8",
  231. "utf16le",
  232. "utf-16le",
  233. "ucs2",
  234. "ucs-2",
  235. "latin1"
  236. ];
  237. function fetchRequestBody(request, bodyBytesLimit = 0) {
  238. if (!(request instanceof import_http.IncomingMessage)) {
  239. throw new import_js_format5.InvalidArgumentError(
  240. 'The first parameter of "fetchRequestBody" must be an IncomingMessage instance, but %v was given.',
  241. request
  242. );
  243. }
  244. if (typeof bodyBytesLimit !== "number") {
  245. throw new import_js_format5.InvalidArgumentError(
  246. 'The parameter "bodyBytesLimit" of "fetchRequestBody" must be a number, but %v was given.',
  247. bodyBytesLimit
  248. );
  249. }
  250. return new Promise((resolve, reject) => {
  251. const contentLength = parseInt(
  252. request.headers["content-length"] || "0",
  253. 10
  254. );
  255. if (bodyBytesLimit && contentLength && contentLength > bodyBytesLimit) {
  256. throw createError(
  257. import_http_errors.default.PayloadTooLarge,
  258. "Request body limit is %s bytes, but %s bytes given.",
  259. bodyBytesLimit,
  260. contentLength
  261. );
  262. }
  263. let encoding = "utf-8";
  264. const contentType = request.headers["content-type"] || "";
  265. if (contentType) {
  266. const parsedContentType = parseContentType(contentType);
  267. if (parsedContentType && parsedContentType.charset) {
  268. encoding = parsedContentType.charset.toLowerCase();
  269. if (!CHARACTER_ENCODING_LIST.includes(encoding)) {
  270. throw createError(
  271. import_http_errors.default.UnsupportedMediaType,
  272. "Request encoding %v is not supported.",
  273. encoding
  274. );
  275. }
  276. }
  277. }
  278. const data = [];
  279. let receivedLength = 0;
  280. const onData = /* @__PURE__ */ __name((chunk) => {
  281. receivedLength += chunk.length;
  282. if (bodyBytesLimit && receivedLength > bodyBytesLimit) {
  283. request.removeAllListeners();
  284. const error = createError(
  285. import_http_errors.default.PayloadTooLarge,
  286. "Request body limit is %v bytes, but %v bytes given.",
  287. bodyBytesLimit,
  288. receivedLength
  289. );
  290. reject(error);
  291. return;
  292. }
  293. data.push(chunk);
  294. }, "onData");
  295. const onEnd = /* @__PURE__ */ __name(() => {
  296. request.removeAllListeners();
  297. if (contentLength && contentLength !== receivedLength) {
  298. const error = createError(
  299. import_http_errors.default.BadRequest,
  300. 'Received bytes do not match the "content-length" header.'
  301. );
  302. reject(error);
  303. return;
  304. }
  305. const buffer = Buffer.concat(data);
  306. const body = buffer.toString(encoding);
  307. resolve(body || void 0);
  308. }, "onEnd");
  309. const onError = /* @__PURE__ */ __name((error) => {
  310. request.removeAllListeners();
  311. reject((0, import_http_errors.default)(400, error));
  312. }, "onError");
  313. request.on("data", onData);
  314. request.on("end", onEnd);
  315. request.on("error", onError);
  316. request.resume();
  317. });
  318. }
  319. __name(fetchRequestBody, "fetchRequestBody");
  320. // src/utils/parse-cookie-string.js
  321. var import_js_format6 = require("@e22m4u/js-format");
  322. function parseCookieString(input) {
  323. if (typeof input !== "string") {
  324. throw new import_js_format6.InvalidArgumentError(
  325. 'The first parameter of "parseCookieString" must be a String, but %v was given.',
  326. input
  327. );
  328. }
  329. return input.split(";").filter((v) => v !== "").map((v) => v.split("=")).reduce((cookies, tuple) => {
  330. const key = decodeURIComponent(tuple[0]).trim();
  331. const value = tuple[1] !== void 0 ? decodeURIComponent(tuple[1]).trim() : "";
  332. cookies[key] = value;
  333. return cookies;
  334. }, {});
  335. }
  336. __name(parseCookieString, "parseCookieString");
  337. // src/utils/create-request-mock.js
  338. var import_net = require("net");
  339. var import_tls = require("tls");
  340. var import_http2 = require("http");
  341. var import_querystring = __toESM(require("querystring"), 1);
  342. var import_js_format8 = require("@e22m4u/js-format");
  343. // src/utils/create-cookie-string.js
  344. var import_js_format7 = require("@e22m4u/js-format");
  345. function createCookieString(data) {
  346. if (!data || typeof data !== "object" || Array.isArray(data)) {
  347. throw new import_js_format7.InvalidArgumentError(
  348. 'The first parameter of "createCookieString" must be an Object, but %v was given.',
  349. data
  350. );
  351. }
  352. let cookies = "";
  353. for (const key in data) {
  354. if (!Object.prototype.hasOwnProperty.call(data, key)) {
  355. continue;
  356. }
  357. const val = data[key];
  358. if (val == null) {
  359. continue;
  360. }
  361. cookies += `${key}=${val}; `;
  362. }
  363. return cookies.trim();
  364. }
  365. __name(createCookieString, "createCookieString");
  366. // src/utils/create-request-mock.js
  367. function createRequestMock(patch) {
  368. if (patch != null && typeof patch !== "object" || Array.isArray(patch)) {
  369. throw new import_js_format8.InvalidArgumentError(
  370. 'The first parameter of "createRequestMock" must be an Object, but %v was given.',
  371. patch
  372. );
  373. }
  374. patch = patch || {};
  375. if (patch.host != null && typeof patch.host !== "string") {
  376. throw new import_js_format8.InvalidArgumentError(
  377. 'The parameter "host" of "createRequestMock" must be a String, but %v was given.',
  378. patch.host
  379. );
  380. }
  381. if (patch.method != null && typeof patch.method !== "string") {
  382. throw new import_js_format8.InvalidArgumentError(
  383. 'The parameter "method" of "createRequestMock" must be a String, but %v was given.',
  384. patch.method
  385. );
  386. }
  387. if (patch.secure != null && typeof patch.secure !== "boolean") {
  388. throw new import_js_format8.InvalidArgumentError(
  389. 'The parameter "secure" of "createRequestMock" must be a Boolean, but %v was given.',
  390. patch.secure
  391. );
  392. }
  393. if (patch.path != null && typeof patch.path !== "string") {
  394. throw new import_js_format8.InvalidArgumentError(
  395. 'The parameter "path" of "createRequestMock" must be a String, but %v was given.',
  396. patch.path
  397. );
  398. }
  399. if (patch.query != null && typeof patch.query !== "object" && typeof patch.query !== "string" || Array.isArray(patch.query)) {
  400. throw new import_js_format8.InvalidArgumentError(
  401. 'The parameter "query" of "createRequestMock" must be a String or Object, but %v was given.',
  402. patch.query
  403. );
  404. }
  405. if (patch.cookies != null && typeof patch.cookies !== "string" && typeof patch.cookies !== "object" || Array.isArray(patch.cookies)) {
  406. throw new import_js_format8.InvalidArgumentError(
  407. 'The parameter "cookies" of "createRequestMock" must be a String or Object, but %v was given.',
  408. patch.cookies
  409. );
  410. }
  411. if (patch.headers != null && typeof patch.headers !== "object" || Array.isArray(patch.headers)) {
  412. throw new import_js_format8.InvalidArgumentError(
  413. 'The parameter "headers" of "createRequestMock" must be an Object, but %v was given.',
  414. patch.headers
  415. );
  416. }
  417. if (patch.stream != null && !isReadableStream(patch.stream)) {
  418. throw new import_js_format8.InvalidArgumentError(
  419. 'The parameter "stream" of "createRequestMock" must be a Stream, but %v was given.',
  420. patch.stream
  421. );
  422. }
  423. if (patch.encoding != null) {
  424. if (typeof patch.encoding !== "string") {
  425. throw new import_js_format8.InvalidArgumentError(
  426. 'The parameter "encoding" of "createRequestMock" must be a String, but %v was given.',
  427. patch.encoding
  428. );
  429. }
  430. if (!CHARACTER_ENCODING_LIST.includes(patch.encoding)) {
  431. throw new import_js_format8.InvalidArgumentError(
  432. "Character encoding %v is not supported.",
  433. patch.encoding
  434. );
  435. }
  436. }
  437. if (patch.stream) {
  438. if (patch.secure != null) {
  439. throw new import_js_format8.InvalidArgumentError(
  440. 'The "createRequestMock" does not allow specifying the "stream" and "secure" options simultaneously.'
  441. );
  442. }
  443. if (patch.body != null) {
  444. throw new import_js_format8.InvalidArgumentError(
  445. 'The "createRequestMock" does not allow specifying the "stream" and "body" options simultaneously.'
  446. );
  447. }
  448. if (patch.encoding != null) {
  449. throw new import_js_format8.InvalidArgumentError(
  450. 'The "createRequestMock" does not allow specifying the "stream" and "encoding" options simultaneously.'
  451. );
  452. }
  453. }
  454. const request = patch.stream || createRequestStream(patch.secure, patch.body, patch.encoding);
  455. request.url = createRequestUrl(patch.path || "/", patch.query);
  456. request.headers = createRequestHeaders(
  457. patch.host,
  458. patch.secure,
  459. patch.body,
  460. patch.cookies,
  461. patch.encoding,
  462. patch.headers
  463. );
  464. request.method = (patch.method || "get").toUpperCase();
  465. return request;
  466. }
  467. __name(createRequestMock, "createRequestMock");
  468. function createRequestStream(secure, body, encoding) {
  469. if (encoding != null && typeof encoding !== "string") {
  470. throw new import_js_format8.InvalidArgumentError(
  471. 'The parameter "encoding" of "createRequestStream" must be a String, but %v was given.',
  472. encoding
  473. );
  474. }
  475. encoding = encoding || "utf-8";
  476. let socket = new import_net.Socket();
  477. if (secure) {
  478. socket = new import_tls.TLSSocket(socket);
  479. }
  480. const request = new import_http2.IncomingMessage(socket);
  481. if (body != null) {
  482. if (typeof body === "string") {
  483. request.push(body, encoding);
  484. } else if (Buffer.isBuffer(body)) {
  485. request.push(body);
  486. } else {
  487. request.push(JSON.stringify(body));
  488. }
  489. }
  490. request.push(null);
  491. return request;
  492. }
  493. __name(createRequestStream, "createRequestStream");
  494. function createRequestUrl(path, query) {
  495. if (typeof path !== "string") {
  496. throw new import_js_format8.InvalidArgumentError(
  497. 'The parameter "path" of "createRequestUrl" must be a String, but %v was given.',
  498. path
  499. );
  500. }
  501. if (query != null && typeof query !== "string" && typeof query !== "object" || Array.isArray(query)) {
  502. throw new import_js_format8.InvalidArgumentError(
  503. 'The parameter "query" of "createRequestUrl" must be a String or Object, but %v was given.',
  504. query
  505. );
  506. }
  507. let url = ("/" + path).replace("//", "/");
  508. if (typeof query === "object") {
  509. const qs = import_querystring.default.stringify(query);
  510. if (qs) {
  511. url += `?${qs}`;
  512. }
  513. } else if (typeof query === "string") {
  514. url += `?${query.replace(/^\?/, "")}`;
  515. }
  516. return url;
  517. }
  518. __name(createRequestUrl, "createRequestUrl");
  519. function createRequestHeaders(host, secure, body, cookies, encoding, headers) {
  520. if (host != null && typeof host !== "string") {
  521. throw new import_js_format8.InvalidArgumentError(
  522. 'The parameter "host" of "createRequestHeaders" a non-empty String, but %v was given.',
  523. host
  524. );
  525. }
  526. host = host || "localhost";
  527. if (secure != null && typeof secure !== "boolean") {
  528. throw new import_js_format8.InvalidArgumentError(
  529. 'The parameter "secure" of "createRequestHeaders" must be a String, but %v was given.',
  530. secure
  531. );
  532. }
  533. secure = Boolean(secure);
  534. if (cookies != null && typeof cookies !== "object" && typeof cookies !== "string" || Array.isArray(cookies)) {
  535. throw new import_js_format8.InvalidArgumentError(
  536. 'The parameter "cookies" of "createRequestHeaders" must be a String or Object, but %v was given.',
  537. cookies
  538. );
  539. }
  540. if (headers != null && typeof headers !== "object" || Array.isArray(headers)) {
  541. throw new import_js_format8.InvalidArgumentError(
  542. 'The parameter "headers" of "createRequestHeaders" must be an Object, but %v was given.',
  543. headers
  544. );
  545. }
  546. headers = headers || {};
  547. if (encoding != null && typeof encoding !== "string") {
  548. throw new import_js_format8.InvalidArgumentError(
  549. 'The parameter "encoding" of "createRequestHeaders" must be a String, but %v was given.',
  550. encoding
  551. );
  552. }
  553. encoding = encoding || "utf-8";
  554. const obj = { ...headers };
  555. obj["host"] = host;
  556. if (secure) {
  557. obj["x-forwarded-proto"] = "https";
  558. }
  559. if (cookies != null) {
  560. if (typeof cookies === "string") {
  561. obj["cookie"] = obj["cookie"] ? obj["cookie"] : "";
  562. obj["cookie"] += obj["cookie"] ? `; ${cookies}` : cookies;
  563. } else if (typeof cookies === "object") {
  564. obj["cookie"] = obj["cookie"] ? obj["cookie"] : "";
  565. const newCookies = createCookieString(cookies);
  566. obj["cookie"] += obj["cookie"] ? `; ${newCookies}` : newCookies;
  567. }
  568. }
  569. if (obj["content-type"] == null) {
  570. if (typeof body === "string") {
  571. obj["content-type"] = "text/plain";
  572. } else if (Buffer.isBuffer(body)) {
  573. obj["content-type"] = "application/octet-stream";
  574. } else if (typeof body === "object" || typeof body === "boolean" || typeof body === "number") {
  575. obj["content-type"] = "application/json";
  576. }
  577. }
  578. if (body != null && obj["content-length"] == null) {
  579. if (typeof body === "string") {
  580. const length = Buffer.byteLength(body, encoding);
  581. obj["content-length"] = String(length);
  582. } else if (Buffer.isBuffer(body)) {
  583. const length = Buffer.byteLength(body);
  584. obj["content-length"] = String(length);
  585. } else if (typeof body === "object" || typeof body === "boolean" || typeof body === "number") {
  586. const json = JSON.stringify(body);
  587. const length = Buffer.byteLength(json, encoding);
  588. obj["content-length"] = String(length);
  589. }
  590. }
  591. return obj;
  592. }
  593. __name(createRequestHeaders, "createRequestHeaders");
  594. // src/utils/create-response-mock.js
  595. var import_stream = require("stream");
  596. function createResponseMock() {
  597. const response = new import_stream.PassThrough();
  598. patchEncoding(response);
  599. patchHeaders(response);
  600. patchBody(response);
  601. return response;
  602. }
  603. __name(createResponseMock, "createResponseMock");
  604. function patchEncoding(response) {
  605. Object.defineProperty(response, "_encoding", {
  606. configurable: true,
  607. writable: true,
  608. value: void 0
  609. });
  610. Object.defineProperty(response, "setEncoding", {
  611. configurable: true,
  612. value: /* @__PURE__ */ __name(function(enc) {
  613. this._encoding = enc;
  614. return this;
  615. }, "value")
  616. });
  617. Object.defineProperty(response, "getEncoding", {
  618. configurable: true,
  619. value: /* @__PURE__ */ __name(function() {
  620. return this._encoding;
  621. }, "value")
  622. });
  623. }
  624. __name(patchEncoding, "patchEncoding");
  625. function patchHeaders(response) {
  626. Object.defineProperty(response, "_headersSent", {
  627. configurable: true,
  628. writable: true,
  629. value: false
  630. });
  631. Object.defineProperty(response, "headersSent", {
  632. configurable: true,
  633. get() {
  634. return this._headersSent;
  635. }
  636. });
  637. Object.defineProperty(response, "_headers", {
  638. configurable: true,
  639. writable: true,
  640. value: {}
  641. });
  642. Object.defineProperty(response, "setHeader", {
  643. configurable: true,
  644. value: /* @__PURE__ */ __name(function(name, value) {
  645. if (this.headersSent) {
  646. throw new Error(
  647. "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"
  648. );
  649. }
  650. const key = name.toLowerCase();
  651. this._headers[key] = String(value);
  652. return this;
  653. }, "value")
  654. });
  655. Object.defineProperty(response, "getHeader", {
  656. configurable: true,
  657. value: /* @__PURE__ */ __name(function(name) {
  658. return this._headers[name.toLowerCase()];
  659. }, "value")
  660. });
  661. Object.defineProperty(response, "getHeaders", {
  662. configurable: true,
  663. value: /* @__PURE__ */ __name(function() {
  664. return JSON.parse(JSON.stringify(this._headers));
  665. }, "value")
  666. });
  667. }
  668. __name(patchHeaders, "patchHeaders");
  669. function patchBody(response) {
  670. let resolve, reject;
  671. const promise = new Promise((rsv, rej) => {
  672. resolve = rsv;
  673. reject = rej;
  674. });
  675. const data = [];
  676. response.on("data", (c) => data.push(c));
  677. response.on("error", (e) => reject(e));
  678. response.on("end", () => {
  679. resolve(Buffer.concat(data));
  680. });
  681. const originalEnd = response.end.bind(response);
  682. response.end = function(...args) {
  683. this._headersSent = true;
  684. return originalEnd(...args);
  685. };
  686. Object.defineProperty(response, "getBody", {
  687. configurable: true,
  688. value: /* @__PURE__ */ __name(function() {
  689. return promise.then((buffer) => {
  690. const enc = this.getEncoding();
  691. const str = buffer.toString(enc);
  692. return data.length ? str : void 0;
  693. });
  694. }, "value")
  695. });
  696. }
  697. __name(patchBody, "patchBody");
  698. // src/utils/get-request-pathname.js
  699. var import_js_format9 = require("@e22m4u/js-format");
  700. function getRequestPathname(request) {
  701. if (!request || typeof request !== "object" || Array.isArray(request) || typeof request.url !== "string") {
  702. throw new import_js_format9.InvalidArgumentError(
  703. 'The first parameter of "getRequestPathname" must be an instance of IncomingMessage, but %v was given.',
  704. request
  705. );
  706. }
  707. return (request.url || "/").replace(/\?.*$/, "");
  708. }
  709. __name(getRequestPathname, "getRequestPathname");
  710. // src/hooks/hook-registry.js
  711. var import_js_format10 = require("@e22m4u/js-format");
  712. var RouterHookType = {
  713. PRE_HANDLER: "preHandler",
  714. POST_HANDLER: "postHandler"
  715. };
  716. var _HookRegistry = class _HookRegistry {
  717. /**
  718. * Hooks.
  719. *
  720. * @type {Map<string, Function[]>}
  721. * @private
  722. */
  723. _hooks = /* @__PURE__ */ new Map();
  724. /**
  725. * Add hook.
  726. *
  727. * @param {string} type
  728. * @param {Function} hook
  729. * @returns {this}
  730. */
  731. addHook(type, hook) {
  732. if (!type || typeof type !== "string") {
  733. throw new import_js_format10.InvalidArgumentError(
  734. "The hook type is required, but %v was given.",
  735. type
  736. );
  737. }
  738. if (!Object.values(RouterHookType).includes(type)) {
  739. throw new import_js_format10.InvalidArgumentError(
  740. "The hook type %v is not supported.",
  741. type
  742. );
  743. }
  744. if (!hook || typeof hook !== "function") {
  745. throw new import_js_format10.InvalidArgumentError(
  746. "The hook %v must be a Function, but %v was given.",
  747. type,
  748. hook
  749. );
  750. }
  751. const hooks = this._hooks.get(type) || [];
  752. hooks.push(hook);
  753. this._hooks.set(type, hooks);
  754. return this;
  755. }
  756. /**
  757. * Has hook.
  758. *
  759. * @param {string} type
  760. * @param {Function} hook
  761. * @returns {boolean}
  762. */
  763. hasHook(type, hook) {
  764. if (!type || typeof type !== "string") {
  765. throw new import_js_format10.InvalidArgumentError(
  766. "The hook type is required, but %v was given.",
  767. type
  768. );
  769. }
  770. if (!Object.values(RouterHookType).includes(type)) {
  771. throw new import_js_format10.InvalidArgumentError(
  772. "The hook type %v is not supported.",
  773. type
  774. );
  775. }
  776. if (!hook || typeof hook !== "function") {
  777. throw new import_js_format10.InvalidArgumentError(
  778. "The hook %v must be a Function, but %v was given.",
  779. type,
  780. hook
  781. );
  782. }
  783. const hooks = this._hooks.get(type) || [];
  784. return hooks.indexOf(hook) > -1;
  785. }
  786. /**
  787. * Get hooks.
  788. *
  789. * @param {string} type
  790. * @returns {Function[]}
  791. */
  792. getHooks(type) {
  793. if (!type || typeof type !== "string") {
  794. throw new import_js_format10.InvalidArgumentError(
  795. "The hook type is required, but %v was given.",
  796. type
  797. );
  798. }
  799. if (!Object.values(RouterHookType).includes(type)) {
  800. throw new import_js_format10.InvalidArgumentError(
  801. "The hook type %v is not supported.",
  802. type
  803. );
  804. }
  805. return this._hooks.get(type) || [];
  806. }
  807. };
  808. __name(_HookRegistry, "HookRegistry");
  809. var HookRegistry = _HookRegistry;
  810. // src/hooks/hook-invoker.js
  811. var _HookInvoker = class _HookInvoker extends DebuggableService {
  812. /**
  813. * Invoke and continue until value received.
  814. *
  815. * @param {Route} route
  816. * @param {string} hookType
  817. * @param {import('http').ServerResponse} response
  818. * @param {*[]} args
  819. * @returns {Promise<*>|*}
  820. */
  821. invokeAndContinueUntilValueReceived(route, hookType, response, ...args) {
  822. if (!route || !(route instanceof Route)) {
  823. throw new import_js_format11.InvalidArgumentError(
  824. 'The parameter "route" of the HookInvoker.invokeAndContinueUntilValueReceived must be a Route instance, but %v was given.',
  825. route
  826. );
  827. }
  828. if (!hookType || typeof hookType !== "string") {
  829. throw new import_js_format11.InvalidArgumentError(
  830. 'The parameter "hookType" of the HookInvoker.invokeAndContinueUntilValueReceived must be a non-empty String, but %v was given.',
  831. hookType
  832. );
  833. }
  834. if (!Object.values(RouterHookType).includes(hookType)) {
  835. throw new import_js_format11.InvalidArgumentError(
  836. "The hook type %v is not supported.",
  837. hookType
  838. );
  839. }
  840. if (!response || typeof response !== "object" || Array.isArray(response) || typeof response.headersSent !== "boolean") {
  841. throw new import_js_format11.InvalidArgumentError(
  842. 'The parameter "response" of the HookInvoker.invokeAndContinueUntilValueReceived must be a ServerResponse instance, but %v was given.',
  843. response
  844. );
  845. }
  846. if (isResponseSent(response)) {
  847. return response;
  848. }
  849. const hooks = [
  850. ...this.getService(HookRegistry).getHooks(hookType),
  851. ...route.hookRegistry.getHooks(hookType)
  852. ];
  853. let result = void 0;
  854. for (let i = 0; i < hooks.length; i++) {
  855. const hook = hooks[i];
  856. result = hook(...args);
  857. if (isResponseSent(response)) {
  858. return response;
  859. }
  860. if (result != null) {
  861. if (isPromise(result)) {
  862. return (async () => {
  863. let asyncResult = await result;
  864. if (isResponseSent(response)) {
  865. return response;
  866. }
  867. if (asyncResult != null) {
  868. return asyncResult;
  869. }
  870. for (let j = i + 1; j < hooks.length; j++) {
  871. asyncResult = await hooks[j](...args);
  872. if (isResponseSent(response)) {
  873. return response;
  874. }
  875. if (asyncResult != null) {
  876. return asyncResult;
  877. }
  878. }
  879. return;
  880. })();
  881. }
  882. return result;
  883. }
  884. }
  885. return;
  886. }
  887. };
  888. __name(_HookInvoker, "HookInvoker");
  889. var HookInvoker = _HookInvoker;
  890. // src/route/validate-route-definition.js
  891. var import_js_format12 = require("@e22m4u/js-format");
  892. function validateRouteDefinition(routeDef) {
  893. if (!routeDef || typeof routeDef !== "object" || Array.isArray(routeDef)) {
  894. throw new import_js_format12.InvalidArgumentError(
  895. "Route definition must be an Object, but %v was given.",
  896. routeDef
  897. );
  898. }
  899. if (!routeDef.method || typeof routeDef.method !== "string") {
  900. throw new import_js_format12.InvalidArgumentError(
  901. 'Option "method" must be a non-empty String, but %v was given.',
  902. routeDef.method
  903. );
  904. }
  905. if (typeof routeDef.path !== "string") {
  906. throw new import_js_format12.InvalidArgumentError(
  907. 'Option "path" must be a String, but %v was given.',
  908. routeDef.path
  909. );
  910. }
  911. if (typeof routeDef.handler !== "function") {
  912. throw new import_js_format12.InvalidArgumentError(
  913. 'Option "handler" must be a Function, but %v was given.',
  914. routeDef.handler
  915. );
  916. }
  917. if (routeDef.meta !== void 0) {
  918. if (!routeDef.meta || typeof routeDef.meta !== "object" || Array.isArray(routeDef.meta)) {
  919. throw new import_js_format12.InvalidArgumentError(
  920. 'Option "meta" must be an Object, but %v was given.',
  921. routeDef.meta
  922. );
  923. }
  924. }
  925. }
  926. __name(validateRouteDefinition, "validateRouteDefinition");
  927. // src/route/route.js
  928. var HttpMethod = {
  929. GET: "GET",
  930. POST: "POST",
  931. PUT: "PUT",
  932. PATCH: "PATCH",
  933. DELETE: "DELETE"
  934. };
  935. var _Route = class _Route extends import_js_debug.Debuggable {
  936. /**
  937. * Method.
  938. *
  939. * @type {string}
  940. * @private
  941. */
  942. _method;
  943. /**
  944. * Getter of the method.
  945. *
  946. * @returns {string}
  947. */
  948. get method() {
  949. return this._method;
  950. }
  951. /**
  952. * Path template.
  953. *
  954. * @type {string}
  955. * @private
  956. */
  957. _path;
  958. /**
  959. * Getter of the path.
  960. *
  961. * @returns {string}
  962. */
  963. get path() {
  964. return this._path;
  965. }
  966. /**
  967. * Meta.
  968. *
  969. * @type {object}
  970. */
  971. _meta = {};
  972. /**
  973. * Getter of the meta.
  974. *
  975. * @returns {object}
  976. */
  977. get meta() {
  978. return this._meta;
  979. }
  980. /**
  981. * Handler.
  982. *
  983. * @type {RouteHandler}
  984. * @private
  985. */
  986. _handler;
  987. /**
  988. * Getter of the handler.
  989. *
  990. * @returns {*}
  991. */
  992. get handler() {
  993. return this._handler;
  994. }
  995. /**
  996. * Hook registry.
  997. *
  998. * @type {HookRegistry}
  999. * @private
  1000. */
  1001. _hookRegistry = new HookRegistry();
  1002. /**
  1003. * Getter of the hook registry.
  1004. *
  1005. * @returns {HookRegistry}
  1006. */
  1007. get hookRegistry() {
  1008. return this._hookRegistry;
  1009. }
  1010. /**
  1011. * Constructor.
  1012. *
  1013. * @param {RouteDefinition} routeDef
  1014. */
  1015. constructor(routeDef) {
  1016. super({
  1017. namespace: MODULE_DEBUG_NAMESPACE,
  1018. noEnvironmentNamespace: true,
  1019. noInstantiationMessage: true
  1020. });
  1021. validateRouteDefinition(routeDef);
  1022. this._method = routeDef.method.toUpperCase();
  1023. this._path = routeDef.path;
  1024. if (routeDef.meta !== void 0) {
  1025. this._meta = cloneDeep(routeDef.meta);
  1026. }
  1027. this._handler = routeDef.handler;
  1028. if (routeDef.preHandler != null) {
  1029. const preHandlerHooks = Array.isArray(routeDef.preHandler) ? routeDef.preHandler : [routeDef.preHandler];
  1030. preHandlerHooks.forEach((hook) => {
  1031. this._hookRegistry.addHook(RouterHookType.PRE_HANDLER, hook);
  1032. });
  1033. }
  1034. if (routeDef.postHandler != null) {
  1035. const postHandlerHooks = Array.isArray(routeDef.postHandler) ? routeDef.postHandler : [routeDef.postHandler];
  1036. postHandlerHooks.forEach((hook) => {
  1037. this._hookRegistry.addHook(RouterHookType.POST_HANDLER, hook);
  1038. });
  1039. }
  1040. this.ctorDebug("A new route %s %v was created.", this._method, this._path);
  1041. }
  1042. /**
  1043. * Handle request.
  1044. *
  1045. * @param {RequestContext} context
  1046. * @returns {*}
  1047. */
  1048. handle(context) {
  1049. const debug = this.getDebuggerFor(this.handle);
  1050. const requestPath = getRequestPathname(context.request);
  1051. debug(
  1052. "Invoking the Route handler for the request %s %v.",
  1053. this.method.toUpperCase(),
  1054. requestPath
  1055. );
  1056. return this._handler(context);
  1057. }
  1058. };
  1059. __name(_Route, "Route");
  1060. var Route = _Route;
  1061. // src/parsers/body-parser.js
  1062. var import_http_errors2 = __toESM(require("http-errors"), 1);
  1063. // src/router-options.js
  1064. var import_js_format13 = require("@e22m4u/js-format");
  1065. var _RouterOptions = class _RouterOptions extends DebuggableService {
  1066. /**
  1067. * Request body bytes limit.
  1068. *
  1069. * @type {number}
  1070. * @private
  1071. */
  1072. _requestBodyBytesLimit = 512e3;
  1073. // 512kb
  1074. /**
  1075. * Getter of request body bytes limit.
  1076. *
  1077. * @returns {number}
  1078. */
  1079. get requestBodyBytesLimit() {
  1080. return this._requestBodyBytesLimit;
  1081. }
  1082. /**
  1083. * Set request body bytes limit.
  1084. *
  1085. * @param {number} input
  1086. * @returns {RouterOptions}
  1087. */
  1088. setRequestBodyBytesLimit(input) {
  1089. if (typeof input !== "number" || input < 0) {
  1090. throw new import_js_format13.InvalidArgumentError(
  1091. 'The option "requestBodyBytesLimit" must be a positive Number or 0, but %v was given.',
  1092. input
  1093. );
  1094. }
  1095. this._requestBodyBytesLimit = input;
  1096. return this;
  1097. }
  1098. };
  1099. __name(_RouterOptions, "RouterOptions");
  1100. var RouterOptions = _RouterOptions;
  1101. // src/parsers/body-parser.js
  1102. var import_js_format14 = require("@e22m4u/js-format");
  1103. var METHODS_WITH_BODY = ["POST", "PUT", "PATCH", "DELETE"];
  1104. var UNPARSABLE_MEDIA_TYPES = ["multipart/form-data"];
  1105. var _BodyParser = class _BodyParser extends DebuggableService {
  1106. /**
  1107. * Parsers.
  1108. *
  1109. * @type {{[mime: string]: Function}}
  1110. */
  1111. _parsers = {
  1112. "text/plain": /* @__PURE__ */ __name((v) => String(v), "text/plain"),
  1113. "application/json": parseJsonBody
  1114. };
  1115. /**
  1116. * Set parser.
  1117. *
  1118. * @param {string} mediaType
  1119. * @param {Function} parser
  1120. * @returns {this}
  1121. */
  1122. defineParser(mediaType, parser) {
  1123. if (!mediaType || typeof mediaType !== "string") {
  1124. throw new import_js_format14.InvalidArgumentError(
  1125. 'The parameter "mediaType" of BodyParser.defineParser must be a non-empty String, but %v was given.',
  1126. mediaType
  1127. );
  1128. }
  1129. if (!parser || typeof parser !== "function") {
  1130. throw new import_js_format14.InvalidArgumentError(
  1131. 'The parameter "parser" of BodyParser.defineParser must be a Function, but %v was given.',
  1132. parser
  1133. );
  1134. }
  1135. this._parsers[mediaType] = parser;
  1136. return this;
  1137. }
  1138. /**
  1139. * Has parser.
  1140. *
  1141. * @param {string} mediaType
  1142. * @returns {boolean}
  1143. */
  1144. hasParser(mediaType) {
  1145. if (!mediaType || typeof mediaType !== "string") {
  1146. throw new import_js_format14.InvalidArgumentError(
  1147. 'The parameter "mediaType" of BodyParser.hasParser must be a non-empty String, but %v was given.',
  1148. mediaType
  1149. );
  1150. }
  1151. return Boolean(this._parsers[mediaType]);
  1152. }
  1153. /**
  1154. * Delete parser.
  1155. *
  1156. * @param {string} mediaType
  1157. * @returns {this}
  1158. */
  1159. deleteParser(mediaType) {
  1160. if (!mediaType || typeof mediaType !== "string") {
  1161. throw new import_js_format14.InvalidArgumentError(
  1162. 'The parameter "mediaType" of BodyParser.deleteParser must be a non-empty String, but %v was given.',
  1163. mediaType
  1164. );
  1165. }
  1166. const parser = this._parsers[mediaType];
  1167. if (!parser) {
  1168. throw new import_js_format14.InvalidArgumentError(
  1169. "The parser of %v is not found.",
  1170. mediaType
  1171. );
  1172. }
  1173. delete this._parsers[mediaType];
  1174. return this;
  1175. }
  1176. /**
  1177. * Parse.
  1178. *
  1179. * @param {import('http').IncomingMessage} request
  1180. * @returns {Promise<*>|undefined}
  1181. */
  1182. parse(request) {
  1183. const debug = this.getDebuggerFor(this.parse);
  1184. if (!METHODS_WITH_BODY.includes(request.method.toUpperCase())) {
  1185. debug(
  1186. "Body parsing was skipped for the %s request.",
  1187. request.method.toUpperCase()
  1188. );
  1189. return;
  1190. }
  1191. const contentType = (request.headers["content-type"] || "").replace(
  1192. /^([^;]+);.*$/,
  1193. "$1"
  1194. );
  1195. if (!contentType) {
  1196. debug(
  1197. "Body parsing was skipped because the request had no content type."
  1198. );
  1199. return;
  1200. }
  1201. const { mediaType } = parseContentType(contentType);
  1202. if (!mediaType) {
  1203. throw createError(
  1204. import_http_errors2.default.BadRequest,
  1205. 'Unable to parse the "content-type" header.'
  1206. );
  1207. }
  1208. const parser = this._parsers[mediaType];
  1209. if (!parser) {
  1210. if (UNPARSABLE_MEDIA_TYPES.includes(mediaType)) {
  1211. debug("Body parsing was skipped for %v.", mediaType);
  1212. return;
  1213. }
  1214. throw createError(
  1215. import_http_errors2.default.UnsupportedMediaType,
  1216. "Media type %v is not supported.",
  1217. mediaType
  1218. );
  1219. }
  1220. const bodyBytesLimit = this.getService(RouterOptions).requestBodyBytesLimit;
  1221. return fetchRequestBody(request, bodyBytesLimit).then((rawBody) => {
  1222. if (rawBody != null) {
  1223. return parser(rawBody);
  1224. }
  1225. return rawBody;
  1226. });
  1227. }
  1228. };
  1229. __name(_BodyParser, "BodyParser");
  1230. var BodyParser = _BodyParser;
  1231. function parseJsonBody(input) {
  1232. if (typeof input !== "string") {
  1233. return void 0;
  1234. }
  1235. try {
  1236. return JSON.parse(input);
  1237. } catch (error) {
  1238. throw createError(import_http_errors2.default.BadRequest, error.message);
  1239. }
  1240. }
  1241. __name(parseJsonBody, "parseJsonBody");
  1242. // src/parsers/query-parser.js
  1243. var import_querystring2 = __toESM(require("querystring"), 1);
  1244. var _QueryParser = class _QueryParser extends DebuggableService {
  1245. /**
  1246. * Parse
  1247. *
  1248. * @param {import('http').IncomingMessage} request
  1249. * @returns {object}
  1250. */
  1251. parse(request) {
  1252. const debug = this.getDebuggerFor(this.parse);
  1253. const queryStr = request.url.replace(/^[^?]*\??/, "");
  1254. const query = queryStr ? import_querystring2.default.parse(queryStr) : {};
  1255. const queryKeys = Object.keys(query);
  1256. if (queryKeys.length) {
  1257. queryKeys.forEach((key) => {
  1258. debug("The query parameter %v had the value %v.", key, query[key]);
  1259. });
  1260. } else {
  1261. debug(
  1262. "The request %s %v had no query parameters.",
  1263. request.method,
  1264. getRequestPathname(request)
  1265. );
  1266. }
  1267. return query;
  1268. }
  1269. };
  1270. __name(_QueryParser, "QueryParser");
  1271. var QueryParser = _QueryParser;
  1272. // src/parsers/cookies-parser.js
  1273. var _CookiesParser = class _CookiesParser extends DebuggableService {
  1274. /**
  1275. * Parse
  1276. *
  1277. * @param {import('http').IncomingMessage} request
  1278. * @returns {object}
  1279. */
  1280. parse(request) {
  1281. const debug = this.getDebuggerFor(this.parse);
  1282. const cookiesString = request.headers["cookie"] || "";
  1283. const cookies = parseCookieString(cookiesString);
  1284. const cookiesKeys = Object.keys(cookies);
  1285. if (cookiesKeys.length) {
  1286. cookiesKeys.forEach((key) => {
  1287. debug("The cookie %v had the value %v.", key, cookies[key]);
  1288. });
  1289. } else {
  1290. debug(
  1291. "The request %s %v had no cookies.",
  1292. request.method,
  1293. getRequestPathname(request)
  1294. );
  1295. }
  1296. return cookies;
  1297. }
  1298. };
  1299. __name(_CookiesParser, "CookiesParser");
  1300. var CookiesParser = _CookiesParser;
  1301. // src/parsers/request-parser.js
  1302. var import_http3 = require("http");
  1303. var import_js_format15 = require("@e22m4u/js-format");
  1304. var _RequestParser = class _RequestParser extends DebuggableService {
  1305. /**
  1306. * Parse.
  1307. *
  1308. * @param {IncomingMessage} request
  1309. * @returns {Promise<object>|object}
  1310. */
  1311. parse(request) {
  1312. if (!(request instanceof import_http3.IncomingMessage)) {
  1313. throw new import_js_format15.InvalidArgumentError(
  1314. "The first parameter of RequestParser.parse must be an instance of IncomingMessage, but %v was given.",
  1315. request
  1316. );
  1317. }
  1318. const data = {};
  1319. const promises = [];
  1320. const parsedQuery = this.getService(QueryParser).parse(request);
  1321. if (isPromise(parsedQuery)) {
  1322. promises.push(parsedQuery.then((v) => data.query = v));
  1323. } else {
  1324. data.query = parsedQuery;
  1325. }
  1326. const parsedCookies = this.getService(CookiesParser).parse(request);
  1327. if (isPromise(parsedCookies)) {
  1328. promises.push(parsedCookies.then((v) => data.cookies = v));
  1329. } else {
  1330. data.cookies = parsedCookies;
  1331. }
  1332. const parsedBody = this.getService(BodyParser).parse(request);
  1333. if (isPromise(parsedBody)) {
  1334. promises.push(parsedBody.then((v) => data.body = v));
  1335. } else {
  1336. data.body = parsedBody;
  1337. }
  1338. data.headers = Object.assign({}, request.headers);
  1339. return promises.length ? Promise.all(promises).then(() => data) : data;
  1340. }
  1341. };
  1342. __name(_RequestParser, "RequestParser");
  1343. var RequestParser = _RequestParser;
  1344. // src/route-registry.js
  1345. var import_js_path_trie = require("@e22m4u/js-path-trie");
  1346. var import_js_service2 = require("@e22m4u/js-service");
  1347. var import_js_format16 = require("@e22m4u/js-format");
  1348. var _RouteRegistry = class _RouteRegistry extends DebuggableService {
  1349. /**
  1350. * Constructor.
  1351. *
  1352. * @param {ServiceContainer} container
  1353. */
  1354. constructor(container) {
  1355. super(container);
  1356. this._trie = new import_js_path_trie.PathTrie();
  1357. }
  1358. /**
  1359. * Define route.
  1360. *
  1361. * @param {import('./route/index.js').RouteDefinition} routeDef
  1362. * @returns {Route}
  1363. */
  1364. defineRoute(routeDef) {
  1365. const debug = this.getDebuggerFor(this.defineRoute);
  1366. if (!routeDef || typeof routeDef !== "object" || Array.isArray(routeDef)) {
  1367. throw new import_js_format16.InvalidArgumentError(
  1368. "The route definition must be an Object, but %v was given.",
  1369. routeDef
  1370. );
  1371. }
  1372. const route = new Route(routeDef);
  1373. const triePath = `${route.method}/${route.path}`;
  1374. this._trie.add(triePath, route);
  1375. debug(
  1376. "The route %s %v was registered.",
  1377. route.method.toUpperCase(),
  1378. route.path
  1379. );
  1380. return route;
  1381. }
  1382. /**
  1383. * Match route by request.
  1384. *
  1385. * @param {import('http').IncomingRequest} request
  1386. * @returns {ResolvedRoute|undefined}
  1387. */
  1388. matchRouteByRequest(request) {
  1389. const debug = this.getDebuggerFor(this.matchRouteByRequest);
  1390. const requestPath = (request.url || "/").replace(/\?.*$/, "");
  1391. debug(
  1392. "Matching routes with the request %s %v.",
  1393. request.method.toUpperCase(),
  1394. requestPath
  1395. );
  1396. const rawTriePath = `${request.method.toUpperCase()}/${requestPath}`;
  1397. const triePath = rawTriePath.replace(/\/+/g, "/");
  1398. const resolved = this._trie.match(triePath);
  1399. if (resolved) {
  1400. const route = resolved.value;
  1401. debug(
  1402. "The route %s %v was matched.",
  1403. route.method.toUpperCase(),
  1404. route.path
  1405. );
  1406. const paramNames = Object.keys(resolved.params);
  1407. if (paramNames.length) {
  1408. paramNames.forEach((name) => {
  1409. debug(
  1410. "The path parameter %v had the value %v.",
  1411. name,
  1412. resolved.params[name]
  1413. );
  1414. });
  1415. } else {
  1416. debug("No path parameters found.");
  1417. }
  1418. return { route, params: resolved.params };
  1419. }
  1420. debug(
  1421. "No matched route for the request %s %v.",
  1422. request.method.toUpperCase(),
  1423. requestPath
  1424. );
  1425. }
  1426. };
  1427. __name(_RouteRegistry, "RouteRegistry");
  1428. var RouteRegistry = _RouteRegistry;
  1429. // src/request-context.js
  1430. var import_js_format17 = require("@e22m4u/js-format");
  1431. var import_js_service3 = require("@e22m4u/js-service");
  1432. var _RequestContext = class _RequestContext {
  1433. /**
  1434. * Service container.
  1435. *
  1436. * @type {ServiceContainer}
  1437. */
  1438. _container;
  1439. /**
  1440. * Getter of service container.
  1441. *
  1442. * @type {ServiceContainer}
  1443. */
  1444. get container() {
  1445. return this._container;
  1446. }
  1447. /**
  1448. * Request.
  1449. *
  1450. * @type {import('http').IncomingMessage}
  1451. */
  1452. _request;
  1453. /**
  1454. * Getter of request.
  1455. *
  1456. * @type {import('http').IncomingMessage}
  1457. */
  1458. get request() {
  1459. return this._request;
  1460. }
  1461. /**
  1462. * Response.
  1463. *
  1464. * @type {import('http').ServerResponse}
  1465. */
  1466. _response;
  1467. /**
  1468. * Getter of response.
  1469. *
  1470. * @type {import('http').ServerResponse}
  1471. */
  1472. get response() {
  1473. return this._response;
  1474. }
  1475. /**
  1476. * Route
  1477. *
  1478. * @type {Route}
  1479. */
  1480. _route;
  1481. /**
  1482. * Getter of route.
  1483. *
  1484. * @type {Route}
  1485. */
  1486. get route() {
  1487. return this._route;
  1488. }
  1489. /**
  1490. * Query.
  1491. *
  1492. * @type {object}
  1493. */
  1494. query = {};
  1495. /**
  1496. * Path parameters.
  1497. *
  1498. * @type {object}
  1499. */
  1500. params = {};
  1501. /**
  1502. * Headers.
  1503. *
  1504. * @type {object}
  1505. */
  1506. headers = {};
  1507. /**
  1508. * Parsed cookies.
  1509. *
  1510. * @type {object}
  1511. */
  1512. cookies = {};
  1513. /**
  1514. * Parsed body.
  1515. *
  1516. * @type {*}
  1517. */
  1518. body;
  1519. /**
  1520. * State.
  1521. *
  1522. * @type {object}
  1523. */
  1524. state = {};
  1525. /**
  1526. * Route meta.
  1527. *
  1528. * @type {import('./route/index.js').RouteMeta}
  1529. */
  1530. get meta() {
  1531. return this.route.meta;
  1532. }
  1533. /**
  1534. * Method.
  1535. *
  1536. * @returns {string}
  1537. */
  1538. get method() {
  1539. return this.request.method.toUpperCase();
  1540. }
  1541. /**
  1542. * Path.
  1543. *
  1544. * @returns {string}
  1545. */
  1546. get path() {
  1547. return this.request.url;
  1548. }
  1549. /**
  1550. * Pathname.
  1551. *
  1552. * @type {string|undefined}
  1553. * @private
  1554. */
  1555. _pathname = void 0;
  1556. /**
  1557. * Pathname.
  1558. *
  1559. * @returns {string}
  1560. */
  1561. get pathname() {
  1562. if (this._pathname != null) {
  1563. return this._pathname;
  1564. }
  1565. this._pathname = getRequestPathname(this.request);
  1566. return this._pathname;
  1567. }
  1568. /**
  1569. * Constructor.
  1570. *
  1571. * @param {ServiceContainer} container
  1572. * @param {import('http').IncomingMessage} request
  1573. * @param {import('http').ServerResponse} response
  1574. * @param {Route} route
  1575. */
  1576. constructor(container, request, response, route) {
  1577. if (!(0, import_js_service3.isServiceContainer)(container)) {
  1578. throw new import_js_format17.InvalidArgumentError(
  1579. 'The parameter "container" of RequestContext.constructor must be an instance of ServiceContainer, but %v was given.',
  1580. container
  1581. );
  1582. }
  1583. this._container = container;
  1584. if (!request || typeof request !== "object" || Array.isArray(request) || !isReadableStream(request)) {
  1585. throw new import_js_format17.InvalidArgumentError(
  1586. 'The parameter "request" of RequestContext.constructor must be an instance of IncomingMessage, but %v was given.',
  1587. request
  1588. );
  1589. }
  1590. this._request = request;
  1591. if (!response || typeof response !== "object" || Array.isArray(response) || !isWritableStream(response)) {
  1592. throw new import_js_format17.InvalidArgumentError(
  1593. 'The parameter "response" of RequestContext.constructor must be an instance of ServerResponse, but %v was given.',
  1594. response
  1595. );
  1596. }
  1597. this._response = response;
  1598. if (!(route instanceof Route)) {
  1599. throw new import_js_format17.InvalidArgumentError(
  1600. 'The parameter "route" of RequestContext.constructor must be an instance of Route, but %v was given.',
  1601. route
  1602. );
  1603. }
  1604. this._route = route;
  1605. }
  1606. };
  1607. __name(_RequestContext, "RequestContext");
  1608. var RequestContext = _RequestContext;
  1609. // src/trie-router.js
  1610. var import_js_service4 = require("@e22m4u/js-service");
  1611. var import_http4 = require("http");
  1612. // src/senders/data-sender.js
  1613. var import_js_format18 = require("@e22m4u/js-format");
  1614. var _DataSender = class _DataSender extends DebuggableService {
  1615. /**
  1616. * Send.
  1617. *
  1618. * @param {import('http').ServerResponse} response
  1619. * @param {*} data
  1620. * @returns {undefined}
  1621. */
  1622. send(response, data) {
  1623. const debug = this.getDebuggerFor(this.send);
  1624. if (data === response || response.headersSent) {
  1625. debug(
  1626. "Response sending was skipped because its headers where sent already."
  1627. );
  1628. return;
  1629. }
  1630. if (data == null) {
  1631. response.statusCode = 204;
  1632. response.end();
  1633. debug("The empty response was sent.");
  1634. return;
  1635. }
  1636. if (isReadableStream(data)) {
  1637. response.setHeader("Content-Type", "application/octet-stream");
  1638. data.pipe(response);
  1639. debug("The stream response was sent.");
  1640. return;
  1641. }
  1642. let debugMsg;
  1643. switch (typeof data) {
  1644. case "object":
  1645. case "boolean":
  1646. case "number":
  1647. if (Buffer.isBuffer(data)) {
  1648. response.setHeader("content-type", "application/octet-stream");
  1649. debugMsg = "The Buffer was sent as binary data.";
  1650. } else {
  1651. response.setHeader("content-type", "application/json");
  1652. debugMsg = (0, import_js_format18.format)("The %v was sent as JSON.", typeof data);
  1653. data = JSON.stringify(data);
  1654. }
  1655. break;
  1656. default:
  1657. response.setHeader("content-type", "text/plain");
  1658. debugMsg = "The response data was sent as plain text.";
  1659. data = String(data);
  1660. break;
  1661. }
  1662. response.end(data);
  1663. debug(debugMsg);
  1664. }
  1665. };
  1666. __name(_DataSender, "DataSender");
  1667. var DataSender = _DataSender;
  1668. // src/senders/error-sender.js
  1669. var import_util = require("util");
  1670. var import_statuses = __toESM(require("statuses"), 1);
  1671. var EXPOSED_ERROR_PROPERTIES = ["code", "details"];
  1672. var _ErrorSender = class _ErrorSender extends DebuggableService {
  1673. /**
  1674. * Handle.
  1675. *
  1676. * @param {import('http').IncomingMessage} request
  1677. * @param {import('http').ServerResponse} response
  1678. * @param {Error} error
  1679. * @returns {undefined}
  1680. */
  1681. send(request, response, error) {
  1682. const debug = this.getDebuggerFor(this.send);
  1683. let safeError = {};
  1684. if (error) {
  1685. if (typeof error === "object") {
  1686. safeError = error;
  1687. } else {
  1688. safeError = { message: String(error) };
  1689. }
  1690. }
  1691. const statusCode = error.statusCode || error.status || 500;
  1692. const body = { error: {} };
  1693. if (safeError.message && typeof safeError.message === "string") {
  1694. body.error.message = safeError.message;
  1695. } else {
  1696. body.error.message = (0, import_statuses.default)(statusCode);
  1697. }
  1698. EXPOSED_ERROR_PROPERTIES.forEach((name) => {
  1699. if (name in safeError) {
  1700. body.error[name] = safeError[name];
  1701. }
  1702. });
  1703. const requestData = {
  1704. url: request.url,
  1705. method: request.method,
  1706. headers: request.headers
  1707. };
  1708. const inspectOptions = {
  1709. showHidden: false,
  1710. depth: null,
  1711. colors: true,
  1712. compact: false
  1713. };
  1714. console.warn((0, import_util.inspect)(requestData, inspectOptions));
  1715. console.warn((0, import_util.inspect)(body, inspectOptions));
  1716. if (error.stack) {
  1717. console.log(error.stack);
  1718. } else {
  1719. console.error(error);
  1720. }
  1721. response.statusCode = statusCode;
  1722. response.setHeader("content-type", "application/json; charset=utf-8");
  1723. response.end(JSON.stringify(body, null, 2), "utf-8");
  1724. debug(
  1725. "The %s error was sent for the request %s %v.",
  1726. statusCode,
  1727. request.method,
  1728. getRequestPathname(request)
  1729. );
  1730. }
  1731. /**
  1732. * Send 404.
  1733. *
  1734. * @param {import('http').IncomingMessage} request
  1735. * @param {import('http').ServerResponse} response
  1736. * @returns {undefined}
  1737. */
  1738. send404(request, response) {
  1739. const debug = this.getDebuggerFor(this.send404);
  1740. response.statusCode = 404;
  1741. response.setHeader("content-type", "text/plain; charset=utf-8");
  1742. response.end("404 Not Found", "utf-8");
  1743. debug(
  1744. "The 404 error was sent for the request %s %v.",
  1745. request.method,
  1746. getRequestPathname(request)
  1747. );
  1748. }
  1749. };
  1750. __name(_ErrorSender, "ErrorSender");
  1751. var ErrorSender = _ErrorSender;
  1752. // src/trie-router.js
  1753. var _TrieRouter = class _TrieRouter extends DebuggableService {
  1754. /**
  1755. * Define route.
  1756. *
  1757. * Example 1:
  1758. * ```
  1759. * const router = new TrieRouter();
  1760. * router.defineRoute({
  1761. * method: HttpMethod.GET, // Request method.
  1762. * path: '/', // Path template.
  1763. * handler: ctx => 'Hello world!', // Request handler.
  1764. * });
  1765. * ```
  1766. *
  1767. * Example 2:
  1768. * ```
  1769. * const router = new TrieRouter();
  1770. * router.defineRoute({
  1771. * method: HttpMethod.POST, // Request method.
  1772. * path: '/users/:id', // The path template may have parameters.
  1773. * preHandler(ctx) { ... }, // The "preHandler" executes before a route handler.
  1774. * handler(ctx) { ... }, // Request handler function.
  1775. * postHandler(ctx, data) { ... }, // The "postHandler" executes after a route handler.
  1776. * });
  1777. * ```
  1778. *
  1779. * @param {import('./route-registry.js').RouteDefinition} routeDef
  1780. * @returns {import('./route/index.js').Route}
  1781. */
  1782. defineRoute(routeDef) {
  1783. return this.getService(RouteRegistry).defineRoute(routeDef);
  1784. }
  1785. /**
  1786. * Request listener.
  1787. *
  1788. * Example:
  1789. * ```
  1790. * import http from 'http';
  1791. * import {TrieRouter} from '@e22m4u/js-trie-router';
  1792. *
  1793. * const router = new TrieRouter();
  1794. * const server = new http.Server();
  1795. * server.on('request', router.requestListener); // Sets the request listener.
  1796. * server.listen(3000); // Starts listening for connections.
  1797. * ```
  1798. *
  1799. * @returns {Function}
  1800. */
  1801. get requestListener() {
  1802. return this._handleRequest.bind(this);
  1803. }
  1804. /**
  1805. * Handle incoming request.
  1806. *
  1807. * @param {import('http').IncomingMessage} request
  1808. * @param {import('http').ServerResponse} response
  1809. * @returns {Promise<undefined>}
  1810. * @private
  1811. */
  1812. async _handleRequest(request, response) {
  1813. const debug = this.getDebuggerFor(this._handleRequest);
  1814. const requestPath = (request.url || "/").replace(/\?.*$/, "");
  1815. debug(
  1816. "Preparing to handle an incoming request %s %v.",
  1817. request.method,
  1818. requestPath
  1819. );
  1820. const resolved = this.getService(RouteRegistry).matchRouteByRequest(request);
  1821. if (!resolved) {
  1822. debug("No route for the request %s %v.", request.method, requestPath);
  1823. this.getService(ErrorSender).send404(request, response);
  1824. } else {
  1825. const { route, params } = resolved;
  1826. const container = new import_js_service4.ServiceContainer(this.container);
  1827. const context = new RequestContext(container, request, response, route);
  1828. container.set(RequestContext, context);
  1829. container.set(import_http4.IncomingMessage, request);
  1830. container.set(import_http4.ServerResponse, response);
  1831. context.params = params;
  1832. let data;
  1833. try {
  1834. const reqDataOrPromise = this.getService(RequestParser).parse(request);
  1835. if (isPromise(reqDataOrPromise)) {
  1836. const reqData = await reqDataOrPromise;
  1837. Object.assign(context, reqData);
  1838. } else {
  1839. Object.assign(context, reqDataOrPromise);
  1840. }
  1841. const hookInvoker = this.getService(HookInvoker);
  1842. data = hookInvoker.invokeAndContinueUntilValueReceived(
  1843. route,
  1844. RouterHookType.PRE_HANDLER,
  1845. response,
  1846. context
  1847. );
  1848. if (isPromise(data)) {
  1849. data = await data;
  1850. }
  1851. if (!isResponseSent(response) && data == null) {
  1852. data = route.handle(context);
  1853. if (isPromise(data)) {
  1854. data = await data;
  1855. }
  1856. let postHandlerData = hookInvoker.invokeAndContinueUntilValueReceived(
  1857. route,
  1858. RouterHookType.POST_HANDLER,
  1859. response,
  1860. context,
  1861. data
  1862. );
  1863. if (isPromise(postHandlerData)) {
  1864. postHandlerData = await postHandlerData;
  1865. }
  1866. if (postHandlerData != null) {
  1867. data = postHandlerData;
  1868. }
  1869. }
  1870. } catch (error) {
  1871. this.getService(ErrorSender).send(request, response, error);
  1872. return;
  1873. }
  1874. if (!isResponseSent(response)) {
  1875. this.getService(DataSender).send(response, data);
  1876. }
  1877. }
  1878. }
  1879. /**
  1880. * Add hook.
  1881. *
  1882. * Example:
  1883. * ```
  1884. * import {TrieRouter} from '@e22m4u/js-trie-router';
  1885. * import {RouterHookType} from '@e22m4u/js-trie-router';
  1886. *
  1887. * // Router instance.
  1888. * const router = new TrieRouter();
  1889. *
  1890. * // Adds the "preHandler" hook for each route.
  1891. * router.addHook(
  1892. * RouterHookType.PRE_HANDLER,
  1893. * ctx => { ... },
  1894. * );
  1895. *
  1896. * // Adds the "postHandler" hook for each route.
  1897. * router.addHook(
  1898. * RouterHookType.POST_HANDLER,
  1899. * ctx => { ... },
  1900. * );
  1901. * ```
  1902. *
  1903. * @param {string} type
  1904. * @param {Function} hook
  1905. * @returns {this}
  1906. */
  1907. addHook(type, hook) {
  1908. this.getService(HookRegistry).addHook(type, hook);
  1909. return this;
  1910. }
  1911. /**
  1912. * Add pre-handler hook.
  1913. *
  1914. * @param {Function} hook
  1915. * @returns {this}
  1916. */
  1917. addPreHandler(hook) {
  1918. this.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, hook);
  1919. return this;
  1920. }
  1921. /**
  1922. * Add post-handler hook.
  1923. *
  1924. * @param {Function} hook
  1925. * @returns {this}
  1926. */
  1927. addPostHandler(hook) {
  1928. this.getService(HookRegistry).addHook(RouterHookType.POST_HANDLER, hook);
  1929. return this;
  1930. }
  1931. };
  1932. __name(_TrieRouter, "TrieRouter");
  1933. var TrieRouter = _TrieRouter;
  1934. // Annotate the CommonJS export names for ESM import in node:
  1935. 0 && (module.exports = {
  1936. BodyParser,
  1937. CHARACTER_ENCODING_LIST,
  1938. CookiesParser,
  1939. DataSender,
  1940. EXPOSED_ERROR_PROPERTIES,
  1941. ErrorSender,
  1942. HookInvoker,
  1943. HookRegistry,
  1944. HttpMethod,
  1945. METHODS_WITH_BODY,
  1946. QueryParser,
  1947. RequestContext,
  1948. RequestParser,
  1949. Route,
  1950. RouteRegistry,
  1951. RouterHookType,
  1952. RouterOptions,
  1953. TrieRouter,
  1954. UNPARSABLE_MEDIA_TYPES,
  1955. cloneDeep,
  1956. createCookieString,
  1957. createError,
  1958. createRequestMock,
  1959. createResponseMock,
  1960. createRouteMock,
  1961. fetchRequestBody,
  1962. getRequestPathname,
  1963. isPromise,
  1964. isReadableStream,
  1965. isResponseSent,
  1966. isWritableStream,
  1967. parseContentType,
  1968. parseCookieString,
  1969. parseJsonBody,
  1970. toCamelCase,
  1971. validateRouteDefinition
  1972. });