yinzerflow 0.1.18 → 0.2.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/README.md +0 -296
- package/YinzerFlow.d.ts +565 -0
- package/YinzerFlow.js +24 -0
- package/YinzerFlow.js.map +42 -0
- package/docs/advanced-configuration-options.md +175 -0
- package/docs/body-parsing.md +294 -0
- package/docs/cors.md +187 -0
- package/docs/ip-security.md +232 -0
- package/docs/request.md +145 -0
- package/docs/response.md +251 -0
- package/docs/start-here.MD +116 -0
- package/example/index.ts +109 -53
- package/package.json +15 -17
- package/constants/index.d.ts +0 -86
- package/constants/index.js +0 -3
- package/constants/index.js.map +0 -13
- package/docs/README.md +0 -327
- package/docs/content-types.md +0 -390
- package/docs/error-handling.md +0 -266
- package/docs/file-parsers.md +0 -276
- package/docs/hooks.md +0 -289
- package/docs/routing.md +0 -204
- package/example/bun.lock +0 -866
- package/example/hooks/authentication.middleware.ts +0 -77
- package/example/package.json +0 -61
- package/example/routes/authentication.routes.ts +0 -243
- package/example/routes/content-types.ts +0 -116
- package/example/tsconfig.json +0 -32
- package/index.d.ts +0 -395
- package/index.js +0 -23
- package/index.js.map +0 -33
package/index.js.map
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../node_modules/ip/lib/ip.js", "../node_modules/dayjs/dayjs.min.js", "../app/index.ts", "../app/core/YinzerFlow.ts", "../app/core/ConfigManager.ts", "../app/core/Route/methods/get.ts", "../app/core/Route/methods/post.ts", "../app/core/Route/methods/put.ts", "../app/core/Route/methods/delete.ts", "../app/core/Route/methods/patch.ts", "../app/core/Route/RouteRegistry.ts", "../app/core/Route/RouteFinder.ts", "../app/core/Request/parsers/multipartFormData.ts", "../app/utils/string.utils.ts", "../app/core/Request/parsers/fileParsers/yaml.ts", "../app/core/Request/parsers/json.ts", "../app/core/Request/guards/multipartFormData.ts", "../app/core/Request/guards/json.ts", "../app/core/Request/Request.ts", "../app/core/Response.ts", "../app/core/Context.ts", "../app/core/Request/RequestHandler.ts", "../app/core/ConnectionManager.ts", "../app/core/HooksManager.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"const ip = exports;\nconst { Buffer } = require('buffer');\nconst os = require('os');\n\nip.toBuffer = function (ip, buff, offset) {\n offset = ~~offset;\n\n let result;\n\n if (this.isV4Format(ip)) {\n result = buff || Buffer.alloc(offset + 4);\n ip.split(/\\./g).map((byte) => {\n result[offset++] = parseInt(byte, 10) & 0xff;\n });\n } else if (this.isV6Format(ip)) {\n const sections = ip.split(':', 8);\n\n let i;\n for (i = 0; i < sections.length; i++) {\n const isv4 = this.isV4Format(sections[i]);\n let v4Buffer;\n\n if (isv4) {\n v4Buffer = this.toBuffer(sections[i]);\n sections[i] = v4Buffer.slice(0, 2).toString('hex');\n }\n\n if (v4Buffer && ++i < 8) {\n sections.splice(i, 0, v4Buffer.slice(2, 4).toString('hex'));\n }\n }\n\n if (sections[0] === '') {\n while (sections.length < 8) sections.unshift('0');\n } else if (sections[sections.length - 1] === '') {\n while (sections.length < 8) sections.push('0');\n } else if (sections.length < 8) {\n for (i = 0; i < sections.length && sections[i] !== ''; i++);\n const argv = [i, 1];\n for (i = 9 - sections.length; i > 0; i--) {\n argv.push('0');\n }\n sections.splice(...argv);\n }\n\n result = buff || Buffer.alloc(offset + 16);\n for (i = 0; i < sections.length; i++) {\n const word = parseInt(sections[i], 16);\n result[offset++] = (word >> 8) & 0xff;\n result[offset++] = word & 0xff;\n }\n }\n\n if (!result) {\n throw Error(`Invalid ip address: ${ip}`);\n }\n\n return result;\n};\n\nip.toString = function (buff, offset, length) {\n offset = ~~offset;\n length = length || (buff.length - offset);\n\n let result = [];\n if (length === 4) {\n // IPv4\n for (let i = 0; i < length; i++) {\n result.push(buff[offset + i]);\n }\n result = result.join('.');\n } else if (length === 16) {\n // IPv6\n for (let i = 0; i < length; i += 2) {\n result.push(buff.readUInt16BE(offset + i).toString(16));\n }\n result = result.join(':');\n result = result.replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3');\n result = result.replace(/:{3,4}/, '::');\n }\n\n return result;\n};\n\nconst ipv4Regex = /^(\\d{1,3}\\.){3,3}\\d{1,3}$/;\nconst ipv6Regex = /^(::)?(((\\d{1,3}\\.){3}(\\d{1,3}){1})?([0-9a-f]){0,4}:{0,2}){1,8}(::)?$/i;\n\nip.isV4Format = function (ip) {\n return ipv4Regex.test(ip);\n};\n\nip.isV6Format = function (ip) {\n return ipv6Regex.test(ip);\n};\n\nfunction _normalizeFamily(family) {\n if (family === 4) {\n return 'ipv4';\n }\n if (family === 6) {\n return 'ipv6';\n }\n return family ? family.toLowerCase() : 'ipv4';\n}\n\nip.fromPrefixLen = function (prefixlen, family) {\n if (prefixlen > 32) {\n family = 'ipv6';\n } else {\n family = _normalizeFamily(family);\n }\n\n let len = 4;\n if (family === 'ipv6') {\n len = 16;\n }\n const buff = Buffer.alloc(len);\n\n for (let i = 0, n = buff.length; i < n; ++i) {\n let bits = 8;\n if (prefixlen < 8) {\n bits = prefixlen;\n }\n prefixlen -= bits;\n\n buff[i] = ~(0xff >> bits) & 0xff;\n }\n\n return ip.toString(buff);\n};\n\nip.mask = function (addr, mask) {\n addr = ip.toBuffer(addr);\n mask = ip.toBuffer(mask);\n\n const result = Buffer.alloc(Math.max(addr.length, mask.length));\n\n // Same protocol - do bitwise and\n let i;\n if (addr.length === mask.length) {\n for (i = 0; i < addr.length; i++) {\n result[i] = addr[i] & mask[i];\n }\n } else if (mask.length === 4) {\n // IPv6 address and IPv4 mask\n // (Mask low bits)\n for (i = 0; i < mask.length; i++) {\n result[i] = addr[addr.length - 4 + i] & mask[i];\n }\n } else {\n // IPv6 mask and IPv4 addr\n for (i = 0; i < result.length - 6; i++) {\n result[i] = 0;\n }\n\n // ::ffff:ipv4\n result[10] = 0xff;\n result[11] = 0xff;\n for (i = 0; i < addr.length; i++) {\n result[i + 12] = addr[i] & mask[i + 12];\n }\n i += 12;\n }\n for (; i < result.length; i++) {\n result[i] = 0;\n }\n\n return ip.toString(result);\n};\n\nip.cidr = function (cidrString) {\n const cidrParts = cidrString.split('/');\n\n const addr = cidrParts[0];\n if (cidrParts.length !== 2) {\n throw new Error(`invalid CIDR subnet: ${addr}`);\n }\n\n const mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));\n\n return ip.mask(addr, mask);\n};\n\nip.subnet = function (addr, mask) {\n const networkAddress = ip.toLong(ip.mask(addr, mask));\n\n // Calculate the mask's length.\n const maskBuffer = ip.toBuffer(mask);\n let maskLength = 0;\n\n for (let i = 0; i < maskBuffer.length; i++) {\n if (maskBuffer[i] === 0xff) {\n maskLength += 8;\n } else {\n let octet = maskBuffer[i] & 0xff;\n while (octet) {\n octet = (octet << 1) & 0xff;\n maskLength++;\n }\n }\n }\n\n const numberOfAddresses = 2 ** (32 - maskLength);\n\n return {\n networkAddress: ip.fromLong(networkAddress),\n firstAddress: numberOfAddresses <= 2\n ? ip.fromLong(networkAddress)\n : ip.fromLong(networkAddress + 1),\n lastAddress: numberOfAddresses <= 2\n ? ip.fromLong(networkAddress + numberOfAddresses - 1)\n : ip.fromLong(networkAddress + numberOfAddresses - 2),\n broadcastAddress: ip.fromLong(networkAddress + numberOfAddresses - 1),\n subnetMask: mask,\n subnetMaskLength: maskLength,\n numHosts: numberOfAddresses <= 2\n ? numberOfAddresses : numberOfAddresses - 2,\n length: numberOfAddresses,\n contains(other) {\n return networkAddress === ip.toLong(ip.mask(other, mask));\n },\n };\n};\n\nip.cidrSubnet = function (cidrString) {\n const cidrParts = cidrString.split('/');\n\n const addr = cidrParts[0];\n if (cidrParts.length !== 2) {\n throw new Error(`invalid CIDR subnet: ${addr}`);\n }\n\n const mask = ip.fromPrefixLen(parseInt(cidrParts[1], 10));\n\n return ip.subnet(addr, mask);\n};\n\nip.not = function (addr) {\n const buff = ip.toBuffer(addr);\n for (let i = 0; i < buff.length; i++) {\n buff[i] = 0xff ^ buff[i];\n }\n return ip.toString(buff);\n};\n\nip.or = function (a, b) {\n a = ip.toBuffer(a);\n b = ip.toBuffer(b);\n\n // same protocol\n if (a.length === b.length) {\n for (let i = 0; i < a.length; ++i) {\n a[i] |= b[i];\n }\n return ip.toString(a);\n\n // mixed protocols\n }\n let buff = a;\n let other = b;\n if (b.length > a.length) {\n buff = b;\n other = a;\n }\n\n const offset = buff.length - other.length;\n for (let i = offset; i < buff.length; ++i) {\n buff[i] |= other[i - offset];\n }\n\n return ip.toString(buff);\n};\n\nip.isEqual = function (a, b) {\n a = ip.toBuffer(a);\n b = ip.toBuffer(b);\n\n // Same protocol\n if (a.length === b.length) {\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n\n // Swap\n if (b.length === 4) {\n const t = b;\n b = a;\n a = t;\n }\n\n // a - IPv4, b - IPv6\n for (let i = 0; i < 10; i++) {\n if (b[i] !== 0) return false;\n }\n\n const word = b.readUInt16BE(10);\n if (word !== 0 && word !== 0xffff) return false;\n\n for (let i = 0; i < 4; i++) {\n if (a[i] !== b[i + 12]) return false;\n }\n\n return true;\n};\n\nip.isPrivate = function (addr) {\n // check loopback addresses first\n if (ip.isLoopback(addr)) {\n return true;\n }\n\n // ensure the ipv4 address is valid\n if (!ip.isV6Format(addr)) {\n const ipl = ip.normalizeToLong(addr);\n if (ipl < 0) {\n throw new Error('invalid ipv4 address');\n }\n // normalize the address for the private range checks that follow\n addr = ip.fromLong(ipl);\n }\n\n // check private ranges\n return /^(::f{4}:)?10\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$/i.test(addr)\n || /^(::f{4}:)?192\\.168\\.([0-9]{1,3})\\.([0-9]{1,3})$/i.test(addr)\n || /^(::f{4}:)?172\\.(1[6-9]|2\\d|30|31)\\.([0-9]{1,3})\\.([0-9]{1,3})$/i\n .test(addr)\n || /^(::f{4}:)?169\\.254\\.([0-9]{1,3})\\.([0-9]{1,3})$/i.test(addr)\n || /^f[cd][0-9a-f]{2}:/i.test(addr)\n || /^fe80:/i.test(addr)\n || /^::1$/.test(addr)\n || /^::$/.test(addr);\n};\n\nip.isPublic = function (addr) {\n return !ip.isPrivate(addr);\n};\n\nip.isLoopback = function (addr) {\n // If addr is an IPv4 address in long integer form (no dots and no colons), convert it\n if (!/\\./.test(addr) && !/:/.test(addr)) {\n addr = ip.fromLong(Number(addr));\n }\n\n return /^(::f{4}:)?127\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})/\n .test(addr)\n || /^0177\\./.test(addr)\n || /^0x7f\\./i.test(addr)\n || /^fe80::1$/i.test(addr)\n || /^::1$/.test(addr)\n || /^::$/.test(addr);\n};\n\nip.loopback = function (family) {\n //\n // Default to `ipv4`\n //\n family = _normalizeFamily(family);\n\n if (family !== 'ipv4' && family !== 'ipv6') {\n throw new Error('family must be ipv4 or ipv6');\n }\n\n return family === 'ipv4' ? '127.0.0.1' : 'fe80::1';\n};\n\n//\n// ### function address (name, family)\n// #### @name {string|'public'|'private'} **Optional** Name or security\n// of the network interface.\n// #### @family {ipv4|ipv6} **Optional** IP family of the address (defaults\n// to ipv4).\n//\n// Returns the address for the network interface on the current system with\n// the specified `name`:\n// * String: First `family` address of the interface.\n// If not found see `undefined`.\n// * 'public': the first public ip address of family.\n// * 'private': the first private ip address of family.\n// * undefined: First address with `ipv4` or loopback address `127.0.0.1`.\n//\nip.address = function (name, family) {\n const interfaces = os.networkInterfaces();\n\n //\n // Default to `ipv4`\n //\n family = _normalizeFamily(family);\n\n //\n // If a specific network interface has been named,\n // return the address.\n //\n if (name && name !== 'private' && name !== 'public') {\n const res = interfaces[name].filter((details) => {\n const itemFamily = _normalizeFamily(details.family);\n return itemFamily === family;\n });\n if (res.length === 0) {\n return undefined;\n }\n return res[0].address;\n }\n\n const all = Object.keys(interfaces).map((nic) => {\n //\n // Note: name will only be `public` or `private`\n // when this is called.\n //\n const addresses = interfaces[nic].filter((details) => {\n details.family = _normalizeFamily(details.family);\n if (details.family !== family || ip.isLoopback(details.address)) {\n return false;\n } if (!name) {\n return true;\n }\n\n return name === 'public' ? ip.isPrivate(details.address)\n : ip.isPublic(details.address);\n });\n\n return addresses.length ? addresses[0].address : undefined;\n }).filter(Boolean);\n\n return !all.length ? ip.loopback(family) : all[0];\n};\n\nip.toLong = function (ip) {\n let ipl = 0;\n ip.split('.').forEach((octet) => {\n ipl <<= 8;\n ipl += parseInt(octet);\n });\n return (ipl >>> 0);\n};\n\nip.fromLong = function (ipl) {\n return (`${ipl >>> 24}.${\n ipl >> 16 & 255}.${\n ipl >> 8 & 255}.${\n ipl & 255}`);\n};\n\nip.normalizeToLong = function (addr) {\n const parts = addr.split('.').map(part => {\n // Handle hexadecimal format\n if (part.startsWith('0x') || part.startsWith('0X')) {\n return parseInt(part, 16);\n }\n // Handle octal format (strictly digits 0-7 after a leading zero)\n else if (part.startsWith('0') && part !== '0' && /^[0-7]+$/.test(part)) {\n return parseInt(part, 8);\n }\n // Handle decimal format, reject invalid leading zeros\n else if (/^[1-9]\\d*$/.test(part) || part === '0') {\n return parseInt(part, 10);\n }\n // Return NaN for invalid formats to indicate parsing failure\n else {\n return NaN;\n }\n });\n\n if (parts.some(isNaN)) return -1; // Indicate error with -1\n\n let val = 0;\n const n = parts.length;\n\n switch (n) {\n case 1:\n val = parts[0];\n break;\n case 2:\n if (parts[0] > 0xff || parts[1] > 0xffffff) return -1;\n val = (parts[0] << 24) | (parts[1] & 0xffffff);\n break;\n case 3:\n if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff) return -1;\n val = (parts[0] << 24) | (parts[1] << 16) | (parts[2] & 0xffff);\n break;\n case 4:\n if (parts.some(part => part > 0xff)) return -1;\n val = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];\n break;\n default:\n return -1; // Error case\n }\n\n return val >>> 0;\n};\n",
|
|
6
|
-
"!function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define(e):(t=\"undefined\"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){\"use strict\";var t=1e3,e=6e4,n=36e5,r=\"millisecond\",i=\"second\",s=\"minute\",u=\"hour\",a=\"day\",o=\"week\",c=\"month\",f=\"quarter\",h=\"year\",d=\"date\",l=\"Invalid Date\",$=/^(\\d{4})[-/]?(\\d{1,2})?[-/]?(\\d{0,2})[Tt\\s]*(\\d{1,2})?:?(\\d{1,2})?:?(\\d{1,2})?[.:]?(\\d+)?$/,y=/\\[([^\\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:\"en\",weekdays:\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),months:\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),ordinal:function(t){var e=[\"th\",\"st\",\"nd\",\"rd\"],n=t%100;return\"[\"+t+(e[(n-20)%10]||e[n]||e[0])+\"]\"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:\"\"+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?\"+\":\"-\")+m(r,2,\"0\")+\":\"+m(i,2,\"0\")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,c),s=n-i<0,u=e.clone().add(r+(s?-1:1),c);return+(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return{M:c,y:h,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:f}[t]||String(t||\"\").toLowerCase().replace(/s$/,\"\")},u:function(t){return void 0===t}},g=\"en\",D={};D[g]=M;var p=\"$isDayjsObject\",S=function(t){return t instanceof _||!(!t||!t[p])},w=function t(e,n,r){var i;if(!e)return g;if(\"string\"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split(\"-\");if(!i&&u.length>1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n=\"object\"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if(\"string\"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||\"0\").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<O(t)},m.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!b.u(e)||e,f=b.p(t),l=function(t,e){var i=b.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return b.w(n.toDate()[t].apply(n.toDate(\"s\"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v=\"set\"+(this.$u?\"UTC\":\"\");switch(f){case h:return r?l(1,0):l(31,11);case c:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+\"Hours\",0);case u:return $(v+\"Minutes\",1);case s:return $(v+\"Seconds\",2);case i:return $(v+\"Milliseconds\",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,!1)},m.$set=function(t,e){var n,o=b.p(t),f=\"set\"+(this.$u?\"UTC\":\"\"),l=(n={},n[a]=f+\"Date\",n[d]=f+\"Date\",n[c]=f+\"Month\",n[h]=f+\"FullYear\",n[u]=f+\"Hours\",n[s]=f+\"Minutes\",n[i]=f+\"Seconds\",n[r]=f+\"Milliseconds\",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===c||o===h){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[b.p(t)]()},m.add=function(r,f){var d,l=this;r=Number(r);var $=b.p(f),y=function(t){var e=O(l);return b.w(e.date(e.date()+Math.round(t*r)),l)};if($===c)return this.set(c,this.$M+r);if($===h)return this.set(h,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return b.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||\"YYYY-MM-DDTHH:mm:ssZ\",i=b.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,c=n.months,f=n.meridiem,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},d=function(t){return b.s(s%12||12,t,\"0\")},$=f||function(t,e,n){var r=t<12?\"AM\":\"PM\";return n?r.toLowerCase():r};return r.replace(y,(function(t,r){return r||function(t){switch(t){case\"YY\":return String(e.$y).slice(-2);case\"YYYY\":return b.s(e.$y,4,\"0\");case\"M\":return a+1;case\"MM\":return b.s(a+1,2,\"0\");case\"MMM\":return h(n.monthsShort,a,c,3);case\"MMMM\":return h(c,a);case\"D\":return e.$D;case\"DD\":return b.s(e.$D,2,\"0\");case\"d\":return String(e.$W);case\"dd\":return h(n.weekdaysMin,e.$W,o,2);case\"ddd\":return h(n.weekdaysShort,e.$W,o,3);case\"dddd\":return o[e.$W];case\"H\":return String(s);case\"HH\":return b.s(s,2,\"0\");case\"h\":return d(1);case\"hh\":return d(2);case\"a\":return $(s,u,!0);case\"A\":return $(s,u,!1);case\"m\":return String(u);case\"mm\":return b.s(u,2,\"0\");case\"s\":return String(e.$s);case\"ss\":return b.s(e.$s,2,\"0\");case\"SSS\":return b.s(e.$ms,3,\"0\");case\"Z\":return i}return null}(t)||i.replace(\":\",\"\")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=this,M=b.p(d),m=O(r),v=(m.utcOffset()-this.utcOffset())*e,g=this-m,D=function(){return b.m(y,m)};switch(M){case h:$=D()/12;break;case c:$=D();break;case f:$=D()/3;break;case o:$=(g-v)/6048e5;break;case a:$=(g-v)/864e5;break;case u:$=g/n;break;case s:$=g/e;break;case i:$=g/t;break;default:$=g}return l?$:b.a($)},m.daysInMonth=function(){return this.endOf(c).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=w(t,e,!0);return r&&(n.$L=r),n},m.clone=function(){return b.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),k=_.prototype;return O.prototype=k,[[\"$ms\",r],[\"$s\",i],[\"$m\",s],[\"$H\",u],[\"$W\",a],[\"$M\",c],[\"$y\",h],[\"$D\",d]].forEach((function(t){k[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),O.extend=function(t,e){return t.$i||(t(e,_,O),t.$i=!0),O},O.locale=w,O.isDayjs=S,O.unix=function(t){return O(1e3*t)},O.en=D[g],O.Ls=D,O.p={},O}));",
|
|
7
|
-
"/**\n * YinzerFlow Main Barrel File\n *\n * This file uses named exports rather than wildcard exports\n * to ensure optimal tree shaking by bundlers.\n */\n\n// Constants exports\nexport { HttpMethod, HttpStatus, HttpStatusCode, ContentType } from 'constants/index.ts';\n\n// Types exports - using 'type' keyword for better tree shaking\nexport type { IRoute, TErrorFunction, THttpStatusCode, TResponseBody, TJsonData, IMultipartFormData, IServerOptions } from 'types/index.ts';\n\n// Core components - export selectively from the core barrel file\nexport { YinzerFlow, Context, Request, Response, RequestHandler, ConnectionManager, HooksManager } from 'core/index.ts';\n\n// Route components - export selectively from the route barrel file\nexport { RouteRegistry, RouteFinder } from 'core/Route/index.ts';\n\n// Route methods - export selectively from the route methods barrel file\nexport { addGetRoute, addPostRoute, addPutRoute, addDeleteRoute, addPatchRoute } from 'core/Route/methods/index.ts';\n\n// Request parsers - export selectively from the request parsers barrel file\nexport { parseMultipartFormData, parseApplicationJson, parseYaml } from 'core/Request/index.ts';\n\n// Request guards - export selectively from the request guards barrel file\nexport { isJsonData, isMultipartFormData } from 'core/Request/index.ts';\n\n\n",
|
|
8
|
-
"import { createServer } from 'net';\nimport type { Socket } from 'net';\nimport ip from 'ip';\n\nimport { ConfigManager } from './ConfigManager.ts';\nimport { addDeleteRoute, addGetRoute, addPatchRoute, addPostRoute, addPutRoute } from 'core/Route/methods/index.ts';\nimport { RouteRegistry } from 'core/Route/RouteRegistry.ts';\nimport { RouteRegistryEvent } from 'constants/route.ts';\nimport { RouteFinder } from 'core/Route/RouteFinder.ts';\nimport type { IRoute } from 'types/Route.ts';\nimport { RequestHandler } from 'core/Request/RequestHandler.ts';\nimport { ConnectionManager } from 'core/ConnectionManager.ts';\nimport { HooksManager } from 'core/HooksManager.ts';\nimport type { IServerOptions } from 'types/Server.ts';\n\n/**\n * Main YinzerFlow server class\n *\n * This class orchestrates all the components of the server:\n * - Route management\n * - Middleware processing\n * - Request handling\n * - Connection management\n */\nexport class YinzerFlow {\n // === COMPONENT MANAGERS ===\n private readonly routeRegistry = new RouteRegistry();\n private readonly routeFinder = new RouteFinder(this.routeRegistry);\n private readonly hooksManager = new HooksManager();\n private readonly connectionManager: ConnectionManager;\n private readonly requestHandler: RequestHandler;\n private readonly configManager: ConfigManager;\n\n // === SERVER CONFIGURATION ===\n private readonly _ip: string = ip.address();\n\n // === PUBLIC ACCESSORS ===\n\n /**\n * Get the hooks manager instance\n *\n * This allows direct access to the hooks manager for advanced use cases,\n * such as subscribing to hook events.\n */\n get hooks(): HooksManager {\n return this.hooksManager;\n }\n\n /**\n * Get the config manager instance\n *\n * This allows direct access to the configuration for advanced use cases.\n */\n get config(): ConfigManager {\n return this.configManager;\n }\n\n /**\n * Create a new YinzerFlow server instance\n */\n constructor(options?: IServerOptions) {\n // Initialize the config manager with all options\n this.configManager = new ConfigManager(options);\n\n // Initialize the connection manager with the config manager\n this.connectionManager = new ConnectionManager(this.configManager);\n\n // Initialize the request handler with the managers\n this.requestHandler = new RequestHandler(this.routeFinder, this.hooksManager, this.configManager);\n\n // Set up event listeners for route changes\n this.routeRegistry.on(RouteRegistryEvent.ROUTES_CHANGED, () => {\n // Update the route finder's pattern cache when routes change\n this.routeFinder.updatePatternRouteCache();\n });\n }\n\n // === ROUTE DEFINITION METHODS ===\n /**\n * This tree shaking method is used to optimize the bundle size by including only the HTTP methods that are actually utilized.\n * Here's the process:\n * 1. User imports YinzerFlow: The main class is imported as before.\n * 2. YinzerFlow loads only what's needed: Only the HTTP methods actually used are included in the bundle.\n * 3. User API remains unchanged: Methods like app.get() and app.post() function as they did previously.\n *\n * Benefits to End Users:\n * - Smaller Bundle Size: Unused methods (e.g., PUT, DELETE) won't bloat the final bundle.\n * - Faster Startup: Less code leads to quicker parsing and execution.\n * - Lower Memory Usage: Only essential code is loaded into memory.\n * - Better Performance: Smaller bundles generally enhance overall performance.\n */\n\n /**\n * Register a GET route\n */\n get = addGetRoute(this.routeRegistry);\n\n /**\n * Register a POST route\n */\n post = addPostRoute(this.routeRegistry);\n\n /**\n * Register a PUT route\n */\n put = addPutRoute(this.routeRegistry);\n\n /**\n * Register a DELETE route\n */\n delete = addDeleteRoute(this.routeRegistry);\n\n /**\n * Register a PATCH route\n */\n patch = addPatchRoute(this.routeRegistry);\n\n /**\n * Register a group of routes with a common prefix\n */\n group(prefix: IRoute['path'], routes: Array<IRoute>, options?: { beforeGroup: IRoute['beforeGroup'] }): void {\n this.routeRegistry.addGroup(prefix, routes, options);\n }\n\n // === MIDDLEWARE METHODS ===\n\n /**\n * Register hooks to be executed before route handlers\n */\n beforeAll(fn: Parameters<HooksManager['add']>[0], options?: Parameters<HooksManager['add']>[1]): this {\n this.hooksManager.add(fn, options);\n return this;\n }\n\n // === SERVER LIFECYCLE METHODS ===\n\n /**\n * Start the server and listen for incoming connections\n */\n async listen(): Promise<void> {\n return new Promise((resolve) => {\n const { port } = this.configManager;\n const server = createServer();\n\n // Start listening\n server.listen(port, this._ip);\n\n this.connectionManager.setServer(server);\n\n server.on('listening', () => {\n this.connectionManager.setListening(true);\n resolve();\n });\n\n server.on('connection', (socket: Socket) => {\n // Add the connection to the connection manager\n this.connectionManager.addConnection(socket);\n\n socket.on('data', (buffer) => {\n this.requestHandler.handleSocketRequest(socket, buffer).catch((err) => {\n console.error('Error handling request:', err);\n });\n });\n\n socket.on('error', (error) => {\n console.error('An error occurred with yinzerflow. Please open an issue on GitHub.', error);\n });\n });\n\n server.on('error', (error) => {\n console.error('An error occurred with yinzerflow. Please open an issue on GitHub.', error);\n });\n });\n }\n\n /**\n * Stop the server and close all connections\n */\n async close(): Promise<void> {\n // If not listening or no server, resolve immediately\n if (!this.connectionManager.isListening() || !this.connectionManager.getServer()) {\n return;\n }\n\n // Close all existing connections with the configured grace period\n await this.connectionManager.closeAllConnections();\n\n // Close the server\n const server = this.connectionManager.getServer();\n if (!server) return;\n\n return new Promise((resolve) => {\n server.close(() => {\n this.connectionManager.setListening(false);\n resolve();\n });\n });\n }\n\n /**\n * Get the current server status\n */\n getStatus(): { isListening: boolean; port: number; ip: string } {\n return {\n isListening: this.connectionManager.isListening(),\n port: this.configManager.port,\n ip: this._ip,\n };\n }\n}\n",
|
|
9
|
-
"import type { IServerOptions } from 'types/Server.ts';\nimport type { TErrorFunction } from 'types/Response.ts';\nimport type { Context } from 'core/Context.ts';\nimport type { TResponseBody } from 'types/http/Response.ts';\nimport {\n DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT,\n DEFAULT_HEADERS_TIMEOUT,\n DEFAULT_KEEP_ALIVE_TIMEOUT,\n DEFAULT_PORT,\n DEFAULT_SOCKET_TIMEOUT,\n} from 'constants/connection.ts';\nimport { HttpStatusCode } from 'constants/http.ts';\n\n/**\n * Manages application configuration in a centralized way\n *\n * This class provides a single source of truth for all configuration options,\n * making it easier to access configuration throughout the application without\n * passing options through multiple layers.\n */\nexport class ConfigManager {\n readonly port: number;\n readonly errorHandler: TErrorFunction;\n readonly connectionOptions: Required<IServerOptions>['connectionOptions'];\n readonly parserOptions: Required<IServerOptions>['parserOptions'];\n\n constructor(options?: IServerOptions) {\n this.port = this._setPort(options?.port);\n this.errorHandler = this._setErrorHandler(options?.errorHandler);\n this.connectionOptions = this._setConnectionOptions(options?.connectionOptions);\n this.parserOptions = this._setParserOptions(options?.parserOptions);\n }\n\n /**\n * Sets the port number and normalizes it to a number\n */\n private _setPort(port?: number | string): number {\n const normalizedPort = typeof port === 'string' ? parseInt(port, 10) : (port ?? DEFAULT_PORT);\n if (isNaN(normalizedPort) || normalizedPort < 0 || normalizedPort > 65535) {\n throw new Error('Invalid port number');\n }\n return normalizedPort;\n }\n\n /**\n * Sets the error handler with validation\n */\n private _setErrorHandler(handler?: TErrorFunction): TErrorFunction {\n if (handler && typeof handler !== 'function') {\n throw new Error('Error handler must be a function');\n }\n return (\n handler ??\n (({ response }: Context, error: unknown): TResponseBody<unknown> => {\n console.error('Server error: \\n', error);\n response.setStatus(HttpStatusCode.INTERNAL_SERVER_ERROR);\n if (error instanceof Error) {\n return { success: false, message: error.message };\n }\n return { success: false, message: 'An unknown error occurred' };\n })\n );\n }\n\n /**\n * Sets and validates connection options\n */\n private _setConnectionOptions(options?: IServerOptions['connectionOptions']): Required<IServerOptions>['connectionOptions'] {\n const normalizedOptions = {\n socketTimeout: this._normalizeTimeout(options?.socketTimeout, DEFAULT_SOCKET_TIMEOUT),\n gracefulShutdownTimeout: this._normalizeTimeout(options?.gracefulShutdownTimeout, DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT),\n keepAliveTimeout: this._normalizeTimeout(options?.keepAliveTimeout, DEFAULT_KEEP_ALIVE_TIMEOUT),\n headersTimeout: this._normalizeTimeout(options?.headersTimeout, DEFAULT_HEADERS_TIMEOUT),\n };\n\n if (normalizedOptions.headersTimeout <= normalizedOptions.keepAliveTimeout) {\n throw new Error('headersTimeout must be greater than keepAliveTimeout');\n }\n\n return normalizedOptions;\n }\n\n /**\n * Normalizes a timeout value to a positive number\n */\n private _normalizeTimeout(value: number | string | undefined, defaultValue: number): number {\n const normalized = typeof value === 'string' ? parseInt(value, 10) : (value ?? defaultValue);\n if (isNaN(normalized) || normalized < 0) {\n throw new Error('Timeout must be a positive number');\n }\n return normalized;\n }\n\n /**\n * Sets and validates parser options\n */\n private _setParserOptions(options?: IServerOptions['parserOptions']): Required<IServerOptions>['parserOptions'] {\n const normalizedOptions = options ?? {};\n\n // Validate JSON parser options\n if (normalizedOptions.json?.raw !== undefined && typeof normalizedOptions.json.raw !== 'boolean') {\n throw new Error('JSON parser raw option must be a boolean');\n }\n\n // Validate YAML parser options\n if (normalizedOptions.yaml?.raw !== undefined && typeof normalizedOptions.yaml.raw !== 'boolean') {\n throw new Error('YAML parser raw option must be a boolean');\n }\n\n return normalizedOptions;\n }\n}\n",
|
|
10
|
-
"import type { RouteRegistry } from '../RouteRegistry.ts';\nimport { HttpMethod } from 'constants/http.ts';\nimport type { IRoute, IRouteOptions } from 'types/Route.ts';\n\nexport const addGetRoute =\n (registry: RouteRegistry) =>\n (path: IRoute['path'], handler: IRoute['handler'], options?: IRouteOptions): IRoute =>\n registry.addRoute({ path, handler, method: HttpMethod.GET, ...options });\n",
|
|
11
|
-
"import type { RouteRegistry } from '../RouteRegistry.ts';\nimport { HttpMethod } from 'constants/http.ts';\nimport type { IRoute, IRouteOptions } from 'types/Route.ts';\n\nexport const addPostRoute =\n (registry: RouteRegistry) =>\n (path: IRoute['path'], handler: IRoute['handler'], options?: IRouteOptions): IRoute =>\n registry.addRoute({ path, handler, method: HttpMethod.POST, ...options });\n",
|
|
12
|
-
"import type { RouteRegistry } from '../RouteRegistry.ts';\nimport { HttpMethod } from 'constants/http.ts';\nimport type { IRoute, IRouteOptions } from 'types/Route.ts';\n\nexport const addPutRoute =\n (registry: RouteRegistry) =>\n (path: IRoute['path'], handler: IRoute['handler'], options?: IRouteOptions): IRoute =>\n registry.addRoute({ path, handler, method: HttpMethod.PUT, ...options });\n",
|
|
13
|
-
"import type { RouteRegistry } from '../RouteRegistry.ts';\nimport { HttpMethod } from 'constants/http.ts';\nimport type { IRoute, IRouteOptions } from 'types/Route.ts';\n\nexport const addDeleteRoute =\n (registry: RouteRegistry) =>\n (path: IRoute['path'], handler: IRoute['handler'], options?: IRouteOptions): IRoute =>\n registry.addRoute({ path, handler, method: HttpMethod.DELETE, ...options });\n",
|
|
14
|
-
"import type { RouteRegistry } from '../RouteRegistry.ts';\nimport { HttpMethod } from 'constants/http.ts';\nimport type { IRoute, IRouteOptions } from 'types/Route.ts';\n\nexport const addPatchRoute =\n (registry: RouteRegistry) =>\n (path: IRoute['path'], handler: IRoute['handler'], options?: IRouteOptions): IRoute =>\n registry.addRoute({ path, handler, method: HttpMethod.PATCH, ...options });\n",
|
|
15
|
-
"import { EventEmitter } from 'events';\nimport type { IRoute } from 'types/Route.ts';\nimport { RouteRegistryEvent } from 'constants/route.ts';\n\n/**\n * Manages route registration\n *\n * This class is responsible for registering routes and storing them.\n * It follows the Single Responsibility Principle by focusing only on\n * route registration and storage.\n */\nexport class RouteRegistry extends EventEmitter {\n private readonly _routes = new Map<string, IRoute>();\n\n /**\n * Get all registered routes\n */\n getRoutes(): Map<string, IRoute> {\n return this._routes;\n }\n\n /**\n * Check if a route exists\n */\n hasRoute(method: string, path: string): boolean {\n const routeKey = this.createRouteKey(method, path);\n return this._routes.has(routeKey);\n }\n\n /**\n * Get a specific route by method and path\n */\n getRoute(method: string, path: string): IRoute | undefined {\n const routeKey = this.createRouteKey(method, path);\n return this._routes.get(routeKey);\n }\n\n /**\n * Create a unique key for a route based on method and path\n */\n private createRouteKey(method: string, path: string): string {\n return `${method}:${path}`;\n }\n\n /**\n * Validate a route path\n * @throws Error if the path is invalid\n */\n private validatePath(path: string): void {\n // Path must start with a slash\n if (!path.startsWith('/')) {\n throw new Error(`Route path must start with a slash: ${path}`);\n }\n\n // Path must not have consecutive slashes\n if (path.includes('//')) {\n throw new Error(`Route path must not contain consecutive slashes: ${path}`);\n }\n\n // Path parameters must have names\n const paramRegex = /:\\w+/g;\n const params = path.match(paramRegex) ?? [];\n\n for (const param of params) {\n if (param === ':') {\n throw new Error(`Route path parameter must have a name: ${path}`);\n }\n }\n }\n\n /**\n * Register a route with the specified path, handler, and options\n */\n addRoute(options: {\n path: IRoute['path'];\n handler: IRoute['handler'];\n method: IRoute['method'];\n beforeHandler?: IRoute['beforeHandler'];\n afterHandler?: IRoute['afterHandler'];\n }): IRoute {\n const { path, handler, method, beforeHandler, afterHandler } = options;\n\n // Validate the route path\n this.validatePath(path);\n\n const route = {\n path,\n method,\n handler,\n beforeHandler: beforeHandler ?? undefined,\n afterHandler: afterHandler ?? undefined,\n };\n\n // Create unique key combining method and path\n const routeKey = this.createRouteKey(method, path);\n\n // Check for duplicate routes\n if (this._routes.has(routeKey)) {\n console.warn(`Route already exists and will be overwritten: ${method} ${path}`);\n }\n\n this._routes.set(routeKey, route);\n\n // Emit events\n this.emit(RouteRegistryEvent.ROUTE_ADDED, route);\n this.emit(RouteRegistryEvent.ROUTES_CHANGED);\n\n return route;\n }\n\n /**\n * Remove a route by method and path\n * @returns true if the route was removed, false if it didn't exist\n */\n removeRoute(method: string, path: string): boolean {\n const routeKey = this.createRouteKey(method, path);\n const route = this._routes.get(routeKey);\n\n if (!route) {\n return false;\n }\n\n const deleted = this._routes.delete(routeKey);\n\n if (deleted) {\n // Emit events\n this.emit(RouteRegistryEvent.ROUTE_REMOVED, route);\n this.emit(RouteRegistryEvent.ROUTES_CHANGED);\n }\n\n return deleted;\n }\n\n /**\n * Register a group of routes with a common prefix and optional beforeGroup handler\n */\n addGroup(prefix: IRoute['path'], routes: Array<IRoute>, options?: { beforeGroup: IRoute['beforeGroup'] }): void {\n // Validate the prefix\n this.validatePath(prefix);\n\n // Ensure prefix ends with a slash if it's not just a slash\n let normalizedPrefix = '';\n if (prefix === '/') {\n normalizedPrefix = '';\n } else if (prefix.endsWith('/')) {\n normalizedPrefix = prefix;\n } else {\n normalizedPrefix = `${prefix}/`;\n }\n\n for (const route of routes) {\n // Ensure route path starts with a slash\n const routePath = route.path.startsWith('/') ? route.path : `/${route.path}`;\n\n // Combine prefix and route path\n const fullPath = `${normalizedPrefix}${routePath.substring(1)}`;\n\n const routeKey = this.createRouteKey(route.method, fullPath);\n\n this._routes.set(routeKey, {\n ...route,\n path: fullPath,\n beforeGroup: options?.beforeGroup,\n });\n\n // Emit events\n this.emit(RouteRegistryEvent.ROUTE_ADDED, this._routes.get(routeKey));\n }\n\n this.emit(RouteRegistryEvent.ROUTES_CHANGED);\n }\n\n /**\n * Register multiple routes at once\n */\n addRoutes(routes: Array<IRoute>): void {\n for (const route of routes) {\n // Validate the route path\n this.validatePath(route.path);\n\n const routeKey = this.createRouteKey(route.method, route.path);\n this._routes.set(routeKey, route);\n\n // Emit events\n this.emit(RouteRegistryEvent.ROUTE_ADDED, route);\n }\n\n this.emit(RouteRegistryEvent.ROUTES_CHANGED);\n }\n\n /**\n * Remove all routes\n */\n clearRoutes(): void {\n this._routes.clear();\n this.emit(RouteRegistryEvent.ROUTES_CHANGED);\n }\n\n /**\n * Get the number of registered routes\n */\n get routeCount(): number {\n return this._routes.size;\n }\n}\n",
|
|
16
|
-
"import type { Request } from 'core/Request/Request.ts';\nimport type { RouteRegistry } from 'core/Route/RouteRegistry.ts';\nimport type { IRoute } from 'types/Route.ts';\n\n/**\n * Handles route lookup and matching\n *\n * This class is responsible for finding routes based on HTTP requests.\n * It follows the Single Responsibility Principle by focusing only on\n * route lookup and matching logic.\n */\nexport class RouteFinder {\n // Cache for pattern routes to avoid recomputing regex patterns\n private readonly patternRouteCache = new Map<string, Array<{ pattern: RegExp; route: IRoute }>>();\n\n constructor(private readonly routeRegistry: RouteRegistry) {\n // Initialize pattern route cache\n this.buildPatternRouteCache();\n }\n\n /**\n * Builds a cache of pattern routes for faster lookup\n * This is called on initialization and when routes are updated\n */\n private buildPatternRouteCache(): void {\n const routes = this.routeRegistry.getRoutes();\n\n // Clear existing cache\n this.patternRouteCache.clear();\n\n // Group pattern routes by method for faster lookup\n for (const [, route] of routes) {\n if (route.path.includes(':')) {\n // This is a pattern route\n const { method } = route;\n const patternRoutes = this.patternRouteCache.get(method) ?? [];\n\n // Convert route pattern to regex for matching\n const regexPattern = this.createRouteRegex(route.path);\n\n patternRoutes.push({\n pattern: regexPattern,\n route,\n });\n\n this.patternRouteCache.set(method, patternRoutes);\n }\n }\n }\n\n /**\n * Creates a regex pattern from a route path\n * @param path The route path pattern (e.g., /users/:id)\n * @returns A RegExp object for matching paths\n */\n private createRouteRegex(path: string): RegExp {\n // Replace :param with named capture groups for better parameter extraction\n const regexPattern = path\n .replace(/:[^/]+/g, '([^/]+)')\n // Escape special regex characters except for the capture groups\n .replace(/(?:[.+*?^$()[\\]{}|])/g, '\\\\$&');\n\n return new RegExp(`^${regexPattern}$`);\n }\n\n /**\n * Find a route by method and path\n */\n findRoute(method: string, path: string): IRoute | undefined {\n return this.routeRegistry.getRoute(method, path);\n }\n\n /**\n * Find a route based on the incoming request\n * First tries exact match, then falls back to pattern matching for route parameters\n */\n findRouteFromRequest(request: Request): IRoute | undefined {\n // Normalize path by removing trailing slash (except for root path)\n const normalizedPath = request.path !== '/' && request.path.endsWith('/') ? request.path.slice(0, -1) : request.path;\n\n // First try exact match with normalized path\n const exactMatch = this.findRoute(request.method, normalizedPath);\n if (exactMatch) return exactMatch;\n\n // If no exact match, check pattern routes for this method\n const patternRoutes = this.patternRouteCache.get(request.method);\n if (!patternRoutes) return undefined;\n\n // Try to match against pattern routes\n for (const { pattern, route } of patternRoutes) {\n if (pattern.test(normalizedPath)) {\n return route;\n }\n }\n\n return undefined;\n }\n\n /**\n * Extract parameters from a path based on a route pattern\n * @param path The actual path (e.g., /users/123)\n * @param pattern The route pattern (e.g., /users/:id)\n * @returns An object with parameter names as keys and their values\n */\n extractParamsFromPath(path: string, pattern: string): Record<string, string> {\n const params: Record<string, string> = {};\n\n // If there are no parameters in the pattern, return empty object\n if (!pattern.includes(':')) {\n return params;\n }\n\n // Remove query string if present\n const pathWithoutQuery = path.split('?')[0] ?? '';\n\n // Split the path and pattern into segments\n const pathSegments = pathWithoutQuery.split('/').filter(Boolean);\n const patternSegments = pattern.split('/').filter(Boolean);\n\n // Match each segment and extract parameters\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n\n // If this segment is a parameter (starts with :)\n if (patternSegment?.startsWith(':')) {\n const paramName = patternSegment.substring(1); // Remove the : prefix\n\n if (i < pathSegments.length) {\n const paramValue = pathSegments[i];\n\n if (paramValue) {\n params[paramName] = decodeURIComponent(paramValue);\n }\n }\n }\n }\n\n return params;\n }\n\n /**\n * Update the pattern route cache when routes are modified\n * This should be called whenever routes are added or removed\n */\n updatePatternRouteCache(): void {\n this.buildPatternRouteCache();\n }\n}\n",
|
|
17
|
-
"import type { TRequestBody } from 'types/http/Request.ts';\nimport { ContentType } from 'constants/http.ts';\nimport type { IContentDisposition, IUploadedFile, TYamlData } from 'types/index.ts';\nimport { calculateContentLength } from 'utils/string.utils.ts';\nimport { parseYaml } from 'core/Request/parsers/fileParsers/yaml.ts';\nimport type { IServerOptions } from 'types/Server.ts';\n\n/**\n * Extract Content-Type from headers\n *\n * @param headers - Raw headers string\n * @returns Content-Type or undefined if not found\n */\nexport const extractContentType = (headers: string): string | undefined => {\n const lines = headers.split('\\r\\n');\n const contentTypeLine = lines.find((line) => line.toLowerCase().startsWith('content-type:'));\n if (!contentTypeLine) return undefined;\n\n const contentType = contentTypeLine.slice(contentTypeLine.indexOf(':') + 1).trim();\n return contentType;\n};\n\n/**\n * Parse Content-Disposition header\n *\n * @param header - Raw header string\n * @returns Object with name and optional filename\n */\nexport const parseContentDisposition = (header: string): IContentDisposition => {\n // Initialize with empty string for name and no filename property\n const result = { name: '' };\n\n // Find the Content-Disposition line\n const lines = header.split('\\r\\n');\n const dispositionLine = lines.find((line) => line.toLowerCase().startsWith('content-disposition:'));\n if (!dispositionLine) return result;\n\n // Extract name and filename\n const nameMatch = /name=\"(?<name>[^\"]*)\"/.exec(dispositionLine);\n const filenameMatch = /filename=\"(?<filename>[^\"]*)\"/.exec(dispositionLine);\n\n if (nameMatch?.groups?.name) {\n result.name = nameMatch.groups.name;\n }\n\n if (filenameMatch?.groups?.filename) {\n // Only add filename property if it exists\n Object.assign(result, { filename: filenameMatch.groups.filename });\n }\n\n return result;\n};\n\n/**\n * Split a multipart section into headers and content\n *\n * @param section - Raw multipart section string\n * @returns Tuple containing headers and content\n */\nconst splitMultipartSection = (section: string): [string, string] => {\n // Remove leading newline if present\n const trimmedSection = section.startsWith('\\r\\n') ? section.slice(2) : section;\n\n // Find the double newline that separates headers from content\n const headerEndIndex = trimmedSection.indexOf('\\r\\n\\r\\n');\n if (headerEndIndex === -1) return ['', ''];\n\n const headers = trimmedSection.slice(0, headerEndIndex);\n const content = trimmedSection.slice(headerEndIndex + 4).trim(); // +4 for \\r\\n\\r\\n and trim to remove trailing newlines\n\n return [headers, content];\n};\n\n/**\n * Parse multipart form data request body\n *\n * @param body - Raw multipart form data string\n * @returns Parsed form data object with fields and files\n * @throws Error if multipart format is invalid\n */\nexport const parseMultipartFormData = (body: string, parserOptions: IServerOptions['parserOptions']): TRequestBody => {\n const result: {\n fields: Record<string, string>;\n files: Array<IUploadedFile>;\n } = {\n fields: {},\n files: [],\n };\n\n // Extract the boundary from the Content-Type header\n // In real requests, the boundary is in the Content-Type header, not in the body\n // For our tests, we'll check if the body starts with a boundary\n const boundaryMatch = /^--(?<boundary>[^\\r\\n]+)/.exec(body);\n const boundary = boundaryMatch?.groups?.boundary ?? null;\n\n if (!boundary) {\n throw new Error('Invalid multipart form data: missing boundary');\n }\n\n // Split the body into parts using the boundary\n const parts = body.split(`--${boundary}`).slice(1); // Skip the first empty part\n\n for (const part of parts) {\n // Skip empty parts and the final boundary marker\n if (!part || part.trim() === '--') continue;\n\n // Parse the part headers\n const [headersSection, contentSection] = splitMultipartSection(part);\n if (!headersSection || !contentSection) continue;\n\n // Parse the Content-Disposition header\n const contentDisposition = parseContentDisposition(headersSection);\n if (!contentDisposition.name) continue;\n\n // Check if this is a file upload\n if (contentDisposition.filename) {\n result.files.push(handleFileUpload({ contentDisposition, contentSection, headersSection, parserOptions }));\n } else {\n // This is a regular form field\n result.fields[contentDisposition.name] = contentSection;\n }\n }\n\n return result;\n};\n\nconst handleFileUpload = ({\n contentDisposition,\n contentSection,\n headersSection,\n parserOptions,\n}: {\n contentDisposition: IContentDisposition;\n contentSection: string;\n headersSection: string;\n parserOptions: IServerOptions['parserOptions'];\n}): IUploadedFile => {\n const contentType = extractContentType(headersSection) ?? 'application/octet-stream';\n\n // Create a file object\n const file: IUploadedFile = {\n filename: contentDisposition.filename ?? '',\n contentType,\n size: calculateContentLength(contentSection),\n content: contentSection,\n };\n\n if ((contentType === ContentType.YAML_APPLICATION || contentType === ContentType.YAML_TEXT) && typeof file.content === 'string') {\n if (parserOptions?.yaml?.raw) return file;\n file.content = <TYamlData>(<unknown>parseYaml(file.content));\n }\n\n return file;\n};\n",
|
|
18
|
-
"/**\n * String manipulation utilities\n *\n * This file encapsulates string manipulation utilities used throughout the framework.\n */\n\n/**\n * Divides a string into two parts based on a separator\n * @param str The string to divide\n * @param separator The separator to use\n * @returns A tuple containing the first part and the rest\n */\nexport const divideString = (str: string, separator: string): [string, string] => {\n const index = str.indexOf(separator);\n if (index === -1) {\n return [str, ''];\n }\n const first = str.slice(0, index);\n const rest = str.slice(index + separator.length);\n return [first, rest];\n};\n\n/**\n * Calculates the content length of a string in bytes\n * @param body The string to calculate the length of\n * @returns The length of the string in bytes\n */\nexport const calculateContentLength = (body: string): number =>\n // Use TextEncoder to correctly calculate UTF-8 byte length\n new TextEncoder().encode(body).length;\n",
|
|
19
|
-
"/* eslint-disable max-lines */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport type { IKeyValueParams, IProcessItemParams, IStackItem, TAnchorMap, TYamlData } from 'types/parsers/fileParsers/Yaml.ts';\n\n/**\n * Parse YAML request body\n *\n * @param body - Raw YAML string\n * @returns Parsed YAML object\n * @throws Error if YAML is invalid\n */\nexport const parseYaml = (body: string): TYamlData => {\n try {\n // The result of parseYamlDocument is TYamlData, but we need to return TRequestBody\n // Since TYamlData is a valid subset of TRequestBody, we can safely cast it\n return parseYamlDocument(body);\n } catch (e) {\n throw new Error(`Invalid YAML: ${e instanceof Error ? e.message : String(e)}`);\n }\n};\n\n/**\n * Parse a complete YAML document\n *\n * @param yamlString - Raw YAML string\n * @returns Parsed YAML object\n */\nconst parseYamlDocument = (yamlString: string): TYamlData => {\n // Simple YAML parsing implementation\n // This is a basic implementation and doesn't handle all YAML features\n const result = <Record<string, TYamlData>>Object.create(null);\n\n // Split into lines\n const lines = yamlString.split(/\\r?\\n/);\n\n // Track indentation levels and their corresponding objects\n const stack: Array<IStackItem> = [{ indent: -1, obj: result }];\n\n // Track anchors for reference\n const anchors: TAnchorMap = {};\n\n // Process each line\n for (let i = 0; i < lines.length; i++) {\n try {\n const line = lines[i];\n if (line !== undefined) {\n processYamlLine(line, stack, i + 1, anchors);\n }\n } catch (error) {\n // Add line number to error message\n throw new Error(`Line ${i + 1}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n return result;\n};\n\n/**\n * Process a single line of YAML\n *\n * @param line - A single line from the YAML document\n * @param stack - The current stack of objects being built\n * @param lineNumber - The current line number (for error reporting)\n * @param anchors - Map of anchors to their values\n */\n\nconst processYamlLine = (line: string, stack: Array<IStackItem>, lineNumber = 0, anchors: TAnchorMap = {}): void => {\n // Skip empty lines and comments\n if (!line || line.trim() === '' || line.trim().startsWith('#')) return;\n\n // Calculate indentation level\n const indent = line.search(/\\S/);\n const content = line.trim();\n\n // Check if we're in a multiline string context\n const lastStackItem = stack[stack.length - 1];\n if (lastStackItem?.multilineKey) {\n processMultilineString(line, indent, stack);\n return;\n }\n\n // Process different line types\n processLineByType(content, indent, stack, lineNumber, anchors);\n};\n\n/**\n * Process a line based on its type (list item, key-value, anchor, alias)\n *\n * @param content - The trimmed content of the line\n * @param indent - The indentation level\n * @param stack - The current stack of objects being built\n * @param lineNumber - The current line number\n * @param anchors - Map of anchors to their values\n */\n\nconst processLineByType = (content: string, indent: number, stack: Array<IStackItem>, lineNumber: number, anchors: TAnchorMap): void => {\n if (content.startsWith('-')) {\n // List item\n processListItem(content, indent, stack, lineNumber, anchors);\n } else if (content.includes(':')) {\n processKeyValuePair(content, indent, stack, lineNumber, anchors);\n } else if (content.startsWith('&')) {\n // This is an anchor definition, handled in processKeyValuePair\n } else if (content.startsWith('*')) {\n // This is an alias reference\n processAliasReference(content, stack, anchors);\n }\n};\n\n/**\n * Process an alias reference (*alias)\n *\n * @param content - The line content\n * @param stack - The stack of objects being built\n * @param anchors - Map of anchors to their values\n */\nconst processAliasReference = (content: string, stack: Array<IStackItem>, anchors: TAnchorMap): void => {\n // Extract the alias name\n const aliasName = content.substring(1).trim();\n\n // Check if the alias exists\n if (!(aliasName in anchors)) {\n throw new Error(`Unknown alias: ${aliasName}`);\n }\n\n // Get the referenced value\n const referencedValue = anchors[aliasName];\n\n // Get the current context\n const lastStackItem = stack[stack.length - 1];\n if (!lastStackItem) return;\n\n // If we're in an array, add the referenced value to it\n if (lastStackItem.isArray && Array.isArray(lastStackItem.obj)) {\n // We need to ensure the referenced value is a valid TYamlData\n lastStackItem.obj.push(<TYamlData>referencedValue);\n }\n // Otherwise, we can't handle standalone aliases outside of arrays\n // In a real implementation, we would need to handle this case\n};\n\n/**\n * Process a multiline string\n *\n * @param line - The current line\n * @param indent - The indentation level\n * @param stack - The stack of objects being built\n */\nconst processMultilineString = (line: string, indent: number, stack: Array<IStackItem>): void => {\n const lastStackItem = stack[stack.length - 1];\n if (!lastStackItem || !lastStackItem.multilineKey) return;\n\n // If this line has less indentation than the multiline string started with,\n // we've reached the end of the multiline string\n if (indent <= lastStackItem.indent) {\n finishMultilineString(lastStackItem);\n\n // Process this line normally\n processYamlLine(line, stack);\n return;\n }\n\n // Add this line to the multiline value\n const lineContent = line.slice(lastStackItem.indent + 2); // +2 for the extra indentation\n if (lastStackItem.multilineValue) {\n lastStackItem.multilineValue += `\\n${lineContent}`;\n } else {\n lastStackItem.multilineValue = lineContent;\n }\n};\n\n/**\n * Finish processing a multiline string and add it to the parent object\n *\n * @param stackItem - The stack item containing the multiline string\n */\nconst finishMultilineString = (stackItem: IStackItem): void => {\n // Process the accumulated multiline value\n if (typeof stackItem.obj === 'object' && stackItem.obj !== null && !Array.isArray(stackItem.obj) && stackItem.multilineKey) {\n const parent = stackItem.obj;\n const value = stackItem.multilineValue ?? '';\n const key = stackItem.multilineKey;\n\n // Process based on the multiline type\n if (stackItem.multilineType === 'literal') {\n // Preserve line breaks in literal style (|)\n parent[key] = value;\n } else {\n // Replace line breaks with spaces in folded style (>)\n parent[key] = value.replace(/\\n/g, ' ');\n }\n }\n\n // Clear multiline context\n delete stackItem.multilineKey;\n delete stackItem.multilineValue;\n delete stackItem.multilineType;\n};\n\n/**\n * Process a list item line from YAML\n *\n * @param content - The trimmed content of the line\n * @param indent - The indentation level\n * @param stack - The current stack of objects being built\n * @param lineNumber - The current line number\n * @param anchors - Map of anchors to their values\n */\n\nconst processListItem = (content: string, indent: number, stack: Array<IStackItem>, lineNumber = 0, anchors: TAnchorMap = {}): void => {\n // Remove the dash and trim\n const itemContent = content.substring(1).trim();\n\n // Adjust the stack based on indentation\n adjustStack(stack, indent);\n\n // Get parent object safely\n const lastStackItem = stack[stack.length - 1];\n if (!lastStackItem) return;\n\n // Check if we're already in an array context\n if (lastStackItem.isArray && Array.isArray(lastStackItem.obj)) {\n processItemInExistingArray(\n {\n itemContent,\n indent,\n stack,\n array: lastStackItem.obj,\n lineNumber,\n },\n anchors,\n );\n } else {\n // If we're at the root level and there's a key in the parent object that matches the array key\n if (typeof lastStackItem.obj === 'object' && lastStackItem.obj !== null && !Array.isArray(lastStackItem.obj)) {\n const parent = lastStackItem.obj;\n const key = lastStackItem.arrayKey;\n\n // If we have a specific key for this array\n if (key && key in parent) {\n // If the property exists but isn't an array yet, convert it to an array\n if (!Array.isArray(parent[key])) {\n parent[key] = [];\n }\n\n // Use the existing array\n const array = <Array<TYamlData>>parent[key];\n processItemInExistingArray(\n {\n itemContent,\n indent,\n stack,\n array,\n lineNumber,\n },\n anchors,\n );\n\n // Push the array onto the stack\n stack.push({\n indent,\n obj: array,\n isArray: true,\n });\n\n return;\n }\n }\n\n // Create a new array with the appropriate key\n createNewArrayWithItem(\n {\n itemContent,\n indent,\n stack,\n lastStackItem,\n lineNumber,\n },\n anchors,\n );\n }\n};\n\n/**\n * Process an item in an existing array\n *\n * @param params - Parameters for processing an item in an array\n * @param anchors - Map of anchors to their values\n */\nconst processItemInExistingArray = (params: IProcessItemParams, anchors: TAnchorMap = {}): void => {\n const { itemContent, indent, stack, array, lineNumber } = params;\n\n if (!array) return;\n\n // Extract anchor and content\n const { processedContent, anchorName } = extractAnchorInfo(itemContent);\n\n if (processedContent.includes(':')) {\n // This is an object in an array\n const newObj = <Record<string, TYamlData>>Object.create(null);\n array.push(newObj);\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = newObj;\n }\n\n // Process the key-value pair within this object\n const [key, value] = processedContent.split(':', 2);\n\n if (key) {\n processKeyValueInArrayItem({\n key,\n value,\n indent,\n stack,\n obj: newObj,\n lineNumber: lineNumber ?? 0,\n });\n }\n } else {\n // Simple value in array\n const parsedValue = parseYamlValue(processedContent);\n array.push(parsedValue);\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = parsedValue;\n }\n }\n};\n\n/**\n * Extract anchor information from a YAML line\n *\n * @param content - The content to extract from\n * @returns The processed content and anchor name\n */\nconst extractAnchorInfo = (content: string): { processedContent: string; anchorName: string | null } => {\n let processedContent = content;\n let anchorName: string | null = null;\n\n if (content.startsWith('&')) {\n const spaceIndex = content.indexOf(' ');\n if (spaceIndex > 1) {\n anchorName = content.substring(1, spaceIndex);\n processedContent = content.substring(spaceIndex + 1);\n }\n }\n\n return { processedContent, anchorName };\n};\n\n/**\n * Process a key-value pair within an array item\n *\n * @param params - Parameters for processing a key-value pair\n */\nconst processKeyValueInArrayItem = (params: IKeyValueParams): void => {\n const { key, value, indent, stack, obj } = params;\n\n if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {\n return; // Can only add properties to objects\n }\n\n const objRecord = obj;\n const trimmedKey = key.trim();\n const trimmedValue = value?.trim() ?? '';\n\n if (trimmedValue === '') {\n // Nested object\n objRecord[trimmedKey] = <Record<string, TYamlData>>Object.create(null);\n stack.push({\n indent: indent + 2, // Assume nested items are indented\n obj: <Record<string, TYamlData>>objRecord[trimmedKey],\n });\n } else if (trimmedValue === '|' || trimmedValue === '>') {\n // Multiline string\n // | = literal style (preserve line breaks)\n // > = folded style (replace line breaks with spaces)\n if (stack.length > 0) {\n const lastItem = stack[stack.length - 1];\n if (lastItem) {\n lastItem.multilineKey = trimmedKey;\n lastItem.multilineType = trimmedValue === '|' ? 'literal' : 'folded';\n }\n }\n } else {\n // Simple key-value\n objRecord[trimmedKey] = parseYamlValue(trimmedValue);\n }\n};\n\n/**\n * Create a new array and add the first item\n *\n * @param params - Parameters for creating a new array\n * @param anchors - Map of anchors to their values\n */\nconst createNewArrayWithItem = (params: IProcessItemParams, anchors: TAnchorMap = {}): void => {\n const { itemContent, indent, stack, lastStackItem } = params;\n\n if (!lastStackItem) return;\n\n // We need to create a new array\n if (typeof lastStackItem.obj === 'object' && lastStackItem.obj !== null && !Array.isArray(lastStackItem.obj)) {\n const parent = lastStackItem.obj;\n const arrayKey = lastStackItem.arrayKey ?? 'items'; // Default key if none exists\n\n // Create the array\n parent[arrayKey] = <Array<TYamlData>>[];\n const newArray = <Array<TYamlData>>parent[arrayKey];\n\n // Add the first item to the array\n addFirstItemToArray(itemContent, indent, stack, newArray, anchors);\n }\n};\n\n/**\n * Add the first item to a newly created array\n *\n * @param itemContent - The content of the item\n * @param indent - The indentation level\n * @param stack - The stack of objects being built\n * @param newArray - The array to add the item to\n * @param anchors - Map of anchors to their values\n */\n\nconst addFirstItemToArray = (itemContent: string, indent: number, stack: Array<IStackItem>, newArray: Array<TYamlData>, anchors: TAnchorMap): void => {\n // Extract anchor and content\n const { processedContent, anchorName } = extractAnchorInfo(itemContent);\n\n // Add the first item\n if (processedContent.includes(':')) {\n // This is an object in an array\n const newObj = <Record<string, TYamlData>>Object.create(null);\n newArray.push(newObj);\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = newObj;\n }\n\n // Process the key-value pair within this object\n const [key, value] = processedContent.split(':', 2);\n\n if (key) {\n processKeyValueInArrayItem({\n key,\n value,\n indent,\n stack,\n obj: newObj,\n lineNumber: 0,\n });\n }\n } else {\n // Simple value in array\n const parsedValue = parseYamlValue(processedContent);\n newArray.push(parsedValue);\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = parsedValue;\n }\n }\n\n // Push the array onto the stack\n stack.push({\n indent,\n obj: newArray,\n isArray: true,\n });\n};\n\n/**\n * Process a key-value pair line from YAML\n *\n * @param content - The trimmed content of the line\n * @param indent - The indentation level of the line\n * @param stack - The current stack of objects being built\n * @param lineNumber - The current line number\n * @param anchors - Map of anchors to their values\n */\n\nconst processKeyValuePair = (content: string, indent: number, stack: Array<IStackItem>, lineNumber = 0, anchors: TAnchorMap = {}): void => {\n // Extract key-value and anchor information\n const { processedContent, key, value, anchorName } = extractKeyValueAnchorInfo(content);\n\n if (!key) return;\n\n const trimmedKey = key.trim();\n const trimmedValue = value?.trim() ?? '';\n\n // Adjust the stack based on indentation\n adjustStack(stack, indent);\n\n // Get parent object safely\n const lastStackItem = stack[stack.length - 1];\n if (!lastStackItem) return;\n\n // Handle array context\n if (handleArrayContext(content, indent, stack, lastStackItem, lineNumber, anchors)) {\n return;\n }\n\n // Ensure we're working with an object\n if (typeof lastStackItem.obj !== 'object' || lastStackItem.obj === null || Array.isArray(lastStackItem.obj)) {\n return; // Can only add properties to objects\n }\n\n const parent = lastStackItem.obj;\n\n // Process the key-value pair based on the value type\n processKeyValueByType(trimmedKey, trimmedValue, processedContent, indent, stack, parent, lastStackItem, anchorName, anchors);\n};\n\n/**\n * Extract key-value and anchor information from a line\n *\n * @param content - The line content\n * @returns The processed content, key, value, and anchor name\n */\nconst extractKeyValueAnchorInfo = (\n content: string,\n): {\n processedContent: string;\n key: string | undefined;\n value: string | undefined;\n anchorName: string | null;\n} => {\n let processedContent = content;\n let anchorName: string | null = null;\n\n const colonIndex = content.indexOf(':');\n if (colonIndex !== -1) {\n const key = content.substring(0, colonIndex).trim();\n let value = content.substring(colonIndex + 1).trim();\n\n if (value.startsWith('&')) {\n const spaceIndex = value.indexOf(' ');\n if (spaceIndex > 1) {\n anchorName = value.substring(1, spaceIndex);\n value = value.substring(spaceIndex + 1);\n processedContent = `${key}: ${value}`;\n }\n }\n }\n\n const [key, value] = processedContent.split(':', 2);\n\n return { processedContent, key, value, anchorName };\n};\n\n/**\n * Handle array context in key-value processing\n *\n * @param content - The line content\n * @param indent - The indentation level\n * @param stack - The stack of objects being built\n * @param lastStackItem - The last item on the stack\n * @param lineNumber - The current line number\n * @param anchors - Map of anchors to their values\n * @returns True if array context was handled\n */\n\nconst handleArrayContext = (\n content: string,\n indent: number,\n stack: Array<IStackItem>,\n lastStackItem: IStackItem,\n lineNumber: number,\n anchors: TAnchorMap,\n): boolean => {\n // Make sure we're working with an object, not an array\n if (lastStackItem.isArray) {\n // If the current context is an array, we need to exit it\n stack.pop();\n // Try again with the parent context\n processKeyValuePair(content, indent, stack, lineNumber, anchors);\n return true;\n }\n\n return false;\n};\n\n/**\n * Process a key-value pair based on the value type\n *\n * @param key - The key\n * @param value - The value\n * @param processedContent - The processed content\n * @param indent - The indentation level\n * @param stack - The stack of objects being built\n * @param parent - The parent object\n * @param lastStackItem - The last item on the stack\n * @param anchorName - The anchor name\n * @param anchors - Map of anchors to their values\n */\n\nconst processKeyValueByType = (\n key: string,\n value: string,\n processedContent: string,\n indent: number,\n stack: Array<IStackItem>,\n parent: Record<string, TYamlData>,\n lastStackItem: IStackItem,\n anchorName: string | null,\n anchors: TAnchorMap,\n): void => {\n if (value === '') {\n // Handle empty value (object or array)\n handleEmptyValue(key, processedContent, indent, stack, parent, anchorName, anchors);\n } else if (value === '|' || value === '>') {\n // Multiline string\n // | = literal style (preserve line breaks)\n // > = folded style (replace line breaks with spaces)\n lastStackItem.multilineKey = key;\n lastStackItem.multilineType = value === '|' ? 'literal' : 'folded';\n } else {\n // This is a key with a value\n const parsedValue = parseYamlValue(value);\n parent[key] = parsedValue;\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = parsedValue;\n }\n }\n};\n\n/**\n * Handle empty value in key-value pair (object or array)\n *\n * @param key - The key\n * @param processedContent - The processed content\n * @param indent - The indentation level\n * @param stack - The stack of objects being built\n * @param parent - The parent object\n * @param anchorName - The anchor name\n * @param anchors - Map of anchors to their values\n */\n\nconst handleEmptyValue = (\n key: string,\n processedContent: string,\n indent: number,\n stack: Array<IStackItem>,\n parent: Record<string, TYamlData>,\n anchorName: string | null,\n anchors: TAnchorMap,\n): void => {\n // Check if the next line might be a list item\n // This is a key that will contain an array\n if (processedContent.endsWith(':')) {\n // Push a context for this key, marking it as potentially an array\n parent[key] = <Record<string, TYamlData>>Object.create(null);\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = parent[key];\n }\n\n stack.push({\n indent,\n obj: <Record<string, TYamlData>>parent[key],\n arrayKey: key,\n });\n } else {\n // This is an object key with nested values\n parent[key] = <Record<string, TYamlData>>Object.create(null);\n\n // Store anchor if defined\n if (anchorName) {\n anchors[anchorName] = parent[key];\n }\n\n stack.push({\n indent,\n obj: <Record<string, TYamlData>>parent[key],\n });\n }\n};\n\n/**\n * Adjust the stack based on indentation level\n *\n * @param stack - The current stack of objects being built\n * @param currentIndent - The indentation level of the current line\n */\nconst adjustStack = (stack: Array<IStackItem>, currentIndent: number): void => {\n // Pop stack until we find the parent object for this indentation\n while (stack.length > 1) {\n const lastItem = stack[stack.length - 1];\n if (lastItem && lastItem.indent >= currentIndent) {\n stack.pop();\n } else {\n break;\n }\n }\n};\n\n/**\n * Parse a YAML value, handling different types\n *\n * @param value - Raw YAML value string\n * @returns Parsed value (string, number, boolean, null)\n */\nexport const parseYamlValue = (value: string): TYamlData => {\n // Check for quoted strings\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n return value.slice(1, -1);\n }\n\n // Check for null/undefined values\n if (isNullValue(value)) {\n return null;\n }\n\n // Check for boolean values\n const booleanValue = parseBooleanValue(value);\n if (booleanValue !== undefined) {\n return booleanValue;\n }\n\n // Check for special number values\n const specialNumber = parseSpecialNumber(value);\n if (specialNumber !== undefined) {\n return specialNumber;\n }\n\n // Check for date values\n const dateValue = parseDateValue(value);\n if (dateValue instanceof Date) {\n return dateValue.toISOString(); // Convert Date to string for YAML\n }\n\n // Check for numeric values\n const numericValue = parseNumericValue(value);\n if (numericValue !== undefined) {\n return numericValue;\n }\n\n // Default to string\n return value;\n};\n\n/**\n * Check if a value represents null in YAML\n *\n * @param value - The value to check\n * @returns True if the value represents null\n */\nconst isNullValue = (value: string): boolean => value === 'null' || value === '~' || value === '';\n\n/**\n * Parse a boolean value from YAML\n *\n * @param value - The value to parse\n * @returns The boolean value or undefined if not a boolean\n */\nconst parseBooleanValue = (value: string): boolean | undefined => {\n const lowerValue = value.toLowerCase();\n if (lowerValue === 'true') return true;\n if (lowerValue === 'false') return false;\n return undefined;\n};\n\n/**\n * Parse special number values (Infinity, NaN)\n *\n * @param value - The value to parse\n * @returns The special number or undefined\n */\nconst parseSpecialNumber = (value: string): number | undefined => {\n // Check for infinity\n if (value === '.inf' || value === '.Inf' || value === '.INF') return Infinity;\n if (value === '-.inf' || value === '-.Inf' || value === '-.INF') return -Infinity;\n\n // Check for NaN\n if (value === '.nan' || value === '.NaN' || value === '.NAN') return NaN;\n\n return undefined;\n};\n\n/**\n * Parse a date value from YAML\n *\n * @param value - The value to parse\n * @returns A Date object or the original value if not a valid date\n */\nconst parseDateValue = (value: string): Date | string => {\n // ISO 8601 date regex with non-capturing groups\n const dateRegex = /^\\d{4}-\\d{2}-\\d{2}(?:T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})?)?$/;\n\n if (dateRegex.test(value)) {\n const date = new Date(value);\n return isNaN(date.getTime()) ? value : date;\n }\n\n return value;\n};\n\n/**\n * Parse numeric values (decimal, hex, octal)\n *\n * @param value - The value to parse\n * @returns The numeric value or undefined\n */\nconst parseNumericValue = (value: string): number | undefined => {\n // Check for decimal numbers\n if (/^-?\\d+(?:\\.\\d+)?$/.test(value)) {\n return Number(value);\n }\n\n // Check for hexadecimal\n if (/^0x[0-9a-fA-F]+$/.test(value)) {\n return parseInt(value, 16);\n }\n\n // Check for octal\n if (/^0o[0-7]+$/.test(value)) {\n return parseInt(value.substring(2), 8);\n }\n\n return undefined;\n};\n",
|
|
20
|
-
"import type { TRequestBody } from 'types/http/Request.ts';\nimport type { TJsonData } from 'types/index.ts';\n\n/**\n * Parse JSON request body\n *\n * @param body - Raw JSON string\n * @returns Parsed JSON object\n * @throws Error if JSON is invalid\n */\nexport const parseApplicationJson = (body: string): TRequestBody => {\n try {\n return <TJsonData>JSON.parse(body);\n } catch (e) {\n throw new Error(`Invalid JSON: ${e instanceof Error ? e.message : String(e)}`);\n }\n};\n",
|
|
21
|
-
"import type { TRequestBody } from 'types/http/Request.ts';\nimport type { IMultipartFormData } from 'types/index.ts';\n\n/**\n * Type guard to check if the request body is multipart form data\n *\n * @param body - Request body to check\n * @returns True if the body is multipart form data\n */\nexport const isMultipartFormData = (body: TRequestBody): body is IMultipartFormData =>\n body !== null && typeof body === 'object' && 'fields' in body && 'files' in body && Array.isArray(body.files) && typeof (<any>body.fields) === 'object';\n",
|
|
22
|
-
"import type { TRequestBody } from 'types/http/Request.ts';\nimport type { TJsonData } from 'types/index.ts';\nimport { isMultipartFormData } from 'core/Request/guards/multipartFormData.ts';\n\n/**\n * Type guard to check if the request body is JSON data\n *\n * Note: This is a simple check that eliminates other known types.\n * It will return true for most object types, so use with caution.\n *\n * @param body - Request body to check\n * @returns True if the body is JSON data\n */\nexport const isJsonData = <T = unknown>(body: TRequestBody): body is TJsonData<T> => !isMultipartFormData(body) && typeof body === 'object';\n",
|
|
23
|
-
"import { parseApplicationJson, parseMultipartFormData } from 'core/Request/index.ts';\nimport type { IRoute } from 'types/Route.ts';\nimport type { IRequest, THttpMethod, TRequestBody } from 'types/http/Request.ts';\nimport { ContentType, HttpMethod } from 'constants/http.ts';\nimport { divideString } from 'utils/string.utils.ts';\nimport type { IServerOptions } from 'types/Server.ts';\n/**\n * Handles HTTP request parsing and parameter extraction\n */\nexport class Request {\n readonly protocol: IRequest['protocol'];\n readonly method: IRequest['method'];\n readonly path: IRequest['path'];\n readonly headers: IRequest['headers'];\n readonly body: IRequest['body'];\n readonly query: IRequest['query'];\n\n params: IRequest['params'];\n\n constructor(request: string, parserOptions: IServerOptions['parserOptions']) {\n const { protocol, method, path, headers, body, query, params } = this._parseRequest(request, parserOptions);\n\n this.protocol = protocol;\n this.method = method;\n this.path = path;\n this.headers = headers;\n this.body = body;\n this.query = query;\n this.params = params;\n }\n\n /**\n * Parse URL parameters from route pattern\n *\n * @param route - Route object containing path pattern\n * @param path - Actual request path\n * @returns Object with parsed parameters\n */\n parseParams = (route: IRoute): Record<string, string> => {\n const params: Record<string, string> = {};\n\n // Early returns for invalid inputs\n if (typeof route.path !== 'string') return params;\n if (typeof this.path !== 'string') return params;\n\n // Extract parameter names from route pattern\n const paramMatches = route.path.match(/:[^/]+/g);\n const paramNames = paramMatches ? paramMatches.map((param) => param.slice(1)) : [];\n\n if (paramNames.length === 0) return params;\n\n // Convert route pattern to regex with capture groups\n const pattern = route.path.replace(/:[^/]+/g, '([^/]+)');\n const regex = new RegExp(`^${pattern}$`);\n\n // Extract parameter values from path\n const match = this.path.match(regex);\n if (!match) return params;\n\n // Map parameter names to values (skip first match which is the full string)\n for (let i = 0; i < paramNames.length; i++) {\n const value = match[i + 1];\n const paramName = paramNames[i];\n\n // Only add to params if both value and paramName are defined\n if (value && paramName) {\n params[paramName] = value;\n }\n }\n\n return params;\n };\n\n private readonly _parseRequest = (request: string, parserOptions: IServerOptions['parserOptions']): IRequest => {\n /**\n * Validate the request\n */\n if (!request) throw new Error('Invalid request');\n\n /**\n * The request is a string that contains the following information:\n * - The first line contains the request method, path, and protocol\n * - The headers are separated from the body by two newlines\n */\n const [firstLine, rest] = divideString(request, '\\r\\n');\n const [method, path, protocol] = <[THttpMethod, string, string]>firstLine.split(' ', 3);\n const [headersRaw, bodyRaw] = divideString(rest, '\\r\\n\\r\\n');\n\n const parsedHeaders = this._parseHeaders(headersRaw);\n const parsedQuery = this._parseQuery(path);\n\n let parsedBody: IRequest['body'] = {};\n if (bodyRaw && method !== HttpMethod.GET && method !== HttpMethod.HEAD) {\n parsedBody = this._parseBody(parsedHeaders, bodyRaw, parserOptions);\n }\n\n return {\n protocol,\n method,\n path,\n headers: parsedHeaders,\n body: parsedBody,\n query: parsedQuery,\n params: {},\n };\n };\n\n /**\n * Parse request body based on Content-Type\n *\n * @param headers - Request headers containing Content-Type\n * @param body - Raw request body string\n * @returns Parsed request body object\n * @throws Error if Content-Type is missing or body format is invalid\n */\n\n private readonly _parseBody = (headers: IRequest['headers'], body: string, parserOptions: IServerOptions['parserOptions']): TRequestBody => {\n if (!headers['Content-Type']) {\n throw new Error('Missing Content-Type header');\n }\n\n const contentType = headers['Content-Type'];\n\n // Use a more efficient approach with early returns\n if (contentType === ContentType.JSON) {\n if (parserOptions?.json?.raw) return body;\n return parseApplicationJson(body);\n }\n\n if (contentType.includes(ContentType.MULTIPART)) {\n return parseMultipartFormData(body, parserOptions);\n }\n\n // Default case - return raw body\n return body;\n };\n\n /**\n * Parse request headers\n *\n * @param rawHeaders - Raw header string\n * @returns Object with parsed headers\n */\n private readonly _parseHeaders = (rawHeaders: string): Record<string, string> => {\n const headers: Record<string, string> = {};\n if (!rawHeaders) return headers;\n\n // Normalize line endings and split\n const normalizedHeaders = rawHeaders.replace(/\\r\\n|\\r|\\n/g, '\\n');\n const headerLines = normalizedHeaders.split('\\n');\n\n for (const line of headerLines) {\n if (!line) continue;\n\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) continue;\n\n const key = line.slice(0, colonIndex).trim();\n const value = line.slice(colonIndex + 1).trim();\n\n if (key) {\n headers[key] = value;\n }\n }\n\n return headers;\n };\n\n /**\n * Parse query parameters from URL\n *\n * @param url - URL string potentially containing query parameters\n * @returns Object with parsed query parameters\n */\n private readonly _parseQuery = (url: string): Record<string, string> => {\n if (!url) return {};\n\n if (!url.includes('?')) return {};\n\n const [, queryString] = url.split('?');\n if (!queryString) return {};\n\n const params: Record<string, string> = {};\n const pairs = queryString.split('&');\n\n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key) {\n params[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';\n }\n }\n\n return params;\n };\n}\n",
|
|
24
|
-
"import dayjs from 'dayjs';\nimport type { IHeaders, IResponse, THttpStatus, THttpStatusCode, TResponseBody } from 'types/http/Response.ts';\nimport { calculateContentLength } from 'utils/string.utils.ts';\nimport { ContentType, HttpStatus, HttpStatusCode } from 'constants/http.ts';\nimport type { Request } from 'core/Request/Request.ts';\n\n/**\n * Handles HTTP response creation, manipulation, and formatting\n */\nexport class Response {\n protected readonly protocol: IResponse['protocol'];\n protected readonly method: IResponse['method'];\n protected readonly path: IResponse['path'];\n protected status: IResponse['status'];\n protected statusCode: IResponse['statusCode'];\n protected statusText: string;\n protected headers: IResponse['headers'] = {};\n\n /**\n * Stores the original response body in its native format (object, string, etc.)\n *\n * This property preserves the original data structure and type information,\n * which is useful for:\n * 1. Maintaining type safety throughout the response lifecycle\n * 2. Allowing for potential modifications before final formatting\n * 3. Enabling different serialization strategies if needed\n * 4. Debugging and introspection of the original data\n */\n protected body: IResponse['body'] = '';\n\n /**\n * Stores the pre-formatted string representation of the body\n *\n * This property is essential for:\n * 1. Ensuring consistent string representation across the response\n * 2. Avoiding redundant formatting operations when the response is used multiple times\n * 3. Accurate Content-Length calculation based on the actual bytes to be sent\n * 4. Preventing type errors when using the body in string contexts (like template literals)\n *\n * The underscore prefix indicates this is an internal implementation detail\n * that should not be accessed directly from outside the class.\n */\n protected _formattedBody = '';\n\n // TODO - add cookie support\n\n /**\n * Default status is 200 OK\n *\n * Default headers are:\n * - Date: Current date in UTC\n * - Connection: keep-alive\n * - Keep-Alive: timeout=5, max=1000\n * - Content-Type: application/json (Default for API responses)\n * - Content-Length: 0 (Default for empty body)\n */\n constructor(request: Request) {\n this.method = request.method;\n this.path = request.path;\n this.protocol = request.protocol;\n this.statusCode = HttpStatusCode.OK;\n this.status = HttpStatus.OK;\n this.statusText = HttpStatus.OK;\n this.headers = {\n Date: dayjs().format('ddd, DD MMM YYYY HH:mm:ss [GMT]'),\n Connection: 'keep-alive',\n 'Keep-Alive': 'timeout=5, max=1000',\n 'Content-Type': ContentType.JSON, // Default to JSON for API responses\n 'Content-Length': '0', // Default for empty body\n };\n }\n\n /**\n * Add multiple headers to the response\n */\n addHeaders(headers: Array<IResponse['headers']>): void {\n for (const header of headers) {\n this.headers = { ...this.headers, ...header };\n }\n }\n\n /**\n * Remove multiple headers from the response\n */\n removeHeaders(headers: Array<keyof IHeaders>): void {\n for (const header of headers) delete this.headers[header];\n }\n\n /**\n * Modify a single header in the response\n */\n modifyHeader(header: keyof IHeaders, value: string): void {\n this.headers[header] = value;\n }\n\n /**\n * Set the HTTP status code and corresponding status text\n */\n setStatus(status: THttpStatusCode): void {\n // Map of status codes to their corresponding status and text\n const statusMap: Record<THttpStatusCode, { status: THttpStatus; text: string }> = {\n [HttpStatusCode.OK]: { status: HttpStatus.OK, text: HttpStatus.OK },\n [HttpStatusCode.CREATED]: { status: HttpStatus.CREATED, text: HttpStatus.CREATED },\n [HttpStatusCode.NO_CONTENT]: { status: HttpStatus.NO_CONTENT, text: HttpStatus.NO_CONTENT },\n [HttpStatusCode.BAD_REQUEST]: { status: HttpStatus.BAD_REQUEST, text: HttpStatus.BAD_REQUEST },\n [HttpStatusCode.UNAUTHORIZED]: { status: HttpStatus.UNAUTHORIZED, text: HttpStatus.UNAUTHORIZED },\n [HttpStatusCode.FORBIDDEN]: { status: HttpStatus.FORBIDDEN, text: HttpStatus.FORBIDDEN },\n [HttpStatusCode.NOT_FOUND]: { status: HttpStatus.NOT_FOUND, text: HttpStatus.NOT_FOUND },\n [HttpStatusCode.METHOD_NOT_ALLOWED]: { status: HttpStatus.METHOD_NOT_ALLOWED, text: HttpStatus.METHOD_NOT_ALLOWED },\n [HttpStatusCode.CONFLICT]: { status: HttpStatus.CONFLICT, text: HttpStatus.CONFLICT },\n [HttpStatusCode.UNSUPPORTED_MEDIA_TYPE]: { status: HttpStatus.UNSUPPORTED_MEDIA_TYPE, text: HttpStatus.UNSUPPORTED_MEDIA_TYPE },\n [HttpStatusCode.TOO_MANY_REQUESTS]: { status: HttpStatus.TOO_MANY_REQUESTS, text: HttpStatus.TOO_MANY_REQUESTS },\n [HttpStatusCode.INTERNAL_SERVER_ERROR]: { status: HttpStatus.INTERNAL_SERVER_ERROR, text: HttpStatus.INTERNAL_SERVER_ERROR },\n };\n\n // Get the status and text from the map, or default to OK\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const statusInfo = statusMap[status] || statusMap[HttpStatusCode.OK];\n\n this.statusCode = status;\n this.status = statusInfo.status;\n this.statusText = statusInfo.text;\n }\n\n /**\n * Set the response body and update Content-Length header\n */\n setBody(body: TResponseBody<unknown>): void {\n // Store the original body\n this.body = body;\n\n // Format the body and store the formatted version\n this._formattedBody = this._formatResponseBody(body);\n\n // By default, we keep JSON as the Content-Type for all responses\n // The user can override this with text(), html(), etc. if needed\n if (!this.headers['Content-Type']) {\n this.headers['Content-Type'] = ContentType.JSON;\n }\n\n // Update Content-Length header\n this.headers['Content-Length'] = String(calculateContentLength(this._formattedBody));\n }\n\n /**\n * Format the complete HTTP response as a string\n */\n formatHttpResponse(): string {\n const statusLine = `${this.protocol} ${this.statusCode} ${String(this.status)}`;\n\n // Format headers\n const headerLines = Object.entries(this.headers)\n .map(([key, value]) => `${key}: ${value}`)\n .join('\\r\\n');\n\n // Return the complete response using the formatted body\n return `${statusLine}\\r\\n${headerLines}\\r\\n\\r\\n${this._formattedBody}`;\n }\n\n /**\n * Format a response body as a string\n * @private Internal method for formatting the response body\n */\n private _formatResponseBody(body: TResponseBody<unknown>): string {\n // Handle null explicitly\n if (body === null) return 'null';\n\n // Handle different types\n // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n switch (typeof body) {\n case 'string':\n return body;\n case 'object':\n return JSON.stringify(body);\n default:\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return String(body);\n }\n }\n}\n",
|
|
25
|
-
"import type { Request } from 'core/Request/Request.ts';\nimport type { Response } from 'core/Response.ts';\n\n/**\n * Request/response context\n *\n * This class encapsulates the request and response objects for a single HTTP request.\n * It is passed to hooks and route handlers to provide access to the request and response.\n */\nexport class Context {\n request: Request;\n response: Response;\n\n constructor(request: Request, response: Response) {\n this.request = request;\n this.response = response;\n }\n}\n",
|
|
26
|
-
"import type { Socket } from 'net';\nimport { Request } from 'core/Request/Request.ts';\nimport { Response } from 'core/Response.ts';\nimport { Context as ContextClass } from 'core/Context.ts';\nimport type { HooksManager } from 'core/HooksManager.ts';\nimport type { RouteFinder } from 'core/Route/RouteFinder.ts';\nimport { HttpStatusCode } from 'constants/http.ts';\nimport type { TErrorFunction } from 'types/Response.ts';\nimport type { IRoute } from 'types/Route.ts';\nimport type { ConfigManager } from 'core/ConfigManager.ts';\n\n/**\n * Handles HTTP requests and routes them to the appropriate handler\n *\n * This class is responsible for:\n * 1. Receiving HTTP requests from a socket\n * 2. Finding the appropriate route\n * 3. Processing the request through hooks\n * 4. Executing the route handler\n * 5. Sending the response back to the client\n * 6. Handling any errors that occur during processing\n */\nexport class RequestHandler {\n private readonly routeFinder: RouteFinder;\n private readonly hooksManager: HooksManager;\n private readonly errorHandler: TErrorFunction;\n private readonly configManager: ConfigManager;\n\n constructor(routeFinder: RouteFinder, hooksManager: HooksManager, configManager: ConfigManager) {\n this.routeFinder = routeFinder;\n this.hooksManager = hooksManager;\n this.configManager = configManager;\n this.errorHandler = configManager.errorHandler;\n }\n\n /**\n * Main handler for incoming HTTP requests from a socket\n *\n * @param socket - The client socket connection\n * @param buffer - The raw request data\n */\n async handleSocketRequest(socket: Socket, buffer: Buffer): Promise<void> {\n const request = new Request(buffer.toString(), this.configManager.parserOptions);\n\n try {\n // Find the route for this request\n const route = this.routeFinder.findRouteFromRequest(request);\n\n // Process the request or return 404\n const response = route ? (request.parseParams(route), await this._processRequest(request, route)) : this._createNotFoundResponse(request);\n\n // Send the response\n await this._sendResponse(socket, response);\n } catch (error) {\n // Handle errors and send error response\n const errorResponse = await this._handleError(request, error);\n await this._sendResponse(socket, errorResponse);\n }\n }\n\n\n\n /**\n * Sends an HTTP response through the socket\n *\n * @param socket - The client socket connection\n * @param response - The HTTP response to send\n */\n private async _sendResponse(socket: Socket, response: Response): Promise<void> {\n await new Promise<void>((resolve) => {\n socket.write(response.formatHttpResponse(), () => resolve());\n socket.end();\n });\n }\n\n /**\n * Handles errors that occur during request processing\n *\n * @param request - The HTTP request\n * @param error - The error that occurred\n * @returns An HTTP response with error details\n */\n private async _handleError(request: Request, error: unknown): Promise<Response> {\n const context = new ContextClass(request, new Response(request));\n const errorResult = await Promise.resolve(this.errorHandler(context, error));\n context.response.setBody(errorResult);\n return context.response;\n }\n\n /**\n * Process a request through hooks and handlers\n *\n * @param request - The HTTP request\n * @param route - The matched route\n * @returns An HTTP response\n */\n private async _processRequest(request: Request, route: IRoute): Promise<Response> {\n const context = new ContextClass(request, new Response(request));\n\n // Process hooks chain\n const hooksResult = await this._processHooksChain(route, context);\n if (hooksResult) {\n return hooksResult;\n }\n\n // Process route handler\n const handlerResult = await Promise.resolve(route.handler(context));\n\n // Process afterHandler if defined\n await this.hooksManager.processAfterHandler(route, context);\n\n context.response.setBody(handlerResult);\n return context.response;\n }\n\n /**\n * Process the hooks chain (beforeAll, beforeGroup, beforeHandler)\n *\n * @param route - The matched route\n * @param context - The request context\n * @returns An HTTP response if a hook returns a result, otherwise undefined\n */\n private async _processHooksChain(route: IRoute, context: ContextClass): Promise<Response | undefined> {\n // Process global hooks\n const beforeAllResult = await this.hooksManager.processBeforeAll(route, context);\n if (beforeAllResult) {\n context.response.setBody(beforeAllResult);\n return context.response;\n }\n\n // Process group hooks\n const beforeGroupResult = await this.hooksManager.processBeforeGroup(route, context);\n if (beforeGroupResult) {\n context.response.setBody(beforeGroupResult);\n return context.response;\n }\n\n // Process handler-specific hooks\n const beforeHandlerResult = await this.hooksManager.processBeforeHandler(route, context);\n if (beforeHandlerResult) {\n context.response.setBody(beforeHandlerResult);\n return context.response;\n }\n\n return undefined;\n }\n\n /**\n * Creates a 404 Not Found response\n *\n * @param request - The HTTP request\n * @returns A 404 Not Found HTTP response\n */\n private _createNotFoundResponse(request: Request): Response {\n const context = new ContextClass(request, new Response(request));\n context.response.setStatus(HttpStatusCode.NOT_FOUND);\n context.response.setBody({ success: false, message: 'Not found' });\n return context.response;\n }\n}\n",
|
|
27
|
-
"import type { Server, Socket } from 'net';\nimport { EventEmitter } from 'events';\nimport type { ConfigManager } from './ConfigManager.ts';\nimport { ConnectionEvent } from 'constants/connection.ts';\nimport type { IConnectionStats } from 'types/Connection.ts';\n\n/**\n * Manages socket connections to the server\n *\n * The ConnectionManager is responsible for:\n * - Tracking active socket connections\n * - Managing the server's listening state\n * - Providing connection statistics\n * - Gracefully closing connections when the server shuts down\n */\nexport class ConnectionManager extends EventEmitter {\n /** Active socket connections */\n private readonly _connections = new Set<Socket>();\n /** Server instance */\n private _server: Server | null = null;\n /** Server listening state */\n private _isListening = false;\n /** Server start time */\n private _startTime = 0;\n /** Total connections since server start */\n private _totalConnections = 0;\n /** Total connection errors */\n private _connectionErrors = 0;\n /** Config manager instance */\n private readonly _configManager: ConfigManager;\n\n /**\n * Creates a new ConnectionManager instance\n *\n * @param configManager The config manager instance\n */\n constructor(configManager: ConfigManager) {\n super();\n this._configManager = configManager;\n }\n\n /**\n * Sets the server instance and configures event listeners\n *\n * @param server The server instance to manage\n */\n setServer(server: Server | null): void {\n this._server = server;\n\n if (server) {\n // Reset statistics when a new server is set\n this._totalConnections = 0;\n this._connectionErrors = 0;\n }\n }\n\n /**\n * Adds a socket connection to the manager and sets up event listeners\n *\n * @param socket The client socket connection\n */\n addConnection(socket: Socket): void {\n try {\n // Get socket timeout from config\n const { socketTimeout, keepAliveTimeout } = this._configManager.connectionOptions;\n\n // Configure socket timeout\n socket.setTimeout(socketTimeout);\n\n // Enable TCP keepalive\n socket.setKeepAlive(true, keepAliveTimeout);\n\n // Add to active connections\n this._connections.add(socket);\n this._totalConnections++;\n\n // Emit connection added event\n this.emit(ConnectionEvent.CONNECTION_ADDED, socket);\n\n // Set up event listeners\n socket.on('close', () => {\n this._connections.delete(socket);\n this.emit(ConnectionEvent.CONNECTION_CLOSED, socket);\n });\n\n socket.on('error', (err) => {\n this._connectionErrors++;\n this.emit(ConnectionEvent.CONNECTION_ERROR, socket, err);\n });\n\n socket.on('timeout', () => {\n // Send HTTP timeout response before closing\n socket.end('HTTP/1.1 408 Request Timeout\\r\\n\\r\\n');\n socket.destroy();\n });\n } catch (err) {\n this._connectionErrors++;\n this.emit(ConnectionEvent.CONNECTION_ERROR, socket, err);\n }\n }\n\n /**\n * Gets all active socket connections\n *\n * @returns A set of active socket connections\n */\n getConnections(): Set<Socket> {\n return this._connections;\n }\n\n /**\n * Gets the current number of active connections\n *\n * @returns The number of active connections\n */\n getConnectionCount(): number {\n return this._connections.size;\n }\n\n /**\n * Sets the server's listening state\n *\n * @param isListening Whether the server is listening for connections\n */\n setListening(isListening: boolean): void {\n const wasListening = this._isListening;\n this._isListening = isListening;\n\n // Update start time and emit events when state changes\n if (isListening && !wasListening) {\n this._startTime = Date.now();\n this.emit(ConnectionEvent.SERVER_STARTED);\n } else if (!isListening && wasListening) {\n this.emit(ConnectionEvent.SERVER_STOPPED);\n }\n }\n\n /**\n * Checks if the server is currently listening\n *\n * @returns True if the server is listening, false otherwise\n */\n isListening(): boolean {\n return this._isListening;\n }\n\n /**\n * Gets the server instance\n *\n * @returns The server instance or null if not set\n */\n getServer(): Server | null {\n return this._server;\n }\n\n /**\n * Gets connection statistics\n *\n * @returns Connection statistics object\n */\n getStats(): IConnectionStats {\n return {\n activeConnections: this._connections.size,\n totalConnections: this._totalConnections,\n connectionErrors: this._connectionErrors,\n uptime: this._isListening ? Date.now() - this._startTime : 0,\n };\n }\n\n /**\n * Closes all active connections gracefully\n *\n * @returns Promise that resolves when all connections are closed\n */\n async closeAllConnections(): Promise<void> {\n // If there are no connections, resolve immediately\n if (this._connections.size === 0) {\n this.emit(ConnectionEvent.ALL_CONNECTIONS_CLOSED);\n return;\n }\n\n // Create a copy of the connections to avoid modification during iteration\n const connections = [...this._connections];\n\n // Get graceful shutdown timeout from config\n const { gracefulShutdownTimeout } = this._configManager.connectionOptions;\n\n // If grace period is provided, attempt graceful shutdown\n if (gracefulShutdownTimeout > 0) {\n // End each connection with a proper HTTP response\n for (const socket of connections) {\n try {\n socket.end('HTTP/1.1 503 Service Unavailable\\r\\n\\r\\n');\n } catch (_err) {\n // Ignore errors during shutdown\n }\n }\n\n // Wait for the grace period\n await new Promise<void>((resolve) => {\n setTimeout(() => resolve(), gracefulShutdownTimeout);\n });\n }\n\n // Force close any remaining connections\n for (const socket of this._connections) {\n try {\n socket.destroy();\n } catch (_err) {\n // Ignore errors during shutdown\n }\n }\n\n // Clear the connections set\n this._connections.clear();\n\n // Emit the all connections closed event\n this.emit(ConnectionEvent.ALL_CONNECTIONS_CLOSED);\n }\n}\n",
|
|
28
|
-
"import { EventEmitter } from 'events';\nimport type { Context } from 'core/Context.ts';\nimport type { IRoute, TUndefinableResponseFunction } from 'types/Route.ts';\nimport { HookManagerEvent, HookPhase, PathMatchingPattern } from 'constants/hooks.ts';\nimport type { TResponseBody } from 'types/http/Response.ts';\nimport type { IExcludeHook, IIncludeHook, THook } from 'types/Hook.ts';\n\n/**\n * Manages hooks registration and execution\n *\n * This class is responsible for registering hook functions and\n * executing them at the appropriate points in the request lifecycle.\n */\nexport class HooksManager extends EventEmitter {\n private readonly hooks: Array<THook> = [];\n\n // Cache for path matching to improve performance\n private readonly pathMatchCache = new Map<string, Array<THook>>();\n\n /**\n * Add a hook to be executed at various points in the request lifecycle\n *\n * @param fn The hook function to execute\n * @param options Configuration options for the hook\n * @returns The hooks manager instance for chaining\n */\n add(\n fn: TUndefinableResponseFunction,\n options?: {\n paths?: Array<string> | typeof PathMatchingPattern.ALL_BUT_EXCLUDED;\n excluded?: Array<string>;\n },\n ): this {\n let hookConfig: THook = <IIncludeHook>{ paths: [], excluded: [], fn };\n\n if (!options) {\n // Global hook with no path restrictions\n // Use the default initialization\n } else if (options.paths === PathMatchingPattern.ALL_BUT_EXCLUDED && Array.isArray(options.excluded)) {\n // Hook that applies to all paths except those explicitly excluded\n const excludeHook: IExcludeHook = {\n paths: PathMatchingPattern.ALL_BUT_EXCLUDED,\n excluded: options.excluded,\n fn,\n };\n hookConfig = excludeHook;\n } else if (Array.isArray(options.paths)) {\n // Hook that only applies to specific paths\n const includeHook: IIncludeHook = {\n paths: options.paths,\n excluded: options.excluded ?? [],\n fn,\n };\n hookConfig = includeHook;\n }\n // else use the default initialization\n\n this.hooks.push(hookConfig);\n\n // Clear the path match cache when a hook is added\n this.clearPathMatchCache();\n\n // Emit event\n this.emit(HookManagerEvent.HOOK_ADDED, hookConfig);\n\n return this;\n }\n\n /**\n * Clear the path match cache\n * This should be called whenever hooks are added or removed\n */\n private clearPathMatchCache(): void {\n this.pathMatchCache.clear();\n }\n\n /**\n * Get hooks that apply to a specific path\n * Uses caching for better performance\n *\n * @param path The route path to match against\n * @returns Array of hooks that apply to the path\n */\n private getHooksForPath(path: string): Array<THook> {\n // Check cache first\n if (this.pathMatchCache.has(path)) {\n return this.pathMatchCache.get(path) ?? [];\n }\n\n // Find all hooks that apply to this path\n const matchingHooks = this.hooks.filter((hook) => {\n // Case 1: \"All but excluded\" hook\n if (hook.paths === PathMatchingPattern.ALL_BUT_EXCLUDED) {\n return !this.isPathExcluded(path, hook.excluded);\n }\n\n // Case 2: Path-specific hook with paths array\n if (Array.isArray(hook.paths)) {\n // Check if the path is included in the paths array and not excluded\n return this.isPathIncluded(path, hook.paths) && !this.isPathExcluded(path, hook.excluded);\n }\n\n // Case 3: Global hook (empty paths array)\n // This should never happen with the current type definitions, but included for safety\n return false;\n });\n\n // Cache the result\n this.pathMatchCache.set(path, matchingHooks);\n\n return matchingHooks;\n }\n\n /**\n * Check if a path is included in a list of path patterns\n * Supports exact matches and pattern matching with wildcards\n *\n * @param path The path to check\n * @param patterns Array of path patterns to match against\n * @returns True if the path matches any pattern\n */\n private isPathIncluded(path: string, patterns: Array<string>): boolean {\n if (patterns.length === 0) return true;\n\n return patterns.some((pattern) => {\n // Exact match\n if (pattern === path) return true;\n\n // Wildcard match (e.g., /api/* matches /api/users)\n if (pattern.endsWith('*')) {\n const prefix = pattern.slice(0, -1);\n return path.startsWith(prefix);\n }\n\n return false;\n });\n }\n\n /**\n * Check if a path is excluded by a list of path patterns\n *\n * @param path The path to check\n * @param patterns Array of path patterns to match against\n * @returns True if the path matches any exclusion pattern\n */\n private isPathExcluded(path: string, patterns: Array<string>): boolean {\n return this.isPathIncluded(path, patterns);\n }\n\n /**\n * Process beforeAll hooks for a route\n *\n * @param route The route to process hooks for\n * @param ctx The request context\n * @returns A response body if a hook short-circuits, undefined otherwise\n */\n async processBeforeAll(route: IRoute, ctx: Context): Promise<TResponseBody<unknown> | void> {\n if (!this.hooks.length) return;\n\n const matchingHooks = this.getHooksForPath(route.path);\n\n for (const hook of matchingHooks) {\n try {\n const result = await Promise.resolve(hook.fn(ctx));\n\n // Emit event for hook execution\n this.emit(HookManagerEvent.HOOK_EXECUTED, {\n phase: HookPhase.BEFORE_ALL,\n path: route.path,\n result: result ? 'short-circuit' : 'continue',\n });\n\n // Emit specific phase event\n this.emit(HookManagerEvent.BEFORE_ALL_EXECUTED, ctx, hook);\n\n // If hook returns a value, short-circuit the request\n if (result) {\n return result;\n }\n } catch (error) {\n // Log the error but continue processing\n console.error(`Hook error for path ${route.path}:`, error);\n // Re-throw to allow error handling hooks to catch it\n throw error;\n }\n }\n\n return undefined;\n }\n\n /**\n * Process beforeGroup hooks for a route\n *\n * @param route The route to process hooks for\n * @param ctx The request context\n * @returns A response body if a hook short-circuits, undefined otherwise\n */\n async processBeforeGroup(route: IRoute, ctx: Context): Promise<TResponseBody<unknown> | void> {\n if (!route.beforeGroup) return;\n\n try {\n const result = await Promise.resolve(route.beforeGroup(ctx));\n\n this.emit(HookManagerEvent.HOOK_EXECUTED, {\n phase: HookPhase.BEFORE_GROUP,\n path: route.path,\n result: result ? 'short-circuit' : 'continue',\n });\n\n // Emit specific phase event\n this.emit(HookManagerEvent.BEFORE_GROUP_EXECUTED, ctx, route.beforeGroup);\n\n return result;\n } catch (error) {\n console.error(`BeforeGroup hook error for path ${route.path}:`, error);\n throw error;\n }\n }\n\n /**\n * Process beforeHandler hooks for a route\n *\n * @param route The route to process hooks for\n * @param ctx The request context\n * @returns A response body if a hook short-circuits, undefined otherwise\n */\n async processBeforeHandler(route: IRoute, ctx: Context): Promise<TResponseBody<unknown> | void> {\n if (!route.beforeHandler) return;\n\n try {\n const result = await Promise.resolve(route.beforeHandler(ctx));\n\n this.emit(HookManagerEvent.HOOK_EXECUTED, {\n phase: HookPhase.BEFORE_HANDLER,\n path: route.path,\n result: result ? 'short-circuit' : 'continue',\n });\n\n // Emit specific phase event\n this.emit(HookManagerEvent.BEFORE_HANDLER_EXECUTED, ctx, route.beforeHandler);\n\n return result;\n } catch (error) {\n console.error(`BeforeHandler hook error for path ${route.path}:`, error);\n throw error;\n }\n }\n\n /**\n * Process afterHandler hooks for a route\n *\n * @param route The route to process hooks for\n * @param ctx The request context\n * @returns A response body if a hook short-circuits, undefined otherwise\n */\n async processAfterHandler(route: IRoute, ctx: Context): Promise<TResponseBody<unknown> | void> {\n if (!route.afterHandler) return;\n\n try {\n const result = await Promise.resolve(route.afterHandler(ctx));\n\n this.emit(HookManagerEvent.HOOK_EXECUTED, {\n phase: HookPhase.AFTER_HANDLER,\n path: route.path,\n result: result ? 'modified' : 'unmodified',\n });\n\n // Emit specific phase event\n this.emit(HookManagerEvent.AFTER_HANDLER_EXECUTED, ctx, route.afterHandler);\n\n return result;\n } catch (error) {\n console.error(`AfterHandler hook error for path ${route.path}:`, error);\n throw error;\n }\n }\n\n /**\n * Remove all hooks\n *\n * @returns The hooks manager instance for chaining\n */\n clear(): this {\n while (this.hooks.length > 0) {\n this.hooks.pop();\n }\n this.clearPathMatchCache();\n return this;\n }\n\n /**\n * Get the number of registered hook functions\n */\n get hooksCount(): number {\n return this.hooks.length;\n }\n}\n"
|
|
29
|
-
],
|
|
30
|
-
"mappings": "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",
|
|
31
|
-
"debugId": "44C4E8D87004813F64756E2164756E21",
|
|
32
|
-
"names": []
|
|
33
|
-
}
|