@makerx/graphql-core 3.0.0-beta.0 → 3.0.0-beta.2
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/package.json +2 -4
- package/request-info.d.ts +16 -0
- package/request-info.js +16 -0
- package/request-info.js.map +1 -1
- package/request-info.mjs +16 -0
- package/request-info.mjs.map +1 -1
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"**"
|
|
5
5
|
],
|
|
6
6
|
"name": "@makerx/graphql-core",
|
|
7
|
-
"version": "3.0.0-beta.
|
|
7
|
+
"version": "3.0.0-beta.2",
|
|
8
8
|
"private": false,
|
|
9
9
|
"description": "A set of core GraphQL utilities that MakerX uses to build GraphQL APIs",
|
|
10
10
|
"author": "MakerX",
|
|
@@ -20,10 +20,8 @@
|
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "git+https://github.com/MakerXStudio/graphql-core.git"
|
|
22
22
|
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"@makerx/node-common": "^1.5.0"
|
|
25
|
-
},
|
|
26
23
|
"peerDependencies": {
|
|
24
|
+
"@makerx/node-common": ">=1",
|
|
27
25
|
"es-toolkit": ">=1",
|
|
28
26
|
"express": "*",
|
|
29
27
|
"graphql": "*",
|
package/request-info.d.ts
CHANGED
|
@@ -16,7 +16,23 @@ export interface BaseRequestInfo extends Record<string, unknown> {
|
|
|
16
16
|
clientIp?: string;
|
|
17
17
|
userAgent?: string;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds the base URL (`protocol://host[:port]`) for an Express HTTP request, using the request's
|
|
21
|
+
* protocol and resolving the host/port from forwarding headers with the Express hostname as fallback.
|
|
22
|
+
* The port is omitted when it matches the default for the protocol (80 for http, 443 for https).
|
|
23
|
+
* @param req The Express request.
|
|
24
|
+
* @returns The base URL string.
|
|
25
|
+
*/
|
|
19
26
|
export declare const requestBaseUrl: (req: Request) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Builds the base URL (`http(s)://host[:port]`) for a raw WebSocket upgrade (connect) request.
|
|
29
|
+
* Returns an `https` URL when the connection is TLS-encrypted or `x-forwarded-proto` indicates a
|
|
30
|
+
* secure scheme, otherwise `http`. Throws if no host can be determined from the request headers,
|
|
31
|
+
* since upgrade requests have no Express `hostname` fallback.
|
|
32
|
+
* @param req The incoming upgrade request.
|
|
33
|
+
* @returns The base URL string.
|
|
34
|
+
* @throws Error when the host cannot be resolved from the request.
|
|
35
|
+
*/
|
|
20
36
|
export declare const connectRequestBaseUrl: (req: IncomingMessage) => string;
|
|
21
37
|
export declare const buildBaseRequestInfo: (req: Request) => BaseRequestInfo;
|
|
22
38
|
export declare const buildConnectRequestInfo: (req: IncomingMessage) => BaseRequestInfo;
|
package/request-info.js
CHANGED
|
@@ -30,10 +30,26 @@ const resolveHostAndPort = (req, fallbackHostname) => {
|
|
|
30
30
|
}
|
|
31
31
|
return { host: fallbackHostname ?? '', port: undefined };
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Builds the base URL (`protocol://host[:port]`) for an Express HTTP request, using the request's
|
|
35
|
+
* protocol and resolving the host/port from forwarding headers with the Express hostname as fallback.
|
|
36
|
+
* The port is omitted when it matches the default for the protocol (80 for http, 443 for https).
|
|
37
|
+
* @param req The Express request.
|
|
38
|
+
* @returns The base URL string.
|
|
39
|
+
*/
|
|
33
40
|
const requestBaseUrl = (req) => {
|
|
34
41
|
const { host, port } = resolveHostAndPort(req, req.hostname);
|
|
35
42
|
return formatBaseUrl(req.protocol, host, port);
|
|
36
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Builds the base URL (`http(s)://host[:port]`) for a raw WebSocket upgrade (connect) request.
|
|
46
|
+
* Returns an `https` URL when the connection is TLS-encrypted or `x-forwarded-proto` indicates a
|
|
47
|
+
* secure scheme, otherwise `http`. Throws if no host can be determined from the request headers,
|
|
48
|
+
* since upgrade requests have no Express `hostname` fallback.
|
|
49
|
+
* @param req The incoming upgrade request.
|
|
50
|
+
* @returns The base URL string.
|
|
51
|
+
* @throws Error when the host cannot be resolved from the request.
|
|
52
|
+
*/
|
|
37
53
|
const connectRequestBaseUrl = (req) => {
|
|
38
54
|
const { host, port } = resolveHostAndPort(req);
|
|
39
55
|
if (!host)
|
package/request-info.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-info.js","sources":["../src/request-info.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport type { Request } from 'express'\nimport type { IncomingMessage } from 'http'\nimport type { TLSSocket } from 'tls'\n\nexport interface BaseRequestInfo extends Record<string, unknown> {\n requestId: string\n source: 'http' | 'subscription'\n protocol: 'http' | 'https' | 'ws' | 'wss'\n host: string\n port?: number\n method: string\n baseUrl: string\n url: string\n origin: string\n referer?: string\n correlationId?: string\n arrLogId?: string\n clientIp?: string\n userAgent?: string\n}\n\nconst isDefaultPort = (protocol: string, port: number | undefined): boolean =>\n port == null || (protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)\n\nconst formatBaseUrl = (protocol: string, hostname: string, port: number | undefined): string =>\n isDefaultPort(protocol, port) ? `${protocol}://${hostname}` : `${protocol}://${hostname}:${port}`\n\nconst firstHeaderValue = (value: string | string[] | undefined): string | undefined => {\n const raw = Array.isArray(value) ? value[0] : value\n return raw?.split(',')[0]?.trim() || undefined\n}\n\nconst parseHostHeader = (hostHeader: string): { hostname: string; port: number | undefined } => {\n const url = new URL(`http://${hostHeader}`)\n return { hostname: url.hostname, port: url.port ? Number(url.port) : undefined }\n}\n\nconst isEncryptedSocket = (req: IncomingMessage): boolean => 'encrypted' in req.socket && (req.socket as TLSSocket).encrypted === true\n\nconst isEncryptedConnect = (req: IncomingMessage): boolean => {\n const forwarded = firstHeaderValue(req.headers['x-forwarded-proto'])?.toLowerCase()\n if (forwarded === 'https' || forwarded === 'wss') return true\n if (forwarded === 'http' || forwarded === 'ws') return false\n return isEncryptedSocket(req)\n}\n\nconst resolveForwardedHost = (req: IncomingMessage): string | undefined => firstHeaderValue(req.headers['x-forwarded-host'])\n\nconst resolveHostAndPort = (req: IncomingMessage, fallbackHostname?: string): { host: string; port: number | undefined } => {\n const headerValue = resolveForwardedHost(req) ?? req.headers.host\n if (headerValue) {\n const { hostname, port } = parseHostHeader(headerValue)\n return { host: hostname, port }\n }\n return { host: fallbackHostname ?? '', port: undefined }\n}\n\nexport const requestBaseUrl = (req: Request): string => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return formatBaseUrl(req.protocol, host, port)\n}\n\nexport const connectRequestBaseUrl = (req: IncomingMessage): string => {\n const { host, port } = resolveHostAndPort(req)\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return formatBaseUrl(isEncryptedConnect(req) ? 'https' : 'http', host, port)\n}\n\nconst buildSharedRequestInfo = (req: IncomingMessage) => ({\n requestId: req.headers['x-request-id']?.toString() ?? randomUUID(),\n method: req.method ?? '',\n origin: req.headers.origin ?? '',\n referer: req.headers.referer?.toString() ?? '',\n arrLogId: req.headers['x-arr-log-id']?.toString() ?? undefined,\n clientIp: firstHeaderValue(req.headers['x-forwarded-for']) ?? req.socket.remoteAddress,\n correlationId: req.headers['x-correlation-id']?.toString() ?? undefined,\n userAgent: req.headers['user-agent']?.toString() ?? undefined,\n})\n\nexport const buildBaseRequestInfo = (req: Request): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return {\n ...buildSharedRequestInfo(req),\n source: 'http',\n protocol: req.protocol as 'http' | 'https',\n host,\n port,\n baseUrl: formatBaseUrl(req.protocol, host, port),\n url: req.originalUrl,\n }\n}\n\nexport const buildConnectRequestInfo = (req: IncomingMessage): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req)\n const protocol = isEncryptedConnect(req) ? 'wss' : 'ws'\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return {\n ...buildSharedRequestInfo(req),\n source: 'subscription',\n protocol,\n host,\n port,\n baseUrl: formatBaseUrl(protocol === 'wss' ? 'https' : 'http', host, port),\n url: req.url ?? '',\n }\n}\n"],"names":["randomUUID"],"mappings":";;;;AAsBA,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,IAAwB,KAC/D,IAAI,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC,KAAK,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,GAAG,CAAC;AAEhG,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAE,IAAwB,KACjF,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,QAAQ,EAAE,GAAG,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,QAAQ,CAAA,CAAA,EAAI,IAAI,EAAE;AAEnG,MAAM,gBAAgB,GAAG,CAAC,KAAoC,KAAwB;AACpF,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AACnD,IAAA,OAAO,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS;AAChD,CAAC;AAED,MAAM,eAAe,GAAG,CAAC,UAAkB,KAAoD;IAC7F,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAA,OAAA,EAAU,UAAU,CAAA,CAAE,CAAC;IAC3C,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,EAAE;AAClF,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,GAAoB,KAAc,WAAW,IAAI,GAAG,CAAC,MAAM,IAAK,GAAG,CAAC,MAAoB,CAAC,SAAS,KAAK,IAAI;AAEtI,MAAM,kBAAkB,GAAG,CAAC,GAAoB,KAAa;AAC3D,IAAA,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,WAAW,EAAE;AACnF,IAAA,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,KAAK;AAAE,QAAA,OAAO,IAAI;AAC7D,IAAA,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,IAAI;AAAE,QAAA,OAAO,KAAK;AAC5D,IAAA,OAAO,iBAAiB,CAAC,GAAG,CAAC;AAC/B,CAAC;AAED,MAAM,oBAAoB,GAAG,CAAC,GAAoB,KAAyB,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE5H,MAAM,kBAAkB,GAAG,CAAC,GAAoB,EAAE,gBAAyB,KAAgD;AACzH,IAAA,MAAM,WAAW,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI;IACjE,IAAI,WAAW,EAAE;QACf,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,WAAW,CAAC;AACvD,QAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjC;IACA,OAAO,EAAE,IAAI,EAAE,gBAAgB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;AAC1D,CAAC;
|
|
1
|
+
{"version":3,"file":"request-info.js","sources":["../src/request-info.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport type { Request } from 'express'\nimport type { IncomingMessage } from 'http'\nimport type { TLSSocket } from 'tls'\n\nexport interface BaseRequestInfo extends Record<string, unknown> {\n requestId: string\n source: 'http' | 'subscription'\n protocol: 'http' | 'https' | 'ws' | 'wss'\n host: string\n port?: number\n method: string\n baseUrl: string\n url: string\n origin: string\n referer?: string\n correlationId?: string\n arrLogId?: string\n clientIp?: string\n userAgent?: string\n}\n\nconst isDefaultPort = (protocol: string, port: number | undefined): boolean =>\n port == null || (protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)\n\nconst formatBaseUrl = (protocol: string, hostname: string, port: number | undefined): string =>\n isDefaultPort(protocol, port) ? `${protocol}://${hostname}` : `${protocol}://${hostname}:${port}`\n\nconst firstHeaderValue = (value: string | string[] | undefined): string | undefined => {\n const raw = Array.isArray(value) ? value[0] : value\n return raw?.split(',')[0]?.trim() || undefined\n}\n\nconst parseHostHeader = (hostHeader: string): { hostname: string; port: number | undefined } => {\n const url = new URL(`http://${hostHeader}`)\n return { hostname: url.hostname, port: url.port ? Number(url.port) : undefined }\n}\n\nconst isEncryptedSocket = (req: IncomingMessage): boolean => 'encrypted' in req.socket && (req.socket as TLSSocket).encrypted === true\n\nconst isEncryptedConnect = (req: IncomingMessage): boolean => {\n const forwarded = firstHeaderValue(req.headers['x-forwarded-proto'])?.toLowerCase()\n if (forwarded === 'https' || forwarded === 'wss') return true\n if (forwarded === 'http' || forwarded === 'ws') return false\n return isEncryptedSocket(req)\n}\n\nconst resolveForwardedHost = (req: IncomingMessage): string | undefined => firstHeaderValue(req.headers['x-forwarded-host'])\n\nconst resolveHostAndPort = (req: IncomingMessage, fallbackHostname?: string): { host: string; port: number | undefined } => {\n const headerValue = resolveForwardedHost(req) ?? req.headers.host\n if (headerValue) {\n const { hostname, port } = parseHostHeader(headerValue)\n return { host: hostname, port }\n }\n return { host: fallbackHostname ?? '', port: undefined }\n}\n\n/**\n * Builds the base URL (`protocol://host[:port]`) for an Express HTTP request, using the request's\n * protocol and resolving the host/port from forwarding headers with the Express hostname as fallback.\n * The port is omitted when it matches the default for the protocol (80 for http, 443 for https).\n * @param req The Express request.\n * @returns The base URL string.\n */\nexport const requestBaseUrl = (req: Request): string => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return formatBaseUrl(req.protocol, host, port)\n}\n\n/**\n * Builds the base URL (`http(s)://host[:port]`) for a raw WebSocket upgrade (connect) request.\n * Returns an `https` URL when the connection is TLS-encrypted or `x-forwarded-proto` indicates a\n * secure scheme, otherwise `http`. Throws if no host can be determined from the request headers,\n * since upgrade requests have no Express `hostname` fallback.\n * @param req The incoming upgrade request.\n * @returns The base URL string.\n * @throws Error when the host cannot be resolved from the request.\n */\nexport const connectRequestBaseUrl = (req: IncomingMessage): string => {\n const { host, port } = resolveHostAndPort(req)\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return formatBaseUrl(isEncryptedConnect(req) ? 'https' : 'http', host, port)\n}\n\nconst buildSharedRequestInfo = (req: IncomingMessage) => ({\n requestId: req.headers['x-request-id']?.toString() ?? randomUUID(),\n method: req.method ?? '',\n origin: req.headers.origin ?? '',\n referer: req.headers.referer?.toString() ?? '',\n arrLogId: req.headers['x-arr-log-id']?.toString() ?? undefined,\n clientIp: firstHeaderValue(req.headers['x-forwarded-for']) ?? req.socket.remoteAddress,\n correlationId: req.headers['x-correlation-id']?.toString() ?? undefined,\n userAgent: req.headers['user-agent']?.toString() ?? undefined,\n})\n\nexport const buildBaseRequestInfo = (req: Request): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return {\n ...buildSharedRequestInfo(req),\n source: 'http',\n protocol: req.protocol as 'http' | 'https',\n host,\n port,\n baseUrl: formatBaseUrl(req.protocol, host, port),\n url: req.originalUrl,\n }\n}\n\nexport const buildConnectRequestInfo = (req: IncomingMessage): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req)\n const protocol = isEncryptedConnect(req) ? 'wss' : 'ws'\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return {\n ...buildSharedRequestInfo(req),\n source: 'subscription',\n protocol,\n host,\n port,\n baseUrl: formatBaseUrl(protocol === 'wss' ? 'https' : 'http', host, port),\n url: req.url ?? '',\n }\n}\n"],"names":["randomUUID"],"mappings":"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"}
|
package/request-info.mjs
CHANGED
|
@@ -28,10 +28,26 @@ const resolveHostAndPort = (req, fallbackHostname) => {
|
|
|
28
28
|
}
|
|
29
29
|
return { host: fallbackHostname ?? '', port: undefined };
|
|
30
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Builds the base URL (`protocol://host[:port]`) for an Express HTTP request, using the request's
|
|
33
|
+
* protocol and resolving the host/port from forwarding headers with the Express hostname as fallback.
|
|
34
|
+
* The port is omitted when it matches the default for the protocol (80 for http, 443 for https).
|
|
35
|
+
* @param req The Express request.
|
|
36
|
+
* @returns The base URL string.
|
|
37
|
+
*/
|
|
31
38
|
const requestBaseUrl = (req) => {
|
|
32
39
|
const { host, port } = resolveHostAndPort(req, req.hostname);
|
|
33
40
|
return formatBaseUrl(req.protocol, host, port);
|
|
34
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* Builds the base URL (`http(s)://host[:port]`) for a raw WebSocket upgrade (connect) request.
|
|
44
|
+
* Returns an `https` URL when the connection is TLS-encrypted or `x-forwarded-proto` indicates a
|
|
45
|
+
* secure scheme, otherwise `http`. Throws if no host can be determined from the request headers,
|
|
46
|
+
* since upgrade requests have no Express `hostname` fallback.
|
|
47
|
+
* @param req The incoming upgrade request.
|
|
48
|
+
* @returns The base URL string.
|
|
49
|
+
* @throws Error when the host cannot be resolved from the request.
|
|
50
|
+
*/
|
|
35
51
|
const connectRequestBaseUrl = (req) => {
|
|
36
52
|
const { host, port } = resolveHostAndPort(req);
|
|
37
53
|
if (!host)
|
package/request-info.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-info.mjs","sources":["../src/request-info.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport type { Request } from 'express'\nimport type { IncomingMessage } from 'http'\nimport type { TLSSocket } from 'tls'\n\nexport interface BaseRequestInfo extends Record<string, unknown> {\n requestId: string\n source: 'http' | 'subscription'\n protocol: 'http' | 'https' | 'ws' | 'wss'\n host: string\n port?: number\n method: string\n baseUrl: string\n url: string\n origin: string\n referer?: string\n correlationId?: string\n arrLogId?: string\n clientIp?: string\n userAgent?: string\n}\n\nconst isDefaultPort = (protocol: string, port: number | undefined): boolean =>\n port == null || (protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)\n\nconst formatBaseUrl = (protocol: string, hostname: string, port: number | undefined): string =>\n isDefaultPort(protocol, port) ? `${protocol}://${hostname}` : `${protocol}://${hostname}:${port}`\n\nconst firstHeaderValue = (value: string | string[] | undefined): string | undefined => {\n const raw = Array.isArray(value) ? value[0] : value\n return raw?.split(',')[0]?.trim() || undefined\n}\n\nconst parseHostHeader = (hostHeader: string): { hostname: string; port: number | undefined } => {\n const url = new URL(`http://${hostHeader}`)\n return { hostname: url.hostname, port: url.port ? Number(url.port) : undefined }\n}\n\nconst isEncryptedSocket = (req: IncomingMessage): boolean => 'encrypted' in req.socket && (req.socket as TLSSocket).encrypted === true\n\nconst isEncryptedConnect = (req: IncomingMessage): boolean => {\n const forwarded = firstHeaderValue(req.headers['x-forwarded-proto'])?.toLowerCase()\n if (forwarded === 'https' || forwarded === 'wss') return true\n if (forwarded === 'http' || forwarded === 'ws') return false\n return isEncryptedSocket(req)\n}\n\nconst resolveForwardedHost = (req: IncomingMessage): string | undefined => firstHeaderValue(req.headers['x-forwarded-host'])\n\nconst resolveHostAndPort = (req: IncomingMessage, fallbackHostname?: string): { host: string; port: number | undefined } => {\n const headerValue = resolveForwardedHost(req) ?? req.headers.host\n if (headerValue) {\n const { hostname, port } = parseHostHeader(headerValue)\n return { host: hostname, port }\n }\n return { host: fallbackHostname ?? '', port: undefined }\n}\n\nexport const requestBaseUrl = (req: Request): string => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return formatBaseUrl(req.protocol, host, port)\n}\n\nexport const connectRequestBaseUrl = (req: IncomingMessage): string => {\n const { host, port } = resolveHostAndPort(req)\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return formatBaseUrl(isEncryptedConnect(req) ? 'https' : 'http', host, port)\n}\n\nconst buildSharedRequestInfo = (req: IncomingMessage) => ({\n requestId: req.headers['x-request-id']?.toString() ?? randomUUID(),\n method: req.method ?? '',\n origin: req.headers.origin ?? '',\n referer: req.headers.referer?.toString() ?? '',\n arrLogId: req.headers['x-arr-log-id']?.toString() ?? undefined,\n clientIp: firstHeaderValue(req.headers['x-forwarded-for']) ?? req.socket.remoteAddress,\n correlationId: req.headers['x-correlation-id']?.toString() ?? undefined,\n userAgent: req.headers['user-agent']?.toString() ?? undefined,\n})\n\nexport const buildBaseRequestInfo = (req: Request): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return {\n ...buildSharedRequestInfo(req),\n source: 'http',\n protocol: req.protocol as 'http' | 'https',\n host,\n port,\n baseUrl: formatBaseUrl(req.protocol, host, port),\n url: req.originalUrl,\n }\n}\n\nexport const buildConnectRequestInfo = (req: IncomingMessage): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req)\n const protocol = isEncryptedConnect(req) ? 'wss' : 'ws'\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return {\n ...buildSharedRequestInfo(req),\n source: 'subscription',\n protocol,\n host,\n port,\n baseUrl: formatBaseUrl(protocol === 'wss' ? 'https' : 'http', host, port),\n url: req.url ?? '',\n }\n}\n"],"names":[],"mappings":";;AAsBA,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,IAAwB,KAC/D,IAAI,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC,KAAK,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,GAAG,CAAC;AAEhG,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAE,IAAwB,KACjF,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,QAAQ,EAAE,GAAG,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,QAAQ,CAAA,CAAA,EAAI,IAAI,EAAE;AAEnG,MAAM,gBAAgB,GAAG,CAAC,KAAoC,KAAwB;AACpF,IAAA,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AACnD,IAAA,OAAO,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS;AAChD,CAAC;AAED,MAAM,eAAe,GAAG,CAAC,UAAkB,KAAoD;IAC7F,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAA,OAAA,EAAU,UAAU,CAAA,CAAE,CAAC;IAC3C,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,EAAE;AAClF,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,GAAoB,KAAc,WAAW,IAAI,GAAG,CAAC,MAAM,IAAK,GAAG,CAAC,MAAoB,CAAC,SAAS,KAAK,IAAI;AAEtI,MAAM,kBAAkB,GAAG,CAAC,GAAoB,KAAa;AAC3D,IAAA,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,EAAE,WAAW,EAAE;AACnF,IAAA,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,KAAK;AAAE,QAAA,OAAO,IAAI;AAC7D,IAAA,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,IAAI;AAAE,QAAA,OAAO,KAAK;AAC5D,IAAA,OAAO,iBAAiB,CAAC,GAAG,CAAC;AAC/B,CAAC;AAED,MAAM,oBAAoB,GAAG,CAAC,GAAoB,KAAyB,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE5H,MAAM,kBAAkB,GAAG,CAAC,GAAoB,EAAE,gBAAyB,KAAgD;AACzH,IAAA,MAAM,WAAW,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI;IACjE,IAAI,WAAW,EAAE;QACf,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,WAAW,CAAC;AACvD,QAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjC;IACA,OAAO,EAAE,IAAI,EAAE,gBAAgB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;AAC1D,CAAC;
|
|
1
|
+
{"version":3,"file":"request-info.mjs","sources":["../src/request-info.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport type { Request } from 'express'\nimport type { IncomingMessage } from 'http'\nimport type { TLSSocket } from 'tls'\n\nexport interface BaseRequestInfo extends Record<string, unknown> {\n requestId: string\n source: 'http' | 'subscription'\n protocol: 'http' | 'https' | 'ws' | 'wss'\n host: string\n port?: number\n method: string\n baseUrl: string\n url: string\n origin: string\n referer?: string\n correlationId?: string\n arrLogId?: string\n clientIp?: string\n userAgent?: string\n}\n\nconst isDefaultPort = (protocol: string, port: number | undefined): boolean =>\n port == null || (protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)\n\nconst formatBaseUrl = (protocol: string, hostname: string, port: number | undefined): string =>\n isDefaultPort(protocol, port) ? `${protocol}://${hostname}` : `${protocol}://${hostname}:${port}`\n\nconst firstHeaderValue = (value: string | string[] | undefined): string | undefined => {\n const raw = Array.isArray(value) ? value[0] : value\n return raw?.split(',')[0]?.trim() || undefined\n}\n\nconst parseHostHeader = (hostHeader: string): { hostname: string; port: number | undefined } => {\n const url = new URL(`http://${hostHeader}`)\n return { hostname: url.hostname, port: url.port ? Number(url.port) : undefined }\n}\n\nconst isEncryptedSocket = (req: IncomingMessage): boolean => 'encrypted' in req.socket && (req.socket as TLSSocket).encrypted === true\n\nconst isEncryptedConnect = (req: IncomingMessage): boolean => {\n const forwarded = firstHeaderValue(req.headers['x-forwarded-proto'])?.toLowerCase()\n if (forwarded === 'https' || forwarded === 'wss') return true\n if (forwarded === 'http' || forwarded === 'ws') return false\n return isEncryptedSocket(req)\n}\n\nconst resolveForwardedHost = (req: IncomingMessage): string | undefined => firstHeaderValue(req.headers['x-forwarded-host'])\n\nconst resolveHostAndPort = (req: IncomingMessage, fallbackHostname?: string): { host: string; port: number | undefined } => {\n const headerValue = resolveForwardedHost(req) ?? req.headers.host\n if (headerValue) {\n const { hostname, port } = parseHostHeader(headerValue)\n return { host: hostname, port }\n }\n return { host: fallbackHostname ?? '', port: undefined }\n}\n\n/**\n * Builds the base URL (`protocol://host[:port]`) for an Express HTTP request, using the request's\n * protocol and resolving the host/port from forwarding headers with the Express hostname as fallback.\n * The port is omitted when it matches the default for the protocol (80 for http, 443 for https).\n * @param req The Express request.\n * @returns The base URL string.\n */\nexport const requestBaseUrl = (req: Request): string => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return formatBaseUrl(req.protocol, host, port)\n}\n\n/**\n * Builds the base URL (`http(s)://host[:port]`) for a raw WebSocket upgrade (connect) request.\n * Returns an `https` URL when the connection is TLS-encrypted or `x-forwarded-proto` indicates a\n * secure scheme, otherwise `http`. Throws if no host can be determined from the request headers,\n * since upgrade requests have no Express `hostname` fallback.\n * @param req The incoming upgrade request.\n * @returns The base URL string.\n * @throws Error when the host cannot be resolved from the request.\n */\nexport const connectRequestBaseUrl = (req: IncomingMessage): string => {\n const { host, port } = resolveHostAndPort(req)\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return formatBaseUrl(isEncryptedConnect(req) ? 'https' : 'http', host, port)\n}\n\nconst buildSharedRequestInfo = (req: IncomingMessage) => ({\n requestId: req.headers['x-request-id']?.toString() ?? randomUUID(),\n method: req.method ?? '',\n origin: req.headers.origin ?? '',\n referer: req.headers.referer?.toString() ?? '',\n arrLogId: req.headers['x-arr-log-id']?.toString() ?? undefined,\n clientIp: firstHeaderValue(req.headers['x-forwarded-for']) ?? req.socket.remoteAddress,\n correlationId: req.headers['x-correlation-id']?.toString() ?? undefined,\n userAgent: req.headers['user-agent']?.toString() ?? undefined,\n})\n\nexport const buildBaseRequestInfo = (req: Request): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req, req.hostname)\n return {\n ...buildSharedRequestInfo(req),\n source: 'http',\n protocol: req.protocol as 'http' | 'https',\n host,\n port,\n baseUrl: formatBaseUrl(req.protocol, host, port),\n url: req.originalUrl,\n }\n}\n\nexport const buildConnectRequestInfo = (req: IncomingMessage): BaseRequestInfo => {\n const { host, port } = resolveHostAndPort(req)\n const protocol = isEncryptedConnect(req) ? 'wss' : 'ws'\n if (!host) throw new Error('Cannot determine base URL from websocket connect request')\n return {\n ...buildSharedRequestInfo(req),\n source: 'subscription',\n protocol,\n host,\n port,\n baseUrl: formatBaseUrl(protocol === 'wss' ? 'https' : 'http', host, port),\n url: req.url ?? '',\n }\n}\n"],"names":[],"mappings":"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"}
|