remote-components 0.0.51 → 0.1.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/dist/{component-loader-1838f572.d.ts → component-loader-21865da3.d.ts} +142 -16
- package/dist/host-config-58cdccea.d.ts +87 -0
- package/dist/html/host.cjs +589 -377
- package/dist/html/host.cjs.map +1 -1
- package/dist/html/host.d.ts +2 -0
- package/dist/html/host.js +588 -377
- package/dist/html/host.js.map +1 -1
- package/dist/html/remote.cjs +65 -57
- package/dist/html/remote.cjs.map +1 -1
- package/dist/html/remote.js +65 -57
- package/dist/html/remote.js.map +1 -1
- package/dist/internal/next/host/app-router-client.cjs +21 -10
- package/dist/internal/next/host/app-router-client.cjs.map +1 -1
- package/dist/internal/next/host/app-router-client.d.ts +36 -14
- package/dist/internal/next/host/app-router-client.js +21 -10
- package/dist/internal/next/host/app-router-client.js.map +1 -1
- package/dist/internal/next/remote/render-server.cjs.map +1 -1
- package/dist/internal/next/remote/render-server.d.ts +13 -14
- package/dist/internal/next/remote/render-server.js.map +1 -1
- package/dist/internal/react/context.cjs +43 -0
- package/dist/internal/react/context.cjs.map +1 -0
- package/dist/internal/react/context.d.ts +20 -0
- package/dist/internal/react/context.js +18 -0
- package/dist/internal/react/context.js.map +1 -0
- package/dist/internal/react/hooks/use-resolve-client-url.cjs +39 -0
- package/dist/internal/react/hooks/use-resolve-client-url.cjs.map +1 -0
- package/dist/internal/react/hooks/use-resolve-client-url.d.ts +5 -0
- package/dist/internal/react/hooks/use-resolve-client-url.js +15 -0
- package/dist/internal/react/hooks/use-resolve-client-url.js.map +1 -0
- package/dist/internal/shared/client/apply-origin.cjs +10 -5
- package/dist/internal/shared/client/apply-origin.cjs.map +1 -1
- package/dist/internal/shared/client/apply-origin.d.ts +3 -1
- package/dist/internal/shared/client/apply-origin.js +10 -5
- package/dist/internal/shared/client/apply-origin.js.map +1 -1
- package/dist/internal/shared/client/default-resolve-client-url.cjs +32 -0
- package/dist/internal/shared/client/default-resolve-client-url.cjs.map +1 -0
- package/dist/internal/shared/client/default-resolve-client-url.d.ts +5 -0
- package/dist/internal/shared/client/default-resolve-client-url.js +10 -0
- package/dist/internal/shared/client/default-resolve-client-url.js.map +1 -0
- package/dist/internal/shared/client/protected-rc-fallback.cjs +11 -2
- package/dist/internal/shared/client/protected-rc-fallback.cjs.map +1 -1
- package/dist/internal/shared/client/protected-rc-fallback.d.ts +2 -1
- package/dist/internal/shared/client/protected-rc-fallback.js +9 -1
- package/dist/internal/shared/client/protected-rc-fallback.js.map +1 -1
- package/dist/internal/shared/client/proxy-through-host.cjs +65 -0
- package/dist/internal/shared/client/proxy-through-host.cjs.map +1 -0
- package/dist/internal/shared/client/proxy-through-host.d.ts +62 -0
- package/dist/internal/shared/client/proxy-through-host.js +40 -0
- package/dist/internal/shared/client/proxy-through-host.js.map +1 -0
- package/dist/internal/shared/client/remote-component.cjs +121 -137
- package/dist/internal/shared/client/remote-component.cjs.map +1 -1
- package/dist/internal/shared/client/remote-component.d.ts +7 -5
- package/dist/internal/shared/client/remote-component.js +120 -137
- package/dist/internal/shared/client/remote-component.js.map +1 -1
- package/dist/internal/shared/constants.cjs +3 -0
- package/dist/internal/shared/constants.cjs.map +1 -1
- package/dist/internal/shared/constants.d.ts +2 -1
- package/dist/internal/shared/constants.js +2 -0
- package/dist/internal/shared/constants.js.map +1 -1
- package/dist/internal/shared/contract/host-state.cjs +38 -0
- package/dist/internal/shared/contract/host-state.cjs.map +1 -0
- package/dist/internal/shared/contract/host-state.d.ts +53 -0
- package/dist/internal/shared/contract/host-state.js +14 -0
- package/dist/internal/shared/contract/host-state.js.map +1 -0
- package/dist/internal/shared/contract/resolve-name-from-src.cjs +40 -0
- package/dist/internal/shared/contract/resolve-name-from-src.cjs.map +1 -0
- package/dist/internal/shared/contract/resolve-name-from-src.d.ts +13 -0
- package/dist/internal/shared/contract/resolve-name-from-src.js +16 -0
- package/dist/internal/shared/contract/resolve-name-from-src.js.map +1 -0
- package/dist/internal/shared/error.cjs +70 -0
- package/dist/internal/shared/error.cjs.map +1 -1
- package/dist/internal/shared/error.d.ts +3 -1
- package/dist/internal/shared/error.js +71 -0
- package/dist/internal/shared/error.js.map +1 -1
- package/dist/internal/shared/ssr/dom-flight.d.ts +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.d.ts +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
- package/dist/internal/shared/ssr/fetch-with-hooks.cjs +7 -2
- package/dist/internal/shared/ssr/fetch-with-hooks.cjs.map +1 -1
- package/dist/internal/shared/ssr/fetch-with-hooks.d.ts +1 -1
- package/dist/internal/shared/ssr/fetch-with-hooks.js +7 -2
- package/dist/internal/shared/ssr/fetch-with-hooks.js.map +1 -1
- package/dist/internal/shared/utils/logger.cjs +26 -10
- package/dist/internal/shared/utils/logger.cjs.map +1 -1
- package/dist/internal/shared/utils/logger.d.ts +6 -1
- package/dist/internal/shared/utils/logger.js +24 -9
- package/dist/internal/shared/utils/logger.js.map +1 -1
- package/dist/next/config.cjs +2 -2
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +2 -2
- package/dist/next/config.js.map +1 -1
- package/dist/next/host/app-router-server.cjs.map +1 -1
- package/dist/next/host/app-router-server.d.ts +11 -41
- package/dist/next/host/app-router-server.js.map +1 -1
- package/dist/next/host/client/index.cjs +467 -298
- package/dist/next/host/client/index.cjs.map +1 -1
- package/dist/next/host/client/index.d.ts +3 -1
- package/dist/next/host/client/index.js +445 -277
- package/dist/next/host/client/index.js.map +1 -1
- package/dist/next/host/pages-router-client.cjs +15 -2
- package/dist/next/host/pages-router-client.cjs.map +1 -1
- package/dist/next/host/pages-router-client.d.ts +14 -26
- package/dist/next/host/pages-router-client.js +15 -2
- package/dist/next/host/pages-router-client.js.map +1 -1
- package/dist/next/host/pages-router-server.cjs +2 -0
- package/dist/next/host/pages-router-server.cjs.map +1 -1
- package/dist/next/host/pages-router-server.d.ts +17 -31
- package/dist/next/host/pages-router-server.js +2 -0
- package/dist/next/host/pages-router-server.js.map +1 -1
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.ts +13 -39
- package/dist/next/index.js.map +1 -1
- package/dist/next/proxy.cjs +33 -6
- package/dist/next/proxy.cjs.map +1 -1
- package/dist/next/proxy.js +33 -6
- package/dist/next/proxy.js.map +1 -1
- package/dist/next/remote/server.d.ts +4 -0
- package/dist/proxy-through-host-a676a522.d.ts +52 -0
- package/dist/react/index.cjs +486 -298
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +27 -40
- package/dist/react/index.js +463 -277
- package/dist/react/index.js.map +1 -1
- package/dist/shared/host/proxy.cjs +32 -6
- package/dist/shared/host/proxy.cjs.map +1 -1
- package/dist/shared/host/proxy.js +36 -7
- package/dist/shared/host/proxy.js.map +1 -1
- package/dist/{types-cbe44b51.d.ts → types-2b26a246.d.ts} +23 -6
- package/package.json +1 -1
- package/dist/internal/shared/client/fetch-with-protected-rc-fallback.cjs +0 -65
- package/dist/internal/shared/client/fetch-with-protected-rc-fallback.cjs.map +0 -1
- package/dist/internal/shared/client/fetch-with-protected-rc-fallback.d.ts +0 -13
- package/dist/internal/shared/client/fetch-with-protected-rc-fallback.js +0 -41
- package/dist/internal/shared/client/fetch-with-protected-rc-fallback.js.map +0 -1
|
@@ -34,6 +34,17 @@ async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
|
34
34
|
status: 400
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
+
let parsedTargetUrl;
|
|
38
|
+
try {
|
|
39
|
+
parsedTargetUrl = new URL(targetUrl);
|
|
40
|
+
} catch {
|
|
41
|
+
return new Response("Bad request: invalid URL", { status: 400 });
|
|
42
|
+
}
|
|
43
|
+
if (parsedTargetUrl.protocol !== "https:" && parsedTargetUrl.protocol !== "http:") {
|
|
44
|
+
return new Response("Bad request: only http/https URLs are supported", {
|
|
45
|
+
status: 400
|
|
46
|
+
});
|
|
47
|
+
}
|
|
37
48
|
const envPatterns = process.env.REMOTE_COMPONENTS_ALLOWED_PROXY_URLS?.split(
|
|
38
49
|
","
|
|
39
50
|
).map((p) => p.trim());
|
|
@@ -41,16 +52,19 @@ async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
|
41
52
|
const allowedPatterns = [...optionPatterns || [], ...envPatterns || []];
|
|
42
53
|
if (allowedPatterns.length === 0) {
|
|
43
54
|
return new Response(
|
|
44
|
-
`Forbidden: no allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS
|
|
55
|
+
`Forbidden: no allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS configured. See: ${import_constants.CORS_DOCS_URL}`,
|
|
45
56
|
{
|
|
46
57
|
status: 403
|
|
47
58
|
}
|
|
48
59
|
);
|
|
49
60
|
}
|
|
61
|
+
const matchTarget = parsedTargetUrl.origin + parsedTargetUrl.pathname;
|
|
50
62
|
const isUrlAllowed = allowedPatterns.some((pattern) => {
|
|
51
63
|
try {
|
|
52
|
-
const
|
|
53
|
-
|
|
64
|
+
const anchored = pattern.startsWith("^") ? pattern : `^${pattern}`;
|
|
65
|
+
const bounded = anchored.endsWith("$") ? anchored : `${anchored}(/|$)`;
|
|
66
|
+
const regex = new RegExp(bounded);
|
|
67
|
+
return regex.test(matchTarget);
|
|
54
68
|
} catch (error) {
|
|
55
69
|
console.error(
|
|
56
70
|
`Invalid regex pattern in allowedProxyUrls: ${pattern}`,
|
|
@@ -61,18 +75,30 @@ async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
|
61
75
|
});
|
|
62
76
|
if (!isUrlAllowed) {
|
|
63
77
|
return new Response(
|
|
64
|
-
`Forbidden:
|
|
78
|
+
`Forbidden: origin "${parsedTargetUrl.origin}" does not match any allowedProxyUrls. Add a matching pattern to REMOTE_COMPONENTS_ALLOWED_PROXY_URLS or the allowedProxyUrls option. See: ${import_constants.CORS_DOCS_URL}`,
|
|
65
79
|
{
|
|
66
80
|
status: 403
|
|
67
81
|
}
|
|
68
82
|
);
|
|
69
83
|
}
|
|
70
84
|
const response = await fetch(targetUrl, { headers: (0, import_fetch_headers.remoteFetchHeaders)() });
|
|
71
|
-
const
|
|
85
|
+
const SAFE_HEADERS = [
|
|
86
|
+
"content-type",
|
|
87
|
+
"cache-control",
|
|
88
|
+
"etag",
|
|
89
|
+
"last-modified"
|
|
90
|
+
];
|
|
91
|
+
const headers = new Headers();
|
|
92
|
+
for (const name of SAFE_HEADERS) {
|
|
93
|
+
const value = response.headers.get(name);
|
|
94
|
+
if (value) {
|
|
95
|
+
headers.set(name, value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
72
98
|
return new Response(response.body, {
|
|
73
99
|
status: response.status,
|
|
74
100
|
statusText: response.statusText,
|
|
75
|
-
headers
|
|
101
|
+
headers
|
|
76
102
|
});
|
|
77
103
|
}
|
|
78
104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/shared/host/proxy.ts"],"sourcesContent":["/**\n * Proxy utilities for host applications that consume remote components.\n *\n * Hosts do NOT handle CORS - that's the remote's responsibility.\n * Hosts only handle protected fetch proxying.\n */\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/shared/host/proxy.ts"],"sourcesContent":["/**\n * Proxy utilities for host applications that consume remote components.\n *\n * Hosts do NOT handle CORS - that's the remote's responsibility.\n * Hosts only handle protected fetch proxying.\n */\n\nimport {\n CORS_DOCS_URL,\n RC_PROTECTED_REMOTE_FETCH_PATHNAME,\n} from '#internal/shared/constants';\nimport { remoteFetchHeaders } from '#internal/shared/ssr/fetch-headers';\n\nexport interface HostProxyOptions {\n /**\n * List of allowed URL patterns (as regex strings) that can be proxied.\n * These patterns are combined with REMOTE_COMPONENTS_ALLOWED_PROXY_URLS env var if both are set.\n * If neither is set, all URLs are blocked.\n */\n allowedProxyUrls?: string[];\n}\n\n/**\n * Handles protected remote component fetch requests by proxying them with\n * authentication headers. This is needed for accessing Vercel-protected remote\n * component deployments from client-side code.\n *\n * @param requestUrl - The full request URL\n * @param options - Host proxy configuration options\n * @returns Response object if this is a protected fetch request, or null if not\n */\nexport async function handleProtectedRemoteFetchRequest(\n requestUrl: string,\n options?: HostProxyOptions,\n): Promise<Response | null> {\n const url = new URL(requestUrl, 'https://fallback.com');\n\n if (url.pathname !== RC_PROTECTED_REMOTE_FETCH_PATHNAME) {\n return null;\n }\n\n const targetUrl = url.searchParams.get('url');\n if (!targetUrl) {\n return new Response('Bad request, missing url query param', {\n status: 400,\n });\n }\n\n // Only allow http/https URLs to prevent SSRF via file://, data:, etc.\n let parsedTargetUrl: URL;\n try {\n parsedTargetUrl = new URL(targetUrl);\n } catch {\n return new Response('Bad request: invalid URL', { status: 400 });\n }\n\n if (\n parsedTargetUrl.protocol !== 'https:' &&\n parsedTargetUrl.protocol !== 'http:'\n ) {\n return new Response('Bad request: only http/https URLs are supported', {\n status: 400,\n });\n }\n\n const envPatterns = process.env.REMOTE_COMPONENTS_ALLOWED_PROXY_URLS?.split(\n ',',\n ).map((p) => p.trim());\n const optionPatterns = options?.allowedProxyUrls;\n\n // Combine both sources if both are specified\n const allowedPatterns = [...(optionPatterns || []), ...(envPatterns || [])];\n\n if (allowedPatterns.length === 0) {\n return new Response(\n `Forbidden: no allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS configured. ` +\n `See: ${CORS_DOCS_URL}`,\n {\n status: 403,\n },\n );\n }\n\n // Validate the target URL against allowed patterns to prevent SSRF.\n // matchTarget is origin + pathname (no query string or fragment).\n const matchTarget = parsedTargetUrl.origin + parsedTargetUrl.pathname;\n const isUrlAllowed = allowedPatterns.some((pattern) => {\n try {\n const anchored = pattern.startsWith('^') ? pattern : `^${pattern}`;\n const bounded = anchored.endsWith('$') ? anchored : `${anchored}(/|$)`;\n const regex = new RegExp(bounded);\n return regex.test(matchTarget);\n } catch (error) {\n console.error(\n `Invalid regex pattern in allowedProxyUrls: ${pattern}`,\n error,\n );\n return false;\n }\n });\n\n if (!isUrlAllowed) {\n return new Response(\n `Forbidden: origin \"${parsedTargetUrl.origin}\" does not match any allowedProxyUrls. ` +\n `Add a matching pattern to REMOTE_COMPONENTS_ALLOWED_PROXY_URLS or the allowedProxyUrls option. ` +\n `See: ${CORS_DOCS_URL}`,\n {\n status: 403,\n },\n );\n }\n\n // Fetch the remote resource\n const response = await fetch(targetUrl, { headers: remoteFetchHeaders() });\n\n // Only forward safe headers — no set-cookie, CORS, or encoding headers.\n // content-length is excluded because fetch() auto-decompresses the upstream\n // response, making the original content-length incorrect for the decoded body.\n const SAFE_HEADERS = [\n 'content-type',\n 'cache-control',\n 'etag',\n 'last-modified',\n ] as const;\n const headers = new Headers();\n for (const name of SAFE_HEADERS) {\n const value = response.headers.get(name);\n if (value) {\n headers.set(name, value);\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,uBAGO;AACP,2BAAmC;AAoBnC,eAAsB,kCACpB,YACA,SAC0B;AAC1B,QAAM,MAAM,IAAI,IAAI,YAAY,sBAAsB;AAEtD,MAAI,IAAI,aAAa,qDAAoC;AACvD,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,IAAI,aAAa,IAAI,KAAK;AAC5C,MAAI,CAAC,WAAW;AACd,WAAO,IAAI,SAAS,wCAAwC;AAAA,MAC1D,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI;AACF,sBAAkB,IAAI,IAAI,SAAS;AAAA,EACrC,QAAE;AACA,WAAO,IAAI,SAAS,4BAA4B,EAAE,QAAQ,IAAI,CAAC;AAAA,EACjE;AAEA,MACE,gBAAgB,aAAa,YAC7B,gBAAgB,aAAa,SAC7B;AACA,WAAO,IAAI,SAAS,mDAAmD;AAAA,MACrE,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,QAAQ,IAAI,sCAAsC;AAAA,IACpE;AAAA,EACF,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACrB,QAAM,iBAAiB,SAAS;AAGhC,QAAM,kBAAkB,CAAC,GAAI,kBAAkB,CAAC,GAAI,GAAI,eAAe,CAAC,CAAE;AAE1E,MAAI,gBAAgB,WAAW,GAAG;AAChC,WAAO,IAAI;AAAA,MACT,2FACU;AAAA,MACV;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAIA,QAAM,cAAc,gBAAgB,SAAS,gBAAgB;AAC7D,QAAM,eAAe,gBAAgB,KAAK,CAAC,YAAY;AACrD,QAAI;AACF,YAAM,WAAW,QAAQ,WAAW,GAAG,IAAI,UAAU,IAAI;AACzD,YAAM,UAAU,SAAS,SAAS,GAAG,IAAI,WAAW,GAAG;AACvD,YAAM,QAAQ,IAAI,OAAO,OAAO;AAChC,aAAO,MAAM,KAAK,WAAW;AAAA,IAC/B,SAAS,OAAP;AACA,cAAQ;AAAA,QACN,8CAA8C;AAAA,QAC9C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,MAAI,CAAC,cAAc;AACjB,WAAO,IAAI;AAAA,MACT,sBAAsB,gBAAgB,oJAE5B;AAAA,MACV;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,MAAM,WAAW,EAAE,aAAS,yCAAmB,EAAE,CAAC;AAKzE,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,IAAI,QAAQ;AAC5B,aAAW,QAAQ,cAAc;AAC/B,UAAM,QAAQ,SAAS,QAAQ,IAAI,IAAI;AACvC,QAAI,OAAO;AACT,cAAQ,IAAI,MAAM,KAAK;AAAA,IACzB;AAAA,EACF;AAEA,SAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CORS_DOCS_URL,
|
|
3
|
+
RC_PROTECTED_REMOTE_FETCH_PATHNAME
|
|
4
|
+
} from "#internal/shared/constants";
|
|
2
5
|
import { remoteFetchHeaders } from "#internal/shared/ssr/fetch-headers";
|
|
3
6
|
async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
4
7
|
const url = new URL(requestUrl, "https://fallback.com");
|
|
@@ -11,6 +14,17 @@ async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
|
11
14
|
status: 400
|
|
12
15
|
});
|
|
13
16
|
}
|
|
17
|
+
let parsedTargetUrl;
|
|
18
|
+
try {
|
|
19
|
+
parsedTargetUrl = new URL(targetUrl);
|
|
20
|
+
} catch {
|
|
21
|
+
return new Response("Bad request: invalid URL", { status: 400 });
|
|
22
|
+
}
|
|
23
|
+
if (parsedTargetUrl.protocol !== "https:" && parsedTargetUrl.protocol !== "http:") {
|
|
24
|
+
return new Response("Bad request: only http/https URLs are supported", {
|
|
25
|
+
status: 400
|
|
26
|
+
});
|
|
27
|
+
}
|
|
14
28
|
const envPatterns = process.env.REMOTE_COMPONENTS_ALLOWED_PROXY_URLS?.split(
|
|
15
29
|
","
|
|
16
30
|
).map((p) => p.trim());
|
|
@@ -18,16 +32,19 @@ async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
|
18
32
|
const allowedPatterns = [...optionPatterns || [], ...envPatterns || []];
|
|
19
33
|
if (allowedPatterns.length === 0) {
|
|
20
34
|
return new Response(
|
|
21
|
-
`Forbidden: no allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS
|
|
35
|
+
`Forbidden: no allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS configured. See: ${CORS_DOCS_URL}`,
|
|
22
36
|
{
|
|
23
37
|
status: 403
|
|
24
38
|
}
|
|
25
39
|
);
|
|
26
40
|
}
|
|
41
|
+
const matchTarget = parsedTargetUrl.origin + parsedTargetUrl.pathname;
|
|
27
42
|
const isUrlAllowed = allowedPatterns.some((pattern) => {
|
|
28
43
|
try {
|
|
29
|
-
const
|
|
30
|
-
|
|
44
|
+
const anchored = pattern.startsWith("^") ? pattern : `^${pattern}`;
|
|
45
|
+
const bounded = anchored.endsWith("$") ? anchored : `${anchored}(/|$)`;
|
|
46
|
+
const regex = new RegExp(bounded);
|
|
47
|
+
return regex.test(matchTarget);
|
|
31
48
|
} catch (error) {
|
|
32
49
|
console.error(
|
|
33
50
|
`Invalid regex pattern in allowedProxyUrls: ${pattern}`,
|
|
@@ -38,18 +55,30 @@ async function handleProtectedRemoteFetchRequest(requestUrl, options) {
|
|
|
38
55
|
});
|
|
39
56
|
if (!isUrlAllowed) {
|
|
40
57
|
return new Response(
|
|
41
|
-
`Forbidden:
|
|
58
|
+
`Forbidden: origin "${parsedTargetUrl.origin}" does not match any allowedProxyUrls. Add a matching pattern to REMOTE_COMPONENTS_ALLOWED_PROXY_URLS or the allowedProxyUrls option. See: ${CORS_DOCS_URL}`,
|
|
42
59
|
{
|
|
43
60
|
status: 403
|
|
44
61
|
}
|
|
45
62
|
);
|
|
46
63
|
}
|
|
47
64
|
const response = await fetch(targetUrl, { headers: remoteFetchHeaders() });
|
|
48
|
-
const
|
|
65
|
+
const SAFE_HEADERS = [
|
|
66
|
+
"content-type",
|
|
67
|
+
"cache-control",
|
|
68
|
+
"etag",
|
|
69
|
+
"last-modified"
|
|
70
|
+
];
|
|
71
|
+
const headers = new Headers();
|
|
72
|
+
for (const name of SAFE_HEADERS) {
|
|
73
|
+
const value = response.headers.get(name);
|
|
74
|
+
if (value) {
|
|
75
|
+
headers.set(name, value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
49
78
|
return new Response(response.body, {
|
|
50
79
|
status: response.status,
|
|
51
80
|
statusText: response.statusText,
|
|
52
|
-
headers
|
|
81
|
+
headers
|
|
53
82
|
});
|
|
54
83
|
}
|
|
55
84
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/shared/host/proxy.ts"],"sourcesContent":["/**\n * Proxy utilities for host applications that consume remote components.\n *\n * Hosts do NOT handle CORS - that's the remote's responsibility.\n * Hosts only handle protected fetch proxying.\n */\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/shared/host/proxy.ts"],"sourcesContent":["/**\n * Proxy utilities for host applications that consume remote components.\n *\n * Hosts do NOT handle CORS - that's the remote's responsibility.\n * Hosts only handle protected fetch proxying.\n */\n\nimport {\n CORS_DOCS_URL,\n RC_PROTECTED_REMOTE_FETCH_PATHNAME,\n} from '#internal/shared/constants';\nimport { remoteFetchHeaders } from '#internal/shared/ssr/fetch-headers';\n\nexport interface HostProxyOptions {\n /**\n * List of allowed URL patterns (as regex strings) that can be proxied.\n * These patterns are combined with REMOTE_COMPONENTS_ALLOWED_PROXY_URLS env var if both are set.\n * If neither is set, all URLs are blocked.\n */\n allowedProxyUrls?: string[];\n}\n\n/**\n * Handles protected remote component fetch requests by proxying them with\n * authentication headers. This is needed for accessing Vercel-protected remote\n * component deployments from client-side code.\n *\n * @param requestUrl - The full request URL\n * @param options - Host proxy configuration options\n * @returns Response object if this is a protected fetch request, or null if not\n */\nexport async function handleProtectedRemoteFetchRequest(\n requestUrl: string,\n options?: HostProxyOptions,\n): Promise<Response | null> {\n const url = new URL(requestUrl, 'https://fallback.com');\n\n if (url.pathname !== RC_PROTECTED_REMOTE_FETCH_PATHNAME) {\n return null;\n }\n\n const targetUrl = url.searchParams.get('url');\n if (!targetUrl) {\n return new Response('Bad request, missing url query param', {\n status: 400,\n });\n }\n\n // Only allow http/https URLs to prevent SSRF via file://, data:, etc.\n let parsedTargetUrl: URL;\n try {\n parsedTargetUrl = new URL(targetUrl);\n } catch {\n return new Response('Bad request: invalid URL', { status: 400 });\n }\n\n if (\n parsedTargetUrl.protocol !== 'https:' &&\n parsedTargetUrl.protocol !== 'http:'\n ) {\n return new Response('Bad request: only http/https URLs are supported', {\n status: 400,\n });\n }\n\n const envPatterns = process.env.REMOTE_COMPONENTS_ALLOWED_PROXY_URLS?.split(\n ',',\n ).map((p) => p.trim());\n const optionPatterns = options?.allowedProxyUrls;\n\n // Combine both sources if both are specified\n const allowedPatterns = [...(optionPatterns || []), ...(envPatterns || [])];\n\n if (allowedPatterns.length === 0) {\n return new Response(\n `Forbidden: no allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS configured. ` +\n `See: ${CORS_DOCS_URL}`,\n {\n status: 403,\n },\n );\n }\n\n // Validate the target URL against allowed patterns to prevent SSRF.\n // matchTarget is origin + pathname (no query string or fragment).\n const matchTarget = parsedTargetUrl.origin + parsedTargetUrl.pathname;\n const isUrlAllowed = allowedPatterns.some((pattern) => {\n try {\n const anchored = pattern.startsWith('^') ? pattern : `^${pattern}`;\n const bounded = anchored.endsWith('$') ? anchored : `${anchored}(/|$)`;\n const regex = new RegExp(bounded);\n return regex.test(matchTarget);\n } catch (error) {\n console.error(\n `Invalid regex pattern in allowedProxyUrls: ${pattern}`,\n error,\n );\n return false;\n }\n });\n\n if (!isUrlAllowed) {\n return new Response(\n `Forbidden: origin \"${parsedTargetUrl.origin}\" does not match any allowedProxyUrls. ` +\n `Add a matching pattern to REMOTE_COMPONENTS_ALLOWED_PROXY_URLS or the allowedProxyUrls option. ` +\n `See: ${CORS_DOCS_URL}`,\n {\n status: 403,\n },\n );\n }\n\n // Fetch the remote resource\n const response = await fetch(targetUrl, { headers: remoteFetchHeaders() });\n\n // Only forward safe headers — no set-cookie, CORS, or encoding headers.\n // content-length is excluded because fetch() auto-decompresses the upstream\n // response, making the original content-length incorrect for the decoded body.\n const SAFE_HEADERS = [\n 'content-type',\n 'cache-control',\n 'etag',\n 'last-modified',\n ] as const;\n const headers = new Headers();\n for (const name of SAFE_HEADERS) {\n const value = response.headers.get(name);\n if (value) {\n headers.set(name, value);\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":"AAOA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AAoBnC,eAAsB,kCACpB,YACA,SAC0B;AAC1B,QAAM,MAAM,IAAI,IAAI,YAAY,sBAAsB;AAEtD,MAAI,IAAI,aAAa,oCAAoC;AACvD,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,IAAI,aAAa,IAAI,KAAK;AAC5C,MAAI,CAAC,WAAW;AACd,WAAO,IAAI,SAAS,wCAAwC;AAAA,MAC1D,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI;AACF,sBAAkB,IAAI,IAAI,SAAS;AAAA,EACrC,QAAE;AACA,WAAO,IAAI,SAAS,4BAA4B,EAAE,QAAQ,IAAI,CAAC;AAAA,EACjE;AAEA,MACE,gBAAgB,aAAa,YAC7B,gBAAgB,aAAa,SAC7B;AACA,WAAO,IAAI,SAAS,mDAAmD;AAAA,MACrE,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,QAAQ,IAAI,sCAAsC;AAAA,IACpE;AAAA,EACF,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACrB,QAAM,iBAAiB,SAAS;AAGhC,QAAM,kBAAkB,CAAC,GAAI,kBAAkB,CAAC,GAAI,GAAI,eAAe,CAAC,CAAE;AAE1E,MAAI,gBAAgB,WAAW,GAAG;AAChC,WAAO,IAAI;AAAA,MACT,2FACU;AAAA,MACV;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAIA,QAAM,cAAc,gBAAgB,SAAS,gBAAgB;AAC7D,QAAM,eAAe,gBAAgB,KAAK,CAAC,YAAY;AACrD,QAAI;AACF,YAAM,WAAW,QAAQ,WAAW,GAAG,IAAI,UAAU,IAAI;AACzD,YAAM,UAAU,SAAS,SAAS,GAAG,IAAI,WAAW,GAAG;AACvD,YAAM,QAAQ,IAAI,OAAO,OAAO;AAChC,aAAO,MAAM,KAAK,WAAW;AAAA,IAC/B,SAAS,OAAP;AACA,cAAQ;AAAA,QACN,8CAA8C;AAAA,QAC9C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,MAAI,CAAC,cAAc;AACjB,WAAO,IAAI;AAAA,MACT,sBAAsB,gBAAgB,oJAE5B;AAAA,MACV;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,MAAM,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAC;AAKzE,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,IAAI,QAAQ;AAC5B,aAAW,QAAQ,cAAc;AAC/B,UAAM,QAAQ,SAAS,QAAQ,IAAI,IAAI;AACvC,QAAI,OAAO;AACT,cAAQ,IAAI,MAAM,KAAK;AAAA,IACzB;AAAA,EACF;AAEA,SAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -35,6 +35,26 @@ declare function visit(node: (Node | ChildNode) & {
|
|
|
35
35
|
}>;
|
|
36
36
|
}, context?: Context): RSC | RSC[] | string | null;
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Serialized descriptor for a `<script>` element extracted from a remote
|
|
40
|
+
* component response. Used in both SSR fetch results and client-side props.
|
|
41
|
+
*/
|
|
42
|
+
interface ScriptDescriptor {
|
|
43
|
+
/** The script `src` URL. Empty string for inline scripts. */
|
|
44
|
+
src: string;
|
|
45
|
+
/** Inline script content (only present for scripts without a `src`). */
|
|
46
|
+
textContent?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Serialized descriptor for a `<link>` element extracted from a remote
|
|
50
|
+
* component response. Captures all HTML attributes as key-value pairs.
|
|
51
|
+
*
|
|
52
|
+
* Note: the client-side parser works with live `HTMLLinkElement` objects.
|
|
53
|
+
* This descriptor represents the serialized form passed between SSR and
|
|
54
|
+
* client hydration.
|
|
55
|
+
*/
|
|
56
|
+
type LinkDescriptor = Record<string, string | boolean>;
|
|
57
|
+
|
|
38
58
|
interface RemoteComponentMetadata {
|
|
39
59
|
bundle: string;
|
|
40
60
|
route: string;
|
|
@@ -175,11 +195,8 @@ interface FetchRemoteComponentResponse {
|
|
|
175
195
|
serverUrl: URL;
|
|
176
196
|
metadata: RemoteComponentMetadata;
|
|
177
197
|
rsc: RSC | RSC[] | string | null;
|
|
178
|
-
scripts:
|
|
179
|
-
|
|
180
|
-
textContent?: string;
|
|
181
|
-
}[];
|
|
182
|
-
links: Record<string, string | boolean>[];
|
|
198
|
+
scripts: ScriptDescriptor[];
|
|
199
|
+
links: LinkDescriptor[];
|
|
183
200
|
hydrationData: string[];
|
|
184
201
|
nextData: NextData | undefined;
|
|
185
202
|
component: React.ReactNode | undefined;
|
|
@@ -187,4 +204,4 @@ interface FetchRemoteComponentResponse {
|
|
|
187
204
|
remoteShared: Record<string, string>;
|
|
188
205
|
}
|
|
189
206
|
|
|
190
|
-
export { Context as C, FetchRemoteComponentResponse as F, OnRequestHook as O, RemoteComponentMetadata as R, OnResponseHook as a, RSC as b, visit as v };
|
|
207
|
+
export { Context as C, FetchRemoteComponentResponse as F, LinkDescriptor as L, OnRequestHook as O, RemoteComponentMetadata as R, ScriptDescriptor as S, OnResponseHook as a, RSC as b, visit as v };
|
package/package.json
CHANGED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var fetch_with_protected_rc_fallback_exports = {};
|
|
20
|
-
__export(fetch_with_protected_rc_fallback_exports, {
|
|
21
|
-
fetchWithProtectedRcFallback: () => fetchWithProtectedRcFallback
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(fetch_with_protected_rc_fallback_exports);
|
|
24
|
-
var import_protected_rc_fallback = require("#internal/shared/client/protected-rc-fallback");
|
|
25
|
-
var import_abort = require("#internal/shared/utils/abort");
|
|
26
|
-
var import_logger = require("#internal/shared/utils/logger");
|
|
27
|
-
async function fetchWithProtectedRcFallback(url, init) {
|
|
28
|
-
try {
|
|
29
|
-
const res = await fetch(url, init);
|
|
30
|
-
return res;
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if ((0, import_abort.isAbortError)(error)) {
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
const parsedUrl = new URL(url);
|
|
36
|
-
if (typeof document === "object" && typeof document.location === "object" && document.location.origin !== parsedUrl.origin) {
|
|
37
|
-
(0, import_logger.logWarn)(
|
|
38
|
-
"FetchRemoteComponent",
|
|
39
|
-
"Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy."
|
|
40
|
-
);
|
|
41
|
-
const proxiedRes = await fetch(
|
|
42
|
-
(0, import_protected_rc_fallback.generateProtectedRcFallbackSrc)(parsedUrl.href),
|
|
43
|
-
init?.signal ? { signal: init.signal } : void 0
|
|
44
|
-
);
|
|
45
|
-
if (proxiedRes.status === 200) {
|
|
46
|
-
(0, import_logger.logInfo)(
|
|
47
|
-
"FetchRemoteComponent",
|
|
48
|
-
`Successfully fetched ${parsedUrl.href} with fallback withRemoteComponentsHost proxy`
|
|
49
|
-
);
|
|
50
|
-
return proxiedRes;
|
|
51
|
-
} else {
|
|
52
|
-
(0, import_logger.logError)(
|
|
53
|
-
"FetchRemoteComponent",
|
|
54
|
-
`Could not proxy remote: [response status ${proxiedRes.status}] ${await proxiedRes.text()}`
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
62
|
-
0 && (module.exports = {
|
|
63
|
-
fetchWithProtectedRcFallback
|
|
64
|
-
});
|
|
65
|
-
//# sourceMappingURL=fetch-with-protected-rc-fallback.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/shared/client/fetch-with-protected-rc-fallback.ts"],"sourcesContent":["import { generateProtectedRcFallbackSrc } from '#internal/shared/client/protected-rc-fallback';\nimport { isAbortError } from '#internal/shared/utils/abort';\nimport { logError, logInfo, logWarn } from '#internal/shared/utils/logger';\n\n/**\n * When a vercel host preview fetches a vercel protected remote preview on the\n * client, the request will reject as it's not possible to authenticate for the\n * protected deployment in a client side fetch - cookies cannot be shared across\n * domains. To enable previews, this request is proxied via the host where the\n * process.env.VERCEL_AUTOMATION_BYPASS_SECRET will be added.\n *\n * @param url - The URL to fetch\n * @param init - Fetch init options (should include signal for abort support)\n */\nexport async function fetchWithProtectedRcFallback(\n url: URL | string,\n init?: RequestInit,\n): Promise<Response> {\n try {\n const res = await fetch(url, init);\n return res;\n } catch (error) {\n // Re-throw AbortError immediately - don't try fallback for cancelled requests\n if (isAbortError(error)) {\n throw error;\n }\n\n const parsedUrl = new URL(url);\n if (\n typeof document === 'object' &&\n typeof document.location === 'object' &&\n document.location.origin !== parsedUrl.origin\n ) {\n logWarn(\n 'FetchRemoteComponent',\n 'Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy.',\n );\n // Pass signal to proxy fetch as well so it can be cancelled\n const proxiedRes = await fetch(\n generateProtectedRcFallbackSrc(parsedUrl.href),\n init?.signal ? { signal: init.signal } : undefined,\n );\n if (proxiedRes.status === 200) {\n logInfo(\n 'FetchRemoteComponent',\n `Successfully fetched ${parsedUrl.href} with fallback withRemoteComponentsHost proxy`,\n );\n return proxiedRes;\n } else {\n logError(\n 'FetchRemoteComponent',\n `Could not proxy remote: [response status ${\n proxiedRes.status\n }] ${await proxiedRes.text()}`,\n );\n }\n }\n\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAA+C;AAC/C,mBAA6B;AAC7B,oBAA2C;AAY3C,eAAsB,6BACpB,KACA,MACmB;AACnB,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI;AACjC,WAAO;AAAA,EACT,SAAS,OAAP;AAEA,YAAI,2BAAa,KAAK,GAAG;AACvB,YAAM;AAAA,IACR;AAEA,UAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,QACE,OAAO,aAAa,YACpB,OAAO,SAAS,aAAa,YAC7B,SAAS,SAAS,WAAW,UAAU,QACvC;AACA;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAEA,YAAM,aAAa,MAAM;AAAA,YACvB,6DAA+B,UAAU,IAAI;AAAA,QAC7C,MAAM,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI;AAAA,MAC3C;AACA,UAAI,WAAW,WAAW,KAAK;AAC7B;AAAA,UACE;AAAA,UACA,wBAAwB,UAAU;AAAA,QACpC;AACA,eAAO;AAAA,MACT,OAAO;AACL;AAAA,UACE;AAAA,UACA,4CACE,WAAW,WACR,MAAM,WAAW,KAAK;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* When a vercel host preview fetches a vercel protected remote preview on the
|
|
3
|
-
* client, the request will reject as it's not possible to authenticate for the
|
|
4
|
-
* protected deployment in a client side fetch - cookies cannot be shared across
|
|
5
|
-
* domains. To enable previews, this request is proxied via the host where the
|
|
6
|
-
* process.env.VERCEL_AUTOMATION_BYPASS_SECRET will be added.
|
|
7
|
-
*
|
|
8
|
-
* @param url - The URL to fetch
|
|
9
|
-
* @param init - Fetch init options (should include signal for abort support)
|
|
10
|
-
*/
|
|
11
|
-
declare function fetchWithProtectedRcFallback(url: URL | string, init?: RequestInit): Promise<Response>;
|
|
12
|
-
|
|
13
|
-
export { fetchWithProtectedRcFallback };
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { generateProtectedRcFallbackSrc } from "#internal/shared/client/protected-rc-fallback";
|
|
2
|
-
import { isAbortError } from "#internal/shared/utils/abort";
|
|
3
|
-
import { logError, logInfo, logWarn } from "#internal/shared/utils/logger";
|
|
4
|
-
async function fetchWithProtectedRcFallback(url, init) {
|
|
5
|
-
try {
|
|
6
|
-
const res = await fetch(url, init);
|
|
7
|
-
return res;
|
|
8
|
-
} catch (error) {
|
|
9
|
-
if (isAbortError(error)) {
|
|
10
|
-
throw error;
|
|
11
|
-
}
|
|
12
|
-
const parsedUrl = new URL(url);
|
|
13
|
-
if (typeof document === "object" && typeof document.location === "object" && document.location.origin !== parsedUrl.origin) {
|
|
14
|
-
logWarn(
|
|
15
|
-
"FetchRemoteComponent",
|
|
16
|
-
"Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy."
|
|
17
|
-
);
|
|
18
|
-
const proxiedRes = await fetch(
|
|
19
|
-
generateProtectedRcFallbackSrc(parsedUrl.href),
|
|
20
|
-
init?.signal ? { signal: init.signal } : void 0
|
|
21
|
-
);
|
|
22
|
-
if (proxiedRes.status === 200) {
|
|
23
|
-
logInfo(
|
|
24
|
-
"FetchRemoteComponent",
|
|
25
|
-
`Successfully fetched ${parsedUrl.href} with fallback withRemoteComponentsHost proxy`
|
|
26
|
-
);
|
|
27
|
-
return proxiedRes;
|
|
28
|
-
} else {
|
|
29
|
-
logError(
|
|
30
|
-
"FetchRemoteComponent",
|
|
31
|
-
`Could not proxy remote: [response status ${proxiedRes.status}] ${await proxiedRes.text()}`
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
throw error;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
export {
|
|
39
|
-
fetchWithProtectedRcFallback
|
|
40
|
-
};
|
|
41
|
-
//# sourceMappingURL=fetch-with-protected-rc-fallback.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/shared/client/fetch-with-protected-rc-fallback.ts"],"sourcesContent":["import { generateProtectedRcFallbackSrc } from '#internal/shared/client/protected-rc-fallback';\nimport { isAbortError } from '#internal/shared/utils/abort';\nimport { logError, logInfo, logWarn } from '#internal/shared/utils/logger';\n\n/**\n * When a vercel host preview fetches a vercel protected remote preview on the\n * client, the request will reject as it's not possible to authenticate for the\n * protected deployment in a client side fetch - cookies cannot be shared across\n * domains. To enable previews, this request is proxied via the host where the\n * process.env.VERCEL_AUTOMATION_BYPASS_SECRET will be added.\n *\n * @param url - The URL to fetch\n * @param init - Fetch init options (should include signal for abort support)\n */\nexport async function fetchWithProtectedRcFallback(\n url: URL | string,\n init?: RequestInit,\n): Promise<Response> {\n try {\n const res = await fetch(url, init);\n return res;\n } catch (error) {\n // Re-throw AbortError immediately - don't try fallback for cancelled requests\n if (isAbortError(error)) {\n throw error;\n }\n\n const parsedUrl = new URL(url);\n if (\n typeof document === 'object' &&\n typeof document.location === 'object' &&\n document.location.origin !== parsedUrl.origin\n ) {\n logWarn(\n 'FetchRemoteComponent',\n 'Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy.',\n );\n // Pass signal to proxy fetch as well so it can be cancelled\n const proxiedRes = await fetch(\n generateProtectedRcFallbackSrc(parsedUrl.href),\n init?.signal ? { signal: init.signal } : undefined,\n );\n if (proxiedRes.status === 200) {\n logInfo(\n 'FetchRemoteComponent',\n `Successfully fetched ${parsedUrl.href} with fallback withRemoteComponentsHost proxy`,\n );\n return proxiedRes;\n } else {\n logError(\n 'FetchRemoteComponent',\n `Could not proxy remote: [response status ${\n proxiedRes.status\n }] ${await proxiedRes.text()}`,\n );\n }\n }\n\n throw error;\n }\n}\n"],"mappings":"AAAA,SAAS,sCAAsC;AAC/C,SAAS,oBAAoB;AAC7B,SAAS,UAAU,SAAS,eAAe;AAY3C,eAAsB,6BACpB,KACA,MACmB;AACnB,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,KAAK,IAAI;AACjC,WAAO;AAAA,EACT,SAAS,OAAP;AAEA,QAAI,aAAa,KAAK,GAAG;AACvB,YAAM;AAAA,IACR;AAEA,UAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,QACE,OAAO,aAAa,YACpB,OAAO,SAAS,aAAa,YAC7B,SAAS,SAAS,WAAW,UAAU,QACvC;AACA;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAEA,YAAM,aAAa,MAAM;AAAA,QACvB,+BAA+B,UAAU,IAAI;AAAA,QAC7C,MAAM,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI;AAAA,MAC3C;AACA,UAAI,WAAW,WAAW,KAAK;AAC7B;AAAA,UACE;AAAA,UACA,wBAAwB,UAAU;AAAA,QACpC;AACA,eAAO;AAAA,MACT,OAAO;AACL;AAAA,UACE;AAAA,UACA,4CACE,WAAW,WACR,MAAM,WAAW,KAAK;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,UAAM;AAAA,EACR;AACF;","names":[]}
|