veryfront 0.1.122 → 0.1.126
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.d.ts.map +1 -1
- package/esm/src/security/http/response/security-handler.js +12 -4
- 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 +12 -4
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/security/http/response/security-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQjD,wBAAgB,aAAa,IAAI,MAAM,CAItC;
|
|
1
|
+
{"version":3,"file":"security-handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/security/http/response/security-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQjD,wBAAgB,aAAa,IAAI,MAAM,CAItC;AA2CD,wBAAgB,QAAQ,CACtB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,MAAM,CA4BR;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,MAAM,CAMR;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,cAAc,EACxB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,IAAI,CA6DN"}
|
|
@@ -14,9 +14,16 @@ export function generateNonce() {
|
|
|
14
14
|
*
|
|
15
15
|
* - Scripts: nonce-based + cdn.jsdelivr.net + esm.sh (Scalar API docs,
|
|
16
16
|
* html2canvas, legacy/browser ESM hydration)
|
|
17
|
-
* - Styles:
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* - Styles:
|
|
18
|
+
* - style-src: 'self' + 'unsafe-inline' + Google Fonts + cdn.veryfront.com
|
|
19
|
+
* so React style="" attributes and framework inline styles remain
|
|
20
|
+
* compatible. Do not include a nonce in style-src here: browsers ignore
|
|
21
|
+
* 'unsafe-inline' when a nonce/hash is present on the directive, which
|
|
22
|
+
* breaks React style attributes.
|
|
23
|
+
* - style-src-elem: nonce-based + Google Fonts + cdn.veryfront.com for
|
|
24
|
+
* inline <style> tags and stylesheet elements
|
|
25
|
+
* - style-src-attr: 'unsafe-inline' for modern browsers with directive-level
|
|
26
|
+
* style attribute support
|
|
20
27
|
* - Images/media/fonts: 'self' + data: + https: + cdn.veryfront.com
|
|
21
28
|
* - Connections: 'self' + wss: + https: (WebSocket for HMR/live reload, API calls)
|
|
22
29
|
* - Objects: 'none' (block Flash/plugins)
|
|
@@ -29,7 +36,8 @@ function buildDefaultCSP(nonce) {
|
|
|
29
36
|
return [
|
|
30
37
|
`default-src 'self'`,
|
|
31
38
|
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net https://esm.sh`,
|
|
32
|
-
`style-src 'self' 'unsafe-inline'
|
|
39
|
+
`style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
40
|
+
`style-src-elem 'self' 'nonce-${nonce}' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
33
41
|
`style-src-attr 'unsafe-inline'`,
|
|
34
42
|
`img-src 'self' data: https:`,
|
|
35
43
|
`font-src 'self' data: https://fonts.gstatic.com https://cdn.veryfront.com`,
|
|
@@ -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":"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"}
|
|
@@ -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.126";
|
|
2
2
|
//# sourceMappingURL=version-constant.d.ts.map
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
|
@@ -20,9 +20,16 @@ export function generateNonce(): string {
|
|
|
20
20
|
*
|
|
21
21
|
* - Scripts: nonce-based + cdn.jsdelivr.net + esm.sh (Scalar API docs,
|
|
22
22
|
* html2canvas, legacy/browser ESM hydration)
|
|
23
|
-
* - Styles:
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* - Styles:
|
|
24
|
+
* - style-src: 'self' + 'unsafe-inline' + Google Fonts + cdn.veryfront.com
|
|
25
|
+
* so React style="" attributes and framework inline styles remain
|
|
26
|
+
* compatible. Do not include a nonce in style-src here: browsers ignore
|
|
27
|
+
* 'unsafe-inline' when a nonce/hash is present on the directive, which
|
|
28
|
+
* breaks React style attributes.
|
|
29
|
+
* - style-src-elem: nonce-based + Google Fonts + cdn.veryfront.com for
|
|
30
|
+
* inline <style> tags and stylesheet elements
|
|
31
|
+
* - style-src-attr: 'unsafe-inline' for modern browsers with directive-level
|
|
32
|
+
* style attribute support
|
|
26
33
|
* - Images/media/fonts: 'self' + data: + https: + cdn.veryfront.com
|
|
27
34
|
* - Connections: 'self' + wss: + https: (WebSocket for HMR/live reload, API calls)
|
|
28
35
|
* - Objects: 'none' (block Flash/plugins)
|
|
@@ -35,7 +42,8 @@ function buildDefaultCSP(nonce: string): string {
|
|
|
35
42
|
return [
|
|
36
43
|
`default-src 'self'`,
|
|
37
44
|
`script-src 'self' 'nonce-${nonce}' https://cdn.jsdelivr.net https://esm.sh`,
|
|
38
|
-
`style-src 'self' 'unsafe-inline'
|
|
45
|
+
`style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
46
|
+
`style-src-elem 'self' 'nonce-${nonce}' https://fonts.googleapis.com https://cdn.veryfront.com`,
|
|
39
47
|
`style-src-attr 'unsafe-inline'`,
|
|
40
48
|
`img-src 'self' data: https:`,
|
|
41
49
|
`font-src 'self' data: https://fonts.gstatic.com https://cdn.veryfront.com`,
|
|
@@ -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
|
+
}
|