insite-common 2.4.0 → 2.6.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 CHANGED
@@ -1,5 +1,7 @@
1
1
  # insite-common
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/insite-common)](https://www.npmjs.com/package/insite-common)
4
+
3
5
  Shared types and backend utilities for the inSite ecosystem. Defines ability schema for RBAC and configuration, plus server helpers for HTTP(S), SSL, and client IP resolution.
4
6
 
5
7
  Part of [inSite](../../README.md) — used by all inSite packages.
@@ -73,7 +75,7 @@ const abilities: AbilitiesSchema = [
73
75
 
74
76
  ### getRemoteAddress
75
77
 
76
- Checks: `Forwarded`, `X-Forwarded-For`, `X-Real-IP`, `CF-Connecting-IP`, `True-Client-IP`. Falls back to `socket.remoteAddress`.
78
+ Checks forwarding headers before `socket.remoteAddress`. A later request with the same `Host` and no forwarding header does not throw. An IPv4 value, including an IPv4 embedded in `::ffff:x.x.x.x`, is returned as four octets. A pure IPv6 address is returned as IPv6 without a zone id, not as `127.0.0.1`.
77
79
 
78
80
  ## Related
79
81
 
@@ -1,2 +1,2 @@
1
- import c from"node:http";import f from"node:https";function h(e,r){let t="key"in e&&"cert"in e?f.createServer(e):c.createServer(e);return r?new Promise(i=>{t.on("listening",()=>i(t)),t.listen(r)}):t}var d=["forwarded","x-forwarded","forwarded-for","x-forwarded-for","x-real-ip","cf-connecting-ip","do-connecting-ip","x-appengine-user-ip","true-client-ip","fastly-client-ip","client-ip","x-client-ip","x-proxyuser-ip","x-cluster-client-ip"],s,o,n=/^.*?((?:\d{1,3}\.){3}\d{1,3}).*$/;function u(e){if(o===void 0||s!==e.headers.host){o=void 0,{host:s}=e.headers;for(let r of d){let t=e.headers[r];typeof t=="string"&&n.test(t)&&(o=r)}o??=e.socket.remoteAddress&&n.test(e.socket.remoteAddress)?!1:null}switch(o){case!1:return e.socket.remoteAddress.replace(n,"$1");case null:return"127.0.0.1";default:return e.headers[o].replace(n,"$1")}}import{readFileSync as p}from"node:fs";function g(e={cert:process.env.INSITE_SSL_CERT,key:process.env.INSITE_SSL_KEY}){if(e.cert&&e.key)try{return typeof e.cert=="string"&&!/^-{3,}BEGIN/.test(e.cert)&&(e.cert=p(e.cert)),typeof e.key=="string"&&!/^-{3,}BEGIN/.test(e.key)&&(e.key=p(e.key)),e}catch(r){console.error("SSL resolve error:",r)}}function x(e){let{address:r,family:t,port:i}=e.server.address();console.info(`${e.icon} ${e.name} is listening on`,`${e.protocol}://${t==="IPv4"?r:r.replace(/^::(?:ffff:)?/,"")||process.env.NODE_ENV==="development"?"localhost":"127.0.0.1"}:${i}`)}export{h as createServer,u as getRemoteAddress,g as resolveSSL,x as showServerListeningMessage};
1
+ import p from"node:http";import s from"node:https";function v(e,r){let t="key"in e&&"cert"in e?s.createServer(e):p.createServer(e);return r?new Promise(o=>{t.on("listening",()=>o(t)),t.listen(r)}):t}var c=["forwarded","x-forwarded","forwarded-for","x-forwarded-for","x-real-ip","cf-connecting-ip","do-connecting-ip","x-appengine-user-ip","true-client-ip","fastly-client-ip","client-ip","x-client-ip","x-proxyuser-ip","x-cluster-client-ip"],f=/^.*?((?:\d{1,3}\.){3}\d{1,3}).*$/,d=/^(?:[\dA-Fa-f]{0,4}:){2,7}[\dA-Fa-f]{0,4}$/;function a(e){return f.exec(e)?.[1]}function m(e){if(!e.includes(":"))return;let r=e.replaceAll("[","").replaceAll("]","");for(let t of r.split(/[^\d%:A-Fa-f]+/)){let[o]=t.split("%",1);if(o&&d.test(o))return o}}function n(e){if(e)return a(e)??m(e)}function h(e){for(let r of c){let t=e.headers[r];if(typeof t=="string"){let o=n(t);if(o)return o}}return n(e.socket?.remoteAddress)??"127.0.0.1"}import{readFileSync as i}from"node:fs";function l(e={cert:process.env.INSITE_SSL_CERT,key:process.env.INSITE_SSL_KEY}){if(e.cert&&e.key)try{return typeof e.cert=="string"&&!/^-{3,}BEGIN/.test(e.cert)&&(e.cert=i(e.cert)),typeof e.key=="string"&&!/^-{3,}BEGIN/.test(e.key)&&(e.key=i(e.key)),e}catch(r){console.error("SSL resolve error:",r)}}function k(e){let{address:r,family:t,port:o}=e.server.address();console.info(`${e.icon} ${e.name} is listening on`,`${e.protocol}://${t==="IPv4"?r:r.replace(/^::(?:ffff:)?/,"")||process.env.NODE_ENV==="development"?"localhost":"127.0.0.1"}:${o}`)}export{v as createServer,h as getRemoteAddress,l as resolveSSL,k as showServerListeningMessage};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/backend/server/createServer.ts", "../../src/backend/server/getRemoteAddress.ts", "../../src/backend/server/resolveSSL.ts", "../../src/backend/server/showServerListeningMessage.ts"],
4
- "sourcesContent": ["import http from \"node:http\";\nimport https from \"node:https\";\n\n\nexport function createServer(options: http.ServerOptions): http.Server;\nexport function createServer(options: https.ServerOptions): https.Server;\nexport function createServer(options: http.ServerOptions, port: number | string): Promise<http.Server>;\nexport function createServer(options: https.ServerOptions, port: number | string): Promise<https.Server>;\nexport function createServer(options: http.ServerOptions | https.ServerOptions, port?: number | string) {\n\t\n\tconst server =\n\t\t(\"key\" in options && \"cert\" in options) ?\n\t\t\thttps.createServer(options) :\n\t\t\thttp.createServer(options);\n\t\n\treturn port ?\n\t\tnew Promise(resolve => {\n\t\t\tserver.on(\"listening\", () => resolve(server));\n\t\t\tserver.listen(port);\n\t\t\t\n\t\t}) :\n\t\tserver;\n}\n", "import type { IncomingMessage } from \"node:http\";\n\n\nconst headersThatMayContainRemoteAddress = [\n\t\"forwarded\",\n\t\"x-forwarded\",\n\t\"forwarded-for\",\n\t\"x-forwarded-for\",\n\t\"x-real-ip\",\n\t\"cf-connecting-ip\",\n\t\"do-connecting-ip\",\n\t\"x-appengine-user-ip\",\n\t\"true-client-ip\",\n\t\"fastly-client-ip\",\n\t\"client-ip\",\n\t\"x-client-ip\",\n\t\"x-proxyuser-ip\",\n\t\"x-cluster-client-ip\"\n] as const;\n\nlet host: string | undefined;\nlet headerWithRemoteAddress: typeof headersThatMayContainRemoteAddress[number] | false | null | undefined;\n\nconst remoteAddressRegExp = /^.*?((?:\\d{1,3}\\.){3}\\d{1,3}).*$/;\n\nexport function getRemoteAddress(request: IncomingMessage) {\n\tif (headerWithRemoteAddress === undefined || host !== request.headers.host) {\n\t\theaderWithRemoteAddress = undefined;\n\t\t({ host } = request.headers);\n\t\t\n\t\tfor (const headerName of headersThatMayContainRemoteAddress) {\n\t\t\tconst header = request.headers[headerName];\n\t\t\tif (typeof header == \"string\" && remoteAddressRegExp.test(header))\n\t\t\t\theaderWithRemoteAddress = headerName;\n\t\t}\n\t\t\n\t\theaderWithRemoteAddress ??=\n\t\t\trequest.socket.remoteAddress && remoteAddressRegExp.test(request.socket.remoteAddress) ?\n\t\t\t\tfalse :\n\t\t\t\tnull;\n\t}\n\t\n\tswitch (headerWithRemoteAddress) {\n\t\tcase false:\n\t\t\treturn request.socket.remoteAddress!.replace(remoteAddressRegExp, \"$1\");\n\t\t\n\t\tcase null:\n\t\t\treturn \"127.0.0.1\";\n\t\t\n\t\tdefault:\n\t\t\treturn (request.headers[headerWithRemoteAddress] as string).replace(remoteAddressRegExp, \"$1\");\n\t}\n}\n", "import { readFileSync } from \"node:fs\";\n\n\nexport function resolveSSL(ssl: {\n\tcert: Buffer<ArrayBufferLike> | string;\n\tkey: Buffer<ArrayBufferLike> | string;\n} = {\n\tcert: process.env.INSITE_SSL_CERT!,\n\tkey: process.env.INSITE_SSL_KEY!\n}) {\n\tif (ssl.cert && ssl.key)\n\t\ttry {\n\t\t\tif (typeof ssl.cert == \"string\" && !/^-{3,}BEGIN/.test(ssl.cert))\n\t\t\t\tssl.cert = readFileSync(ssl.cert);\n\t\t\t\n\t\t\tif (typeof ssl.key == \"string\" && !/^-{3,}BEGIN/.test(ssl.key))\n\t\t\t\tssl.key = readFileSync(ssl.key);\n\t\t\t\n\t\t\treturn ssl;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"SSL resolve error:\", error);\n\t\t}\n\t\n\treturn undefined;// eslint-disable-line unicorn/no-useless-undefined\n}\n\n", "import type http from \"node:http\";\nimport type https from \"node:https\";\nimport type { AddressInfo } from \"node:net\";\n\n\ntype Server = {\n\ticon: string;\n\tname: string;\n\tprotocol: string;\n\tserver: http.Server | https.Server;\n};\n\n\nexport function showServerListeningMessage(server: Server) {\n\t\n\tconst { address, family, port } = server.server.address() as AddressInfo;\n\t\n\tconsole.info(\n\t\t`${server.icon} ${server.name} is listening on`,\n\t\t`${server.protocol}://${\n\t\t\tfamily === \"IPv4\" ?\n\t\t\t\taddress : (\n\t\t\t\t\taddress.replace(/^::(?:ffff:)?/, \"\") ||\n\t\t\t\t\tprocess.env.NODE_ENV === \"development\" ? \"localhost\" : \"127.0.0.1\"\n\t\t\t\t)\n\t\t}:${port}`\n\t);\n\t\n}\n"],
5
- "mappings": "AAAA,OAAOA,MAAU,YACjB,OAAOC,MAAW,aAOX,SAASC,EAAaC,EAAmDC,EAAwB,CAEvG,IAAMC,EACJ,QAASF,GAAW,SAAUA,EAC9BF,EAAM,aAAaE,CAAO,EAC1BH,EAAK,aAAaG,CAAO,EAE3B,OAAOC,EACN,IAAI,QAAQE,GAAW,CACtBD,EAAO,GAAG,YAAa,IAAMC,EAAQD,CAAM,CAAC,EAC5CA,EAAO,OAAOD,CAAI,CAEnB,CAAC,EACDC,CACF,CCnBA,IAAME,EAAqC,CAC1C,YACA,cACA,gBACA,kBACA,YACA,mBACA,mBACA,sBACA,iBACA,mBACA,YACA,cACA,iBACA,qBACD,EAEIC,EACAC,EAEEC,EAAsB,mCAErB,SAASC,EAAiBC,EAA0B,CAC1D,GAAIH,IAA4B,QAAaD,IAASI,EAAQ,QAAQ,KAAM,CAC3EH,EAA0B,OACzB,CAAE,KAAAD,CAAK,EAAII,EAAQ,QAEpB,QAAWC,KAAcN,EAAoC,CAC5D,IAAMO,EAASF,EAAQ,QAAQC,CAAU,EACrC,OAAOC,GAAU,UAAYJ,EAAoB,KAAKI,CAAM,IAC/DL,EAA0BI,EAC5B,CAEAJ,IACCG,EAAQ,OAAO,eAAiBF,EAAoB,KAAKE,EAAQ,OAAO,aAAa,EACpF,GACA,IACH,CAEA,OAAQH,EAAyB,CAChC,IAAK,GACJ,OAAOG,EAAQ,OAAO,cAAe,QAAQF,EAAqB,IAAI,EAEvE,KAAK,KACJ,MAAO,YAER,QACC,OAAQE,EAAQ,QAAQH,CAAuB,EAAa,QAAQC,EAAqB,IAAI,CAC/F,CACD,CCpDA,OAAS,gBAAAK,MAAoB,UAGtB,SAASC,EAAWC,EAGvB,CACH,KAAM,QAAQ,IAAI,gBAClB,IAAK,QAAQ,IAAI,cAClB,EAAG,CACF,GAAIA,EAAI,MAAQA,EAAI,IACnB,GAAI,CACH,OAAI,OAAOA,EAAI,MAAQ,UAAY,CAAC,cAAc,KAAKA,EAAI,IAAI,IAC9DA,EAAI,KAAOF,EAAaE,EAAI,IAAI,GAE7B,OAAOA,EAAI,KAAO,UAAY,CAAC,cAAc,KAAKA,EAAI,GAAG,IAC5DA,EAAI,IAAMF,EAAaE,EAAI,GAAG,GAExBA,CACR,OAASC,EAAO,CACf,QAAQ,MAAM,qBAAsBA,CAAK,CAC1C,CAGF,CCXO,SAASC,EAA2BC,EAAgB,CAE1D,GAAM,CAAE,QAAAC,EAAS,OAAAC,EAAQ,KAAAC,CAAK,EAAIH,EAAO,OAAO,QAAQ,EAExD,QAAQ,KACP,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,mBAC7B,GAAGA,EAAO,QAAQ,MACjBE,IAAW,OACVD,EACCA,EAAQ,QAAQ,gBAAiB,EAAE,GACnC,QAAQ,IAAI,WAAa,cAAgB,YAAc,WAE1D,IAAIE,CAAI,EACT,CAED",
6
- "names": ["http", "https", "createServer", "options", "port", "server", "resolve", "headersThatMayContainRemoteAddress", "host", "headerWithRemoteAddress", "remoteAddressRegExp", "getRemoteAddress", "request", "headerName", "header", "readFileSync", "resolveSSL", "ssl", "error", "showServerListeningMessage", "server", "address", "family", "port"]
4
+ "sourcesContent": ["import http from \"node:http\";\nimport https from \"node:https\";\n\n\nexport function createServer(options: http.ServerOptions): http.Server;\nexport function createServer(options: https.ServerOptions): https.Server;\nexport function createServer(options: http.ServerOptions, port: number | string): Promise<http.Server>;\nexport function createServer(options: https.ServerOptions, port: number | string): Promise<https.Server>;\nexport function createServer(options: http.ServerOptions | https.ServerOptions, port?: number | string) {\n\t\n\tconst server =\n\t\t(\"key\" in options && \"cert\" in options) ?\n\t\t\thttps.createServer(options) :\n\t\t\thttp.createServer(options);\n\t\n\treturn port ?\n\t\tnew Promise(resolve => {\n\t\t\tserver.on(\"listening\", () => resolve(server));\n\t\t\tserver.listen(port);\n\t\t\t\n\t\t}) :\n\t\tserver;\n}\n", "import type { IncomingMessage } from \"node:http\";\n\n\nconst headersThatMayContainRemoteAddress = [\n\t\"forwarded\",\n\t\"x-forwarded\",\n\t\"forwarded-for\",\n\t\"x-forwarded-for\",\n\t\"x-real-ip\",\n\t\"cf-connecting-ip\",\n\t\"do-connecting-ip\",\n\t\"x-appengine-user-ip\",\n\t\"true-client-ip\",\n\t\"fastly-client-ip\",\n\t\"client-ip\",\n\t\"x-client-ip\",\n\t\"x-proxyuser-ip\",\n\t\"x-cluster-client-ip\"\n] as const;\n\nconst remoteAddressRegExp = /^.*?((?:\\d{1,3}\\.){3}\\d{1,3}).*$/;\nconst ipv6AddressRegExp = /^(?:[\\dA-Fa-f]{0,4}:){2,7}[\\dA-Fa-f]{0,4}$/;\n\nfunction ipv4From(value: string) {\n\treturn remoteAddressRegExp.exec(value)?.[1];\n}\n\nfunction ipv6From(value: string) {\n\tif (!value.includes(\":\"))\n\t\treturn;\n\t\n\tconst stripped = value.replaceAll(\"[\", \"\").replaceAll(\"]\", \"\");\n\t\n\tfor (const token of stripped.split(/[^\\d%:A-Fa-f]+/)) {\n\t\tconst [ address ] = token.split(\"%\", 1);\n\t\t\n\t\tif (address && ipv6AddressRegExp.test(address))\n\t\t\treturn address;\n\t}\n\t\n}\n\nfunction addressFrom(value: string | undefined) {\n\tif (!value)\n\t\treturn;\n\t\n\treturn ipv4From(value) ?? ipv6From(value);\n}\n\nexport function getRemoteAddress(request: IncomingMessage) {\n\tfor (const headerName of headersThatMayContainRemoteAddress) {\n\t\tconst header = request.headers[headerName];\n\t\t\n\t\tif (typeof header == \"string\") {\n\t\t\tconst address = addressFrom(header);\n\t\t\t\n\t\t\tif (address)\n\t\t\t\treturn address;\n\t\t}\n\t}\n\t\n\treturn addressFrom(request.socket?.remoteAddress) ?? \"127.0.0.1\";\n}\n", "import { readFileSync } from \"node:fs\";\n\n\nexport function resolveSSL(ssl: {\n\tcert: Buffer<ArrayBufferLike> | string;\n\tkey: Buffer<ArrayBufferLike> | string;\n} = {\n\tcert: process.env.INSITE_SSL_CERT!,\n\tkey: process.env.INSITE_SSL_KEY!\n}) {\n\tif (ssl.cert && ssl.key)\n\t\ttry {\n\t\t\tif (typeof ssl.cert == \"string\" && !/^-{3,}BEGIN/.test(ssl.cert))\n\t\t\t\tssl.cert = readFileSync(ssl.cert);\n\t\t\t\n\t\t\tif (typeof ssl.key == \"string\" && !/^-{3,}BEGIN/.test(ssl.key))\n\t\t\t\tssl.key = readFileSync(ssl.key);\n\t\t\t\n\t\t\treturn ssl;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"SSL resolve error:\", error);\n\t\t}\n\t\n\treturn undefined;// eslint-disable-line unicorn/no-useless-undefined\n}\n\n", "import type http from \"node:http\";\nimport type https from \"node:https\";\nimport type { AddressInfo } from \"node:net\";\n\n\ntype Server = {\n\ticon: string;\n\tname: string;\n\tprotocol: string;\n\tserver: http.Server | https.Server;\n};\n\n\nexport function showServerListeningMessage(server: Server) {\n\t\n\tconst { address, family, port } = server.server.address() as AddressInfo;\n\t\n\tconsole.info(\n\t\t`${server.icon} ${server.name} is listening on`,\n\t\t`${server.protocol}://${\n\t\t\tfamily === \"IPv4\" ?\n\t\t\t\taddress : (\n\t\t\t\t\taddress.replace(/^::(?:ffff:)?/, \"\") ||\n\t\t\t\t\tprocess.env.NODE_ENV === \"development\" ? \"localhost\" : \"127.0.0.1\"\n\t\t\t\t)\n\t\t}:${port}`\n\t);\n\t\n}\n"],
5
+ "mappings": "AAAA,OAAOA,MAAU,YACjB,OAAOC,MAAW,aAOX,SAASC,EAAaC,EAAmDC,EAAwB,CAEvG,IAAMC,EACJ,QAASF,GAAW,SAAUA,EAC9BF,EAAM,aAAaE,CAAO,EAC1BH,EAAK,aAAaG,CAAO,EAE3B,OAAOC,EACN,IAAI,QAAQE,GAAW,CACtBD,EAAO,GAAG,YAAa,IAAMC,EAAQD,CAAM,CAAC,EAC5CA,EAAO,OAAOD,CAAI,CAEnB,CAAC,EACDC,CACF,CCnBA,IAAME,EAAqC,CAC1C,YACA,cACA,gBACA,kBACA,YACA,mBACA,mBACA,sBACA,iBACA,mBACA,YACA,cACA,iBACA,qBACD,EAEMC,EAAsB,mCACtBC,EAAoB,6CAE1B,SAASC,EAASC,EAAe,CAChC,OAAOH,EAAoB,KAAKG,CAAK,IAAI,CAAC,CAC3C,CAEA,SAASC,EAASD,EAAe,CAChC,GAAI,CAACA,EAAM,SAAS,GAAG,EACtB,OAED,IAAME,EAAWF,EAAM,WAAW,IAAK,EAAE,EAAE,WAAW,IAAK,EAAE,EAE7D,QAAWG,KAASD,EAAS,MAAM,gBAAgB,EAAG,CACrD,GAAM,CAAEE,CAAQ,EAAID,EAAM,MAAM,IAAK,CAAC,EAEtC,GAAIC,GAAWN,EAAkB,KAAKM,CAAO,EAC5C,OAAOA,CACT,CAED,CAEA,SAASC,EAAYL,EAA2B,CAC/C,GAAKA,EAGL,OAAOD,EAASC,CAAK,GAAKC,EAASD,CAAK,CACzC,CAEO,SAASM,EAAiBC,EAA0B,CAC1D,QAAWC,KAAcZ,EAAoC,CAC5D,IAAMa,EAASF,EAAQ,QAAQC,CAAU,EAEzC,GAAI,OAAOC,GAAU,SAAU,CAC9B,IAAML,EAAUC,EAAYI,CAAM,EAElC,GAAIL,EACH,OAAOA,CACT,CACD,CAEA,OAAOC,EAAYE,EAAQ,QAAQ,aAAa,GAAK,WACtD,CC9DA,OAAS,gBAAAG,MAAoB,UAGtB,SAASC,EAAWC,EAGvB,CACH,KAAM,QAAQ,IAAI,gBAClB,IAAK,QAAQ,IAAI,cAClB,EAAG,CACF,GAAIA,EAAI,MAAQA,EAAI,IACnB,GAAI,CACH,OAAI,OAAOA,EAAI,MAAQ,UAAY,CAAC,cAAc,KAAKA,EAAI,IAAI,IAC9DA,EAAI,KAAOF,EAAaE,EAAI,IAAI,GAE7B,OAAOA,EAAI,KAAO,UAAY,CAAC,cAAc,KAAKA,EAAI,GAAG,IAC5DA,EAAI,IAAMF,EAAaE,EAAI,GAAG,GAExBA,CACR,OAASC,EAAO,CACf,QAAQ,MAAM,qBAAsBA,CAAK,CAC1C,CAGF,CCXO,SAASC,EAA2BC,EAAgB,CAE1D,GAAM,CAAE,QAAAC,EAAS,OAAAC,EAAQ,KAAAC,CAAK,EAAIH,EAAO,OAAO,QAAQ,EAExD,QAAQ,KACP,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,mBAC7B,GAAGA,EAAO,QAAQ,MACjBE,IAAW,OACVD,EACCA,EAAQ,QAAQ,gBAAiB,EAAE,GACnC,QAAQ,IAAI,WAAa,cAAgB,YAAc,WAE1D,IAAIE,CAAI,EACT,CAED",
6
+ "names": ["http", "https", "createServer", "options", "port", "server", "resolve", "headersThatMayContainRemoteAddress", "remoteAddressRegExp", "ipv6AddressRegExp", "ipv4From", "value", "ipv6From", "stripped", "token", "address", "addressFrom", "getRemoteAddress", "request", "headerName", "header", "readFileSync", "resolveSSL", "ssl", "error", "showServerListeningMessage", "server", "address", "family", "port"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getRemoteAddress.d.ts","sourceRoot":"","sources":["../../../src/backend/server/getRemoteAddress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAyBjD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,UA2BxD"}
1
+ {"version":3,"file":"getRemoteAddress.d.ts","sourceRoot":"","sources":["../../../src/backend/server/getRemoteAddress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAiDjD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,UAaxD"}
@@ -1,2 +1,2 @@
1
- import f from"node:http";import c from"node:https";function h(e,r){let t="key"in e&&"cert"in e?c.createServer(e):f.createServer(e);return r?new Promise(i=>{t.on("listening",()=>i(t)),t.listen(r)}):t}var d=["forwarded","x-forwarded","forwarded-for","x-forwarded-for","x-real-ip","cf-connecting-ip","do-connecting-ip","x-appengine-user-ip","true-client-ip","fastly-client-ip","client-ip","x-client-ip","x-proxyuser-ip","x-cluster-client-ip"],s,o,n=/^.*?((?:\d{1,3}\.){3}\d{1,3}).*$/;function u(e){if(o===void 0||s!==e.headers.host){o=void 0,{host:s}=e.headers;for(let r of d){let t=e.headers[r];typeof t=="string"&&n.test(t)&&(o=r)}o??=e.socket.remoteAddress&&n.test(e.socket.remoteAddress)?!1:null}switch(o){case!1:return e.socket.remoteAddress.replace(n,"$1");case null:return"127.0.0.1";default:return e.headers[o].replace(n,"$1")}}import{readFileSync as p}from"node:fs";function x(e={cert:process.env.INSITE_SSL_CERT,key:process.env.INSITE_SSL_KEY}){if(e.cert&&e.key)try{return typeof e.cert=="string"&&!/^-{3,}BEGIN/.test(e.cert)&&(e.cert=p(e.cert)),typeof e.key=="string"&&!/^-{3,}BEGIN/.test(e.key)&&(e.key=p(e.key)),e}catch(r){console.error("SSL resolve error:",r)}}function y(e){let{address:r,family:t,port:i}=e.server.address();console.info(`${e.icon} ${e.name} is listening on`,`${e.protocol}://${t==="IPv4"?r:r.replace(/^::(?:ffff:)?/,"")||process.env.NODE_ENV==="development"?"localhost":"127.0.0.1"}:${i}`)}export{h as createServer,u as getRemoteAddress,x as resolveSSL,y as showServerListeningMessage};
1
+ import p from"node:http";import s from"node:https";function v(e,r){let t="key"in e&&"cert"in e?s.createServer(e):p.createServer(e);return r?new Promise(o=>{t.on("listening",()=>o(t)),t.listen(r)}):t}var f=["forwarded","x-forwarded","forwarded-for","x-forwarded-for","x-real-ip","cf-connecting-ip","do-connecting-ip","x-appengine-user-ip","true-client-ip","fastly-client-ip","client-ip","x-client-ip","x-proxyuser-ip","x-cluster-client-ip"],c=/^.*?((?:\d{1,3}\.){3}\d{1,3}).*$/,d=/^(?:[\dA-Fa-f]{0,4}:){2,7}[\dA-Fa-f]{0,4}$/;function m(e){return c.exec(e)?.[1]}function a(e){if(!e.includes(":"))return;let r=e.replaceAll("[","").replaceAll("]","");for(let t of r.split(/[^\d%:A-Fa-f]+/)){let[o]=t.split("%",1);if(o&&d.test(o))return o}}function n(e){if(e)return m(e)??a(e)}function g(e){for(let r of f){let t=e.headers[r];if(typeof t=="string"){let o=n(t);if(o)return o}}return n(e.socket?.remoteAddress)??"127.0.0.1"}import{readFileSync as i}from"node:fs";function l(e={cert:process.env.INSITE_SSL_CERT,key:process.env.INSITE_SSL_KEY}){if(e.cert&&e.key)try{return typeof e.cert=="string"&&!/^-{3,}BEGIN/.test(e.cert)&&(e.cert=i(e.cert)),typeof e.key=="string"&&!/^-{3,}BEGIN/.test(e.key)&&(e.key=i(e.key)),e}catch(r){console.error("SSL resolve error:",r)}}function k(e){let{address:r,family:t,port:o}=e.server.address();console.info(`${e.icon} ${e.name} is listening on`,`${e.protocol}://${t==="IPv4"?r:r.replace(/^::(?:ffff:)?/,"")||process.env.NODE_ENV==="development"?"localhost":"127.0.0.1"}:${o}`)}export{v as createServer,g as getRemoteAddress,l as resolveSSL,k as showServerListeningMessage};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/backend/server/createServer.ts", "../../src/backend/server/getRemoteAddress.ts", "../../src/backend/server/resolveSSL.ts", "../../src/backend/server/showServerListeningMessage.ts"],
4
- "sourcesContent": ["import http from \"node:http\";\nimport https from \"node:https\";\n\n\nexport function createServer(options: http.ServerOptions): http.Server;\nexport function createServer(options: https.ServerOptions): https.Server;\nexport function createServer(options: http.ServerOptions, port: number | string): Promise<http.Server>;\nexport function createServer(options: https.ServerOptions, port: number | string): Promise<https.Server>;\nexport function createServer(options: http.ServerOptions | https.ServerOptions, port?: number | string) {\n\t\n\tconst server =\n\t\t(\"key\" in options && \"cert\" in options) ?\n\t\t\thttps.createServer(options) :\n\t\t\thttp.createServer(options);\n\t\n\treturn port ?\n\t\tnew Promise(resolve => {\n\t\t\tserver.on(\"listening\", () => resolve(server));\n\t\t\tserver.listen(port);\n\t\t\t\n\t\t}) :\n\t\tserver;\n}\n", "import type { IncomingMessage } from \"node:http\";\n\n\nconst headersThatMayContainRemoteAddress = [\n\t\"forwarded\",\n\t\"x-forwarded\",\n\t\"forwarded-for\",\n\t\"x-forwarded-for\",\n\t\"x-real-ip\",\n\t\"cf-connecting-ip\",\n\t\"do-connecting-ip\",\n\t\"x-appengine-user-ip\",\n\t\"true-client-ip\",\n\t\"fastly-client-ip\",\n\t\"client-ip\",\n\t\"x-client-ip\",\n\t\"x-proxyuser-ip\",\n\t\"x-cluster-client-ip\"\n] as const;\n\nlet host: string | undefined;\nlet headerWithRemoteAddress: typeof headersThatMayContainRemoteAddress[number] | false | null | undefined;\n\nconst remoteAddressRegExp = /^.*?((?:\\d{1,3}\\.){3}\\d{1,3}).*$/;\n\nexport function getRemoteAddress(request: IncomingMessage) {\n\tif (headerWithRemoteAddress === undefined || host !== request.headers.host) {\n\t\theaderWithRemoteAddress = undefined;\n\t\t({ host } = request.headers);\n\t\t\n\t\tfor (const headerName of headersThatMayContainRemoteAddress) {\n\t\t\tconst header = request.headers[headerName];\n\t\t\tif (typeof header == \"string\" && remoteAddressRegExp.test(header))\n\t\t\t\theaderWithRemoteAddress = headerName;\n\t\t}\n\t\t\n\t\theaderWithRemoteAddress ??=\n\t\t\trequest.socket.remoteAddress && remoteAddressRegExp.test(request.socket.remoteAddress) ?\n\t\t\t\tfalse :\n\t\t\t\tnull;\n\t}\n\t\n\tswitch (headerWithRemoteAddress) {\n\t\tcase false:\n\t\t\treturn request.socket.remoteAddress!.replace(remoteAddressRegExp, \"$1\");\n\t\t\n\t\tcase null:\n\t\t\treturn \"127.0.0.1\";\n\t\t\n\t\tdefault:\n\t\t\treturn (request.headers[headerWithRemoteAddress] as string).replace(remoteAddressRegExp, \"$1\");\n\t}\n}\n", "import { readFileSync } from \"node:fs\";\n\n\nexport function resolveSSL(ssl: {\n\tcert: Buffer<ArrayBufferLike> | string;\n\tkey: Buffer<ArrayBufferLike> | string;\n} = {\n\tcert: process.env.INSITE_SSL_CERT!,\n\tkey: process.env.INSITE_SSL_KEY!\n}) {\n\tif (ssl.cert && ssl.key)\n\t\ttry {\n\t\t\tif (typeof ssl.cert == \"string\" && !/^-{3,}BEGIN/.test(ssl.cert))\n\t\t\t\tssl.cert = readFileSync(ssl.cert);\n\t\t\t\n\t\t\tif (typeof ssl.key == \"string\" && !/^-{3,}BEGIN/.test(ssl.key))\n\t\t\t\tssl.key = readFileSync(ssl.key);\n\t\t\t\n\t\t\treturn ssl;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"SSL resolve error:\", error);\n\t\t}\n\t\n\treturn undefined;// eslint-disable-line unicorn/no-useless-undefined\n}\n\n", "import type http from \"node:http\";\nimport type https from \"node:https\";\nimport type { AddressInfo } from \"node:net\";\n\n\ntype Server = {\n\ticon: string;\n\tname: string;\n\tprotocol: string;\n\tserver: http.Server | https.Server;\n};\n\n\nexport function showServerListeningMessage(server: Server) {\n\t\n\tconst { address, family, port } = server.server.address() as AddressInfo;\n\t\n\tconsole.info(\n\t\t`${server.icon} ${server.name} is listening on`,\n\t\t`${server.protocol}://${\n\t\t\tfamily === \"IPv4\" ?\n\t\t\t\taddress : (\n\t\t\t\t\taddress.replace(/^::(?:ffff:)?/, \"\") ||\n\t\t\t\t\tprocess.env.NODE_ENV === \"development\" ? \"localhost\" : \"127.0.0.1\"\n\t\t\t\t)\n\t\t}:${port}`\n\t);\n\t\n}\n"],
5
- "mappings": "AAAA,OAAOA,MAAU,YACjB,OAAOC,MAAW,aAOX,SAASC,EAAaC,EAAmDC,EAAwB,CAEvG,IAAMC,EACJ,QAASF,GAAW,SAAUA,EAC9BF,EAAM,aAAaE,CAAO,EAC1BH,EAAK,aAAaG,CAAO,EAE3B,OAAOC,EACN,IAAI,QAAQE,GAAW,CACtBD,EAAO,GAAG,YAAa,IAAMC,EAAQD,CAAM,CAAC,EAC5CA,EAAO,OAAOD,CAAI,CAEnB,CAAC,EACDC,CACF,CCnBA,IAAME,EAAqC,CAC1C,YACA,cACA,gBACA,kBACA,YACA,mBACA,mBACA,sBACA,iBACA,mBACA,YACA,cACA,iBACA,qBACD,EAEIC,EACAC,EAEEC,EAAsB,mCAErB,SAASC,EAAiBC,EAA0B,CAC1D,GAAIH,IAA4B,QAAaD,IAASI,EAAQ,QAAQ,KAAM,CAC3EH,EAA0B,OACzB,CAAE,KAAAD,CAAK,EAAII,EAAQ,QAEpB,QAAWC,KAAcN,EAAoC,CAC5D,IAAMO,EAASF,EAAQ,QAAQC,CAAU,EACrC,OAAOC,GAAU,UAAYJ,EAAoB,KAAKI,CAAM,IAC/DL,EAA0BI,EAC5B,CAEAJ,IACCG,EAAQ,OAAO,eAAiBF,EAAoB,KAAKE,EAAQ,OAAO,aAAa,EACpF,GACA,IACH,CAEA,OAAQH,EAAyB,CAChC,IAAK,GACJ,OAAOG,EAAQ,OAAO,cAAe,QAAQF,EAAqB,IAAI,EAEvE,KAAK,KACJ,MAAO,YAER,QACC,OAAQE,EAAQ,QAAQH,CAAuB,EAAa,QAAQC,EAAqB,IAAI,CAC/F,CACD,CCpDA,OAAS,gBAAAK,MAAoB,UAGtB,SAASC,EAAWC,EAGvB,CACH,KAAM,QAAQ,IAAI,gBAClB,IAAK,QAAQ,IAAI,cAClB,EAAG,CACF,GAAIA,EAAI,MAAQA,EAAI,IACnB,GAAI,CACH,OAAI,OAAOA,EAAI,MAAQ,UAAY,CAAC,cAAc,KAAKA,EAAI,IAAI,IAC9DA,EAAI,KAAOF,EAAaE,EAAI,IAAI,GAE7B,OAAOA,EAAI,KAAO,UAAY,CAAC,cAAc,KAAKA,EAAI,GAAG,IAC5DA,EAAI,IAAMF,EAAaE,EAAI,GAAG,GAExBA,CACR,OAASC,EAAO,CACf,QAAQ,MAAM,qBAAsBA,CAAK,CAC1C,CAGF,CCXO,SAASC,EAA2BC,EAAgB,CAE1D,GAAM,CAAE,QAAAC,EAAS,OAAAC,EAAQ,KAAAC,CAAK,EAAIH,EAAO,OAAO,QAAQ,EAExD,QAAQ,KACP,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,mBAC7B,GAAGA,EAAO,QAAQ,MACjBE,IAAW,OACVD,EACCA,EAAQ,QAAQ,gBAAiB,EAAE,GACnC,QAAQ,IAAI,WAAa,cAAgB,YAAc,WAE1D,IAAIE,CAAI,EACT,CAED",
6
- "names": ["http", "https", "createServer", "options", "port", "server", "resolve", "headersThatMayContainRemoteAddress", "host", "headerWithRemoteAddress", "remoteAddressRegExp", "getRemoteAddress", "request", "headerName", "header", "readFileSync", "resolveSSL", "ssl", "error", "showServerListeningMessage", "server", "address", "family", "port"]
4
+ "sourcesContent": ["import http from \"node:http\";\nimport https from \"node:https\";\n\n\nexport function createServer(options: http.ServerOptions): http.Server;\nexport function createServer(options: https.ServerOptions): https.Server;\nexport function createServer(options: http.ServerOptions, port: number | string): Promise<http.Server>;\nexport function createServer(options: https.ServerOptions, port: number | string): Promise<https.Server>;\nexport function createServer(options: http.ServerOptions | https.ServerOptions, port?: number | string) {\n\t\n\tconst server =\n\t\t(\"key\" in options && \"cert\" in options) ?\n\t\t\thttps.createServer(options) :\n\t\t\thttp.createServer(options);\n\t\n\treturn port ?\n\t\tnew Promise(resolve => {\n\t\t\tserver.on(\"listening\", () => resolve(server));\n\t\t\tserver.listen(port);\n\t\t\t\n\t\t}) :\n\t\tserver;\n}\n", "import type { IncomingMessage } from \"node:http\";\n\n\nconst headersThatMayContainRemoteAddress = [\n\t\"forwarded\",\n\t\"x-forwarded\",\n\t\"forwarded-for\",\n\t\"x-forwarded-for\",\n\t\"x-real-ip\",\n\t\"cf-connecting-ip\",\n\t\"do-connecting-ip\",\n\t\"x-appengine-user-ip\",\n\t\"true-client-ip\",\n\t\"fastly-client-ip\",\n\t\"client-ip\",\n\t\"x-client-ip\",\n\t\"x-proxyuser-ip\",\n\t\"x-cluster-client-ip\"\n] as const;\n\nconst remoteAddressRegExp = /^.*?((?:\\d{1,3}\\.){3}\\d{1,3}).*$/;\nconst ipv6AddressRegExp = /^(?:[\\dA-Fa-f]{0,4}:){2,7}[\\dA-Fa-f]{0,4}$/;\n\nfunction ipv4From(value: string) {\n\treturn remoteAddressRegExp.exec(value)?.[1];\n}\n\nfunction ipv6From(value: string) {\n\tif (!value.includes(\":\"))\n\t\treturn;\n\t\n\tconst stripped = value.replaceAll(\"[\", \"\").replaceAll(\"]\", \"\");\n\t\n\tfor (const token of stripped.split(/[^\\d%:A-Fa-f]+/)) {\n\t\tconst [ address ] = token.split(\"%\", 1);\n\t\t\n\t\tif (address && ipv6AddressRegExp.test(address))\n\t\t\treturn address;\n\t}\n\t\n}\n\nfunction addressFrom(value: string | undefined) {\n\tif (!value)\n\t\treturn;\n\t\n\treturn ipv4From(value) ?? ipv6From(value);\n}\n\nexport function getRemoteAddress(request: IncomingMessage) {\n\tfor (const headerName of headersThatMayContainRemoteAddress) {\n\t\tconst header = request.headers[headerName];\n\t\t\n\t\tif (typeof header == \"string\") {\n\t\t\tconst address = addressFrom(header);\n\t\t\t\n\t\t\tif (address)\n\t\t\t\treturn address;\n\t\t}\n\t}\n\t\n\treturn addressFrom(request.socket?.remoteAddress) ?? \"127.0.0.1\";\n}\n", "import { readFileSync } from \"node:fs\";\n\n\nexport function resolveSSL(ssl: {\n\tcert: Buffer<ArrayBufferLike> | string;\n\tkey: Buffer<ArrayBufferLike> | string;\n} = {\n\tcert: process.env.INSITE_SSL_CERT!,\n\tkey: process.env.INSITE_SSL_KEY!\n}) {\n\tif (ssl.cert && ssl.key)\n\t\ttry {\n\t\t\tif (typeof ssl.cert == \"string\" && !/^-{3,}BEGIN/.test(ssl.cert))\n\t\t\t\tssl.cert = readFileSync(ssl.cert);\n\t\t\t\n\t\t\tif (typeof ssl.key == \"string\" && !/^-{3,}BEGIN/.test(ssl.key))\n\t\t\t\tssl.key = readFileSync(ssl.key);\n\t\t\t\n\t\t\treturn ssl;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"SSL resolve error:\", error);\n\t\t}\n\t\n\treturn undefined;// eslint-disable-line unicorn/no-useless-undefined\n}\n\n", "import type http from \"node:http\";\nimport type https from \"node:https\";\nimport type { AddressInfo } from \"node:net\";\n\n\ntype Server = {\n\ticon: string;\n\tname: string;\n\tprotocol: string;\n\tserver: http.Server | https.Server;\n};\n\n\nexport function showServerListeningMessage(server: Server) {\n\t\n\tconst { address, family, port } = server.server.address() as AddressInfo;\n\t\n\tconsole.info(\n\t\t`${server.icon} ${server.name} is listening on`,\n\t\t`${server.protocol}://${\n\t\t\tfamily === \"IPv4\" ?\n\t\t\t\taddress : (\n\t\t\t\t\taddress.replace(/^::(?:ffff:)?/, \"\") ||\n\t\t\t\t\tprocess.env.NODE_ENV === \"development\" ? \"localhost\" : \"127.0.0.1\"\n\t\t\t\t)\n\t\t}:${port}`\n\t);\n\t\n}\n"],
5
+ "mappings": "AAAA,OAAOA,MAAU,YACjB,OAAOC,MAAW,aAOX,SAASC,EAAaC,EAAmDC,EAAwB,CAEvG,IAAMC,EACJ,QAASF,GAAW,SAAUA,EAC9BF,EAAM,aAAaE,CAAO,EAC1BH,EAAK,aAAaG,CAAO,EAE3B,OAAOC,EACN,IAAI,QAAQE,GAAW,CACtBD,EAAO,GAAG,YAAa,IAAMC,EAAQD,CAAM,CAAC,EAC5CA,EAAO,OAAOD,CAAI,CAEnB,CAAC,EACDC,CACF,CCnBA,IAAME,EAAqC,CAC1C,YACA,cACA,gBACA,kBACA,YACA,mBACA,mBACA,sBACA,iBACA,mBACA,YACA,cACA,iBACA,qBACD,EAEMC,EAAsB,mCACtBC,EAAoB,6CAE1B,SAASC,EAASC,EAAe,CAChC,OAAOH,EAAoB,KAAKG,CAAK,IAAI,CAAC,CAC3C,CAEA,SAASC,EAASD,EAAe,CAChC,GAAI,CAACA,EAAM,SAAS,GAAG,EACtB,OAED,IAAME,EAAWF,EAAM,WAAW,IAAK,EAAE,EAAE,WAAW,IAAK,EAAE,EAE7D,QAAWG,KAASD,EAAS,MAAM,gBAAgB,EAAG,CACrD,GAAM,CAAEE,CAAQ,EAAID,EAAM,MAAM,IAAK,CAAC,EAEtC,GAAIC,GAAWN,EAAkB,KAAKM,CAAO,EAC5C,OAAOA,CACT,CAED,CAEA,SAASC,EAAYL,EAA2B,CAC/C,GAAKA,EAGL,OAAOD,EAASC,CAAK,GAAKC,EAASD,CAAK,CACzC,CAEO,SAASM,EAAiBC,EAA0B,CAC1D,QAAWC,KAAcZ,EAAoC,CAC5D,IAAMa,EAASF,EAAQ,QAAQC,CAAU,EAEzC,GAAI,OAAOC,GAAU,SAAU,CAC9B,IAAML,EAAUC,EAAYI,CAAM,EAElC,GAAIL,EACH,OAAOA,CACT,CACD,CAEA,OAAOC,EAAYE,EAAQ,QAAQ,aAAa,GAAK,WACtD,CC9DA,OAAS,gBAAAG,MAAoB,UAGtB,SAASC,EAAWC,EAGvB,CACH,KAAM,QAAQ,IAAI,gBAClB,IAAK,QAAQ,IAAI,cAClB,EAAG,CACF,GAAIA,EAAI,MAAQA,EAAI,IACnB,GAAI,CACH,OAAI,OAAOA,EAAI,MAAQ,UAAY,CAAC,cAAc,KAAKA,EAAI,IAAI,IAC9DA,EAAI,KAAOF,EAAaE,EAAI,IAAI,GAE7B,OAAOA,EAAI,KAAO,UAAY,CAAC,cAAc,KAAKA,EAAI,GAAG,IAC5DA,EAAI,IAAMF,EAAaE,EAAI,GAAG,GAExBA,CACR,OAASC,EAAO,CACf,QAAQ,MAAM,qBAAsBA,CAAK,CAC1C,CAGF,CCXO,SAASC,EAA2BC,EAAgB,CAE1D,GAAM,CAAE,QAAAC,EAAS,OAAAC,EAAQ,KAAAC,CAAK,EAAIH,EAAO,OAAO,QAAQ,EAExD,QAAQ,KACP,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,mBAC7B,GAAGA,EAAO,QAAQ,MACjBE,IAAW,OACVD,EACCA,EAAQ,QAAQ,gBAAiB,EAAE,GACnC,QAAQ,IAAI,WAAa,cAAgB,YAAc,WAE1D,IAAIE,CAAI,EACT,CAED",
6
+ "names": ["http", "https", "createServer", "options", "port", "server", "resolve", "headersThatMayContainRemoteAddress", "remoteAddressRegExp", "ipv6AddressRegExp", "ipv4From", "value", "ipv6From", "stripped", "token", "address", "addressFrom", "getRemoteAddress", "request", "headerName", "header", "readFileSync", "resolveSSL", "ssl", "error", "showServerListeningMessage", "server", "address", "family", "port"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insite-common",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Shared types, utilities, and schemas for inSite stack",
5
5
  "keywords": [
6
6
  "insite",
@@ -43,8 +43,8 @@
43
43
  "test": "echo \"Error: no test specified\" && exit 1",
44
44
  "typecheck": "tsc --noEmit"
45
45
  },
46
- "packageManager": "bun@1.3.9",
47
46
  "engines": {
48
- "node": ">=20.0.0"
47
+ "bun": ">=1.4.4",
48
+ "node": ">=22.0.0"
49
49
  }
50
50
  }