veryfront 0.1.121 → 0.1.124
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/esm/deno.js +1 -1
- package/esm/src/security/http/response/security-handler.js +3 -3
- package/esm/src/server/context/request-context.d.ts.map +1 -1
- package/esm/src/server/context/request-context.js +2 -10
- package/esm/src/server/handlers/dev/projects/api.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/projects/api.js +2 -4
- package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/hmr.handler.js +2 -1
- package/esm/src/server/runtime-handler/project-resolution.d.ts.map +1 -1
- package/esm/src/server/runtime-handler/project-resolution.js +2 -10
- package/esm/src/server/utils/request-host.d.ts +4 -0
- package/esm/src/server/utils/request-host.d.ts.map +1 -0
- package/esm/src/server/utils/request-host.js +11 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/security/http/response/security-handler.ts +3 -3
- package/src/src/server/context/request-context.ts +2 -11
- package/src/src/server/handlers/dev/projects/api.ts +2 -5
- package/src/src/server/handlers/preview/hmr.handler.ts +2 -1
- package/src/src/server/runtime-handler/project-resolution.ts +2 -10
- package/src/src/server/utils/request-host.ts +13 -0
- package/src/src/utils/version-constant.ts +1 -1
package/esm/deno.js
CHANGED
|
@@ -12,8 +12,8 @@ export function generateNonce() {
|
|
|
12
12
|
/**
|
|
13
13
|
* Build a default CSP that works for typical veryfront apps.
|
|
14
14
|
*
|
|
15
|
-
* - Scripts: nonce-based + cdn.jsdelivr.net (Scalar API docs,
|
|
16
|
-
*
|
|
15
|
+
* - Scripts: nonce-based + cdn.jsdelivr.net + esm.sh (Scalar API docs,
|
|
16
|
+
* html2canvas, legacy/browser ESM hydration)
|
|
17
17
|
* - Styles: 'self' + 'unsafe-inline' + nonce + Google Fonts + cdn.veryfront.com
|
|
18
18
|
* plus style-src-attr 'unsafe-inline' so React style="" attributes remain
|
|
19
19
|
* compatible while inline <style> tags continue to use the nonce
|
|
@@ -28,7 +28,7 @@ export function generateNonce() {
|
|
|
28
28
|
function buildDefaultCSP(nonce) {
|
|
29
29
|
return [
|
|
30
30
|
`default-src 'self'`,
|
|
31
|
-
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net`,
|
|
31
|
+
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net https://esm.sh`,
|
|
32
32
|
`style-src 'self' 'unsafe-inline' 'nonce-${nonce}' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
33
33
|
`style-src-attr 'unsafe-inline'`,
|
|
34
34
|
`img-src 'self' data: https:`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAKlD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,cAAc,CAqBzE;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,cAAc,CAAC,EAAE,OAAO,GACvB,MAAM,GAAG,YAAY,GAAG,WAAW,CAIrC;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAExF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAG/F"}
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
import { getHostEnv } from "../../platform/compat/process.js";
|
|
2
2
|
import { parseProjectDomain } from "../utils/domain-parser.js";
|
|
3
|
+
import { getEffectiveRequestHost } from "../utils/request-host.js";
|
|
3
4
|
export function createRequestContext(req) {
|
|
4
|
-
const
|
|
5
|
-
const rawForwardedHost = req.headers.get("x-forwarded-host");
|
|
6
|
-
// x-forwarded-host can be comma-separated (multiple proxies); take the first entry.
|
|
7
|
-
const forwardedHost = rawForwardedHost
|
|
8
|
-
? (rawForwardedHost.split(",")[0]?.trim() || undefined)
|
|
9
|
-
: undefined;
|
|
10
|
-
const hostHeader = req.headers.get("host");
|
|
11
|
-
// In proxy mode, req.url hostname may be 127.0.0.1 while the real domain
|
|
12
|
-
// is in the Host header (e.g., "flow-ops.lvh.me:3010"). Prefer Host header.
|
|
13
|
-
const effectiveHost = forwardedHost ?? hostHeader ?? hostname;
|
|
5
|
+
const effectiveHost = getEffectiveRequestHost(req);
|
|
14
6
|
const parsed = parseProjectDomain(effectiveHost);
|
|
15
7
|
const headerProjectSlug = req.headers.get("x-project-slug")?.trim() || undefined;
|
|
16
8
|
const xEnvironment = req.headers.get("x-environment");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/dev/projects/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/dev/projects/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAYrD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAOpG"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as dntShim from "../../../../../_dnt.shims.js";
|
|
2
|
+
import { getEffectiveRequestHost } from "../../../utils/request-host.js";
|
|
2
3
|
const JSON_HEADERS = {
|
|
3
4
|
"Content-Type": "application/json",
|
|
4
5
|
"Cache-Control": "no-cache",
|
|
@@ -16,10 +17,7 @@ export function handleProjectsAPI(req, ctx) {
|
|
|
16
17
|
}
|
|
17
18
|
function handleGetConfig(req, ctx) {
|
|
18
19
|
const url = new URL(req.url);
|
|
19
|
-
const host = req.
|
|
20
|
-
req.headers.get("host") ??
|
|
21
|
-
url.host ??
|
|
22
|
-
"lvh.me";
|
|
20
|
+
const host = getEffectiveRequestHost(req, url) || "lvh.me";
|
|
23
21
|
const hostWithoutPort = host.replace(/:\d+$/, "") || "lvh.me";
|
|
24
22
|
const port = host.includes(":") ? host.split(":")[1] ?? "" : "";
|
|
25
23
|
return jsonResponse({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AASrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AASrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAoBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAK7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IAsCzB,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA0JzE;;;;;OAKG;YACW,wBAAwB;IAuCtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,+BAA+B,IAAI,MAAM,IAAI;IAWpD,MAAM,CAAC,QAAQ,IAAI,IAAI;IAcvB,OAAO,CAAC,MAAM,CAAC,cAAc;CAO9B"}
|
|
@@ -10,6 +10,7 @@ import { isLocalDevHost } from "../../utils/domain-parser.js";
|
|
|
10
10
|
import { addClient, clearAll, getClient, getClientCount, getClientDetails, removeClient, } from "./hmr-client-manager.js";
|
|
11
11
|
import { getPingIntervalMs, startPingInterval, stopPingInterval } from "./hmr-ping-keepalive.js";
|
|
12
12
|
import { broadcastUpdate, getMetrics } from "./hmr-message-router.js";
|
|
13
|
+
import { getEffectiveRequestHost } from "../../utils/request-host.js";
|
|
13
14
|
const logger = serverLogger.component("hmr-handler");
|
|
14
15
|
// Priority between auth (0) and high (100)
|
|
15
16
|
const PRIORITY_HMR = HandlerPriority.EARLY;
|
|
@@ -62,7 +63,7 @@ export class HMRHandler extends BaseHandler {
|
|
|
62
63
|
const queryEnv = url.searchParams.get("x-environment");
|
|
63
64
|
const isPreviewMode = ctx.requestContext?.mode === "preview" || queryEnv === "preview";
|
|
64
65
|
const isLocal = !!ctx.isLocalProject;
|
|
65
|
-
const host = req
|
|
66
|
+
const host = getEffectiveRequestHost(req, url);
|
|
66
67
|
const isLocalhost = isLocalDevHost(host);
|
|
67
68
|
if (!isPreviewMode && !isLocal && !isLocalhost) {
|
|
68
69
|
logger.warn("Skipping /_ws - not preview, local dev, or localhost", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-resolution.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/project-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,KAAK,YAAY,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACtF,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"project-resolution.d.ts","sourceRoot":"","sources":["../../../../src/src/server/runtime-handler/project-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,KAAK,YAAY,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACtF,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAStF;;GAEG;AACH,UAAU,qBAAqB;IAC7B,qBAAqB,CAAC,EAAE,OAAO,qBAAqB,CAAC;IACrD,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;CAChD;AAID;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAE7E;AAUD,UAAU,cAAc;IACtB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,0CAA0C;IAC1C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,0CAA0C;IAC1C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,4CAA4C;IAC5C,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4CAA4C;IAC5C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,2EAA2E;IAC3E,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,sCAAsC;IACtC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,wDAAwD;IACxD,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,8CAA8C;IAC9C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAMD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,cAAc,CAkBpF;AAED,UAAU,uBAAuB;IAC/B,4BAA4B;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,0BAA0B;IAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,0BAA0B;IAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,yCAAyC;IACzC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,sDAAsD;IACtD,QAAQ,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACvC,gCAAgC;IAChC,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,UAAU,wBAAwB;IAChC,sCAAsC;IACtC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,gDAAgD;IAChD,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;QAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;QAClC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KAC3B,CAAC;IACF,+CAA+C;IAC/C,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,6CAA6C;IAC7C,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,wCAAwC;IACxC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,uBAAuB,CAAC,CAuHlC;AAGD,OAAO,EAAE,KAAK,YAAY,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -4,6 +4,7 @@ import { getEnvironmentType, lookupProjectByDomain } from "../utils/domain-looku
|
|
|
4
4
|
import { parseProxyEnvironment } from "./proxy-environment.js";
|
|
5
5
|
import { SpanNames, withSpan } from "./tracing.js";
|
|
6
6
|
import { isInternalHost } from "./request-utils.js";
|
|
7
|
+
import { getEffectiveRequestHost } from "../utils/request-host.js";
|
|
7
8
|
const baseLogger = getBaseLogger("SERVER");
|
|
8
9
|
const logger = baseLogger.component("project-resolution");
|
|
9
10
|
let injectedDeps = null;
|
|
@@ -20,17 +21,8 @@ function getDeps() {
|
|
|
20
21
|
getEnvironmentType: injectedDeps?.getEnvironmentType ?? getEnvironmentType,
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
|
-
function parseForwardedHost(raw) {
|
|
24
|
-
if (!raw)
|
|
25
|
-
return undefined;
|
|
26
|
-
// x-forwarded-host can be a comma-separated list when multiple proxies
|
|
27
|
-
// are chained. Take the first (client-facing) entry and trim whitespace.
|
|
28
|
-
const first = raw.split(",")[0]?.trim();
|
|
29
|
-
return first || undefined;
|
|
30
|
-
}
|
|
31
24
|
function getEffectiveHost(req, url) {
|
|
32
|
-
|
|
33
|
-
return forwardedHost ?? req.headers.get("host") ?? url.host;
|
|
25
|
+
return getEffectiveRequestHost(req, url);
|
|
34
26
|
}
|
|
35
27
|
/**
|
|
36
28
|
* Extract project-related headers from a request.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-host.d.ts","sourceRoot":"","sources":["../../../../src/src/server/utils/request-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAKzE;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAI/E"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function parseForwardedHost(raw) {
|
|
2
|
+
if (!raw)
|
|
3
|
+
return undefined;
|
|
4
|
+
const first = raw.split(",")[0]?.trim();
|
|
5
|
+
return first || undefined;
|
|
6
|
+
}
|
|
7
|
+
export function getEffectiveRequestHost(req, url) {
|
|
8
|
+
return parseForwardedHost(req.headers.get("x-forwarded-host")) ??
|
|
9
|
+
req.headers.get("host") ??
|
|
10
|
+
(url ?? new URL(req.url)).host;
|
|
11
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.124";
|
|
2
2
|
//# sourceMappingURL=version-constant.d.ts.map
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
|
@@ -18,8 +18,8 @@ export function generateNonce(): string {
|
|
|
18
18
|
/**
|
|
19
19
|
* Build a default CSP that works for typical veryfront apps.
|
|
20
20
|
*
|
|
21
|
-
* - Scripts: nonce-based + cdn.jsdelivr.net (Scalar API docs,
|
|
22
|
-
*
|
|
21
|
+
* - Scripts: nonce-based + cdn.jsdelivr.net + esm.sh (Scalar API docs,
|
|
22
|
+
* html2canvas, legacy/browser ESM hydration)
|
|
23
23
|
* - Styles: 'self' + 'unsafe-inline' + nonce + Google Fonts + cdn.veryfront.com
|
|
24
24
|
* plus style-src-attr 'unsafe-inline' so React style="" attributes remain
|
|
25
25
|
* compatible while inline <style> tags continue to use the nonce
|
|
@@ -34,7 +34,7 @@ export function generateNonce(): string {
|
|
|
34
34
|
function buildDefaultCSP(nonce: string): string {
|
|
35
35
|
return [
|
|
36
36
|
`default-src 'self'`,
|
|
37
|
-
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net`,
|
|
37
|
+
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net https://esm.sh`,
|
|
38
38
|
`style-src 'self' 'unsafe-inline' 'nonce-${nonce}' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
39
39
|
`style-src-attr 'unsafe-inline'`,
|
|
40
40
|
`img-src 'self' data: https:`,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
2
|
import { getHostEnv } from "../../platform/compat/process.js";
|
|
3
3
|
import { parseProjectDomain } from "../utils/domain-parser.js";
|
|
4
|
+
import { getEffectiveRequestHost } from "../utils/request-host.js";
|
|
4
5
|
|
|
5
6
|
export interface RequestContext {
|
|
6
7
|
token: string;
|
|
@@ -10,17 +11,7 @@ export interface RequestContext {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export function createRequestContext(req: dntShim.Request): RequestContext {
|
|
13
|
-
const
|
|
14
|
-
const rawForwardedHost = req.headers.get("x-forwarded-host");
|
|
15
|
-
// x-forwarded-host can be comma-separated (multiple proxies); take the first entry.
|
|
16
|
-
const forwardedHost = rawForwardedHost
|
|
17
|
-
? (rawForwardedHost.split(",")[0]?.trim() || undefined)
|
|
18
|
-
: undefined;
|
|
19
|
-
const hostHeader = req.headers.get("host");
|
|
20
|
-
|
|
21
|
-
// In proxy mode, req.url hostname may be 127.0.0.1 while the real domain
|
|
22
|
-
// is in the Host header (e.g., "flow-ops.lvh.me:3010"). Prefer Host header.
|
|
23
|
-
const effectiveHost = forwardedHost ?? hostHeader ?? hostname;
|
|
14
|
+
const effectiveHost = getEffectiveRequestHost(req);
|
|
24
15
|
const parsed = parseProjectDomain(effectiveHost);
|
|
25
16
|
const headerProjectSlug = req.headers.get("x-project-slug")?.trim() || undefined;
|
|
26
17
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as dntShim from "../../../../../_dnt.shims.js";
|
|
2
2
|
import type { HandlerContext } from "../../types.js";
|
|
3
|
+
import { getEffectiveRequestHost } from "../../../utils/request-host.js";
|
|
3
4
|
|
|
4
5
|
const JSON_HEADERS = {
|
|
5
6
|
"Content-Type": "application/json",
|
|
@@ -21,11 +22,7 @@ export function handleProjectsAPI(req: dntShim.Request, ctx: HandlerContext): dn
|
|
|
21
22
|
|
|
22
23
|
function handleGetConfig(req: dntShim.Request, ctx: HandlerContext): dntShim.Response {
|
|
23
24
|
const url = new URL(req.url);
|
|
24
|
-
|
|
25
|
-
const host = req.headers.get("x-forwarded-host") ??
|
|
26
|
-
req.headers.get("host") ??
|
|
27
|
-
url.host ??
|
|
28
|
-
"lvh.me";
|
|
25
|
+
const host = getEffectiveRequestHost(req, url) || "lvh.me";
|
|
29
26
|
|
|
30
27
|
const hostWithoutPort = host.replace(/:\d+$/, "") || "lvh.me";
|
|
31
28
|
const port = host.includes(":") ? host.split(":")[1] ?? "" : "";
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
} from "./hmr-client-manager.js";
|
|
29
29
|
import { getPingIntervalMs, startPingInterval, stopPingInterval } from "./hmr-ping-keepalive.js";
|
|
30
30
|
import { broadcastUpdate, getMetrics } from "./hmr-message-router.js";
|
|
31
|
+
import { getEffectiveRequestHost } from "../../utils/request-host.js";
|
|
31
32
|
|
|
32
33
|
const logger = serverLogger.component("hmr-handler");
|
|
33
34
|
|
|
@@ -95,7 +96,7 @@ export class HMRHandler extends BaseHandler {
|
|
|
95
96
|
const queryEnv = url.searchParams.get("x-environment");
|
|
96
97
|
const isPreviewMode = ctx.requestContext?.mode === "preview" || queryEnv === "preview";
|
|
97
98
|
const isLocal = !!ctx.isLocalProject;
|
|
98
|
-
const host = req
|
|
99
|
+
const host = getEffectiveRequestHost(req, url);
|
|
99
100
|
const isLocalhost = isLocalDevHost(host);
|
|
100
101
|
|
|
101
102
|
if (!isPreviewMode && !isLocal && !isLocalhost) {
|
|
@@ -19,6 +19,7 @@ import { getEnvironmentType, lookupProjectByDomain } from "../utils/domain-looku
|
|
|
19
19
|
import { parseProxyEnvironment, type ProxyEnvironment } from "./proxy-environment.js";
|
|
20
20
|
import { SpanNames, withSpan } from "./tracing.js";
|
|
21
21
|
import { isInternalHost } from "./request-utils.js";
|
|
22
|
+
import { getEffectiveRequestHost } from "../utils/request-host.js";
|
|
22
23
|
|
|
23
24
|
const baseLogger = getBaseLogger("SERVER");
|
|
24
25
|
|
|
@@ -73,17 +74,8 @@ interface RequestHeaders {
|
|
|
73
74
|
projectPath: string | undefined;
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
function parseForwardedHost(raw: string | null): string | undefined {
|
|
77
|
-
if (!raw) return undefined;
|
|
78
|
-
// x-forwarded-host can be a comma-separated list when multiple proxies
|
|
79
|
-
// are chained. Take the first (client-facing) entry and trim whitespace.
|
|
80
|
-
const first = raw.split(",")[0]?.trim();
|
|
81
|
-
return first || undefined;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
77
|
function getEffectiveHost(req: dntShim.Request, url: URL): string {
|
|
85
|
-
|
|
86
|
-
return forwardedHost ?? req.headers.get("host") ?? url.host;
|
|
78
|
+
return getEffectiveRequestHost(req, url);
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
/**
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
|
+
export function parseForwardedHost(raw: string | null): string | undefined {
|
|
3
|
+
if (!raw) return undefined;
|
|
4
|
+
|
|
5
|
+
const first = raw.split(",")[0]?.trim();
|
|
6
|
+
return first || undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getEffectiveRequestHost(req: dntShim.Request, url?: URL): string {
|
|
10
|
+
return parseForwardedHost(req.headers.get("x-forwarded-host")) ??
|
|
11
|
+
req.headers.get("host") ??
|
|
12
|
+
(url ?? new URL(req.url)).host;
|
|
13
|
+
}
|