remote-components 0.0.51 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/{component-loader-1838f572.d.ts → component-loader-76eb1b8b.d.ts} +3 -1
  2. package/dist/html/host.cjs +297 -217
  3. package/dist/html/host.cjs.map +1 -1
  4. package/dist/html/host.d.ts +2 -0
  5. package/dist/html/host.js +296 -217
  6. package/dist/html/host.js.map +1 -1
  7. package/dist/html/remote.cjs +65 -57
  8. package/dist/html/remote.cjs.map +1 -1
  9. package/dist/html/remote.js +65 -57
  10. package/dist/html/remote.js.map +1 -1
  11. package/dist/internal/next/host/app-router-client.cjs +12 -3
  12. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  13. package/dist/internal/next/host/app-router-client.d.ts +11 -2
  14. package/dist/internal/next/host/app-router-client.js +12 -3
  15. package/dist/internal/next/host/app-router-client.js.map +1 -1
  16. package/dist/internal/react/context.cjs +43 -0
  17. package/dist/internal/react/context.cjs.map +1 -0
  18. package/dist/internal/react/context.d.ts +20 -0
  19. package/dist/internal/react/context.js +18 -0
  20. package/dist/internal/react/context.js.map +1 -0
  21. package/dist/internal/react/hooks/use-resolve-client-url.cjs +39 -0
  22. package/dist/internal/react/hooks/use-resolve-client-url.cjs.map +1 -0
  23. package/dist/internal/react/hooks/use-resolve-client-url.d.ts +5 -0
  24. package/dist/internal/react/hooks/use-resolve-client-url.js +15 -0
  25. package/dist/internal/react/hooks/use-resolve-client-url.js.map +1 -0
  26. package/dist/internal/shared/client/apply-origin.cjs +10 -5
  27. package/dist/internal/shared/client/apply-origin.cjs.map +1 -1
  28. package/dist/internal/shared/client/apply-origin.d.ts +3 -1
  29. package/dist/internal/shared/client/apply-origin.js +10 -5
  30. package/dist/internal/shared/client/apply-origin.js.map +1 -1
  31. package/dist/internal/shared/client/default-resolve-client-url.cjs +32 -0
  32. package/dist/internal/shared/client/default-resolve-client-url.cjs.map +1 -0
  33. package/dist/internal/shared/client/default-resolve-client-url.d.ts +5 -0
  34. package/dist/internal/shared/client/default-resolve-client-url.js +10 -0
  35. package/dist/internal/shared/client/default-resolve-client-url.js.map +1 -0
  36. package/dist/internal/shared/client/protected-rc-fallback.cjs +11 -2
  37. package/dist/internal/shared/client/protected-rc-fallback.cjs.map +1 -1
  38. package/dist/internal/shared/client/protected-rc-fallback.d.ts +2 -1
  39. package/dist/internal/shared/client/protected-rc-fallback.js +9 -1
  40. package/dist/internal/shared/client/protected-rc-fallback.js.map +1 -1
  41. package/dist/internal/shared/client/proxy-through-host.cjs +51 -0
  42. package/dist/internal/shared/client/proxy-through-host.cjs.map +1 -0
  43. package/dist/internal/shared/client/proxy-through-host.d.ts +57 -0
  44. package/dist/internal/shared/client/proxy-through-host.js +26 -0
  45. package/dist/internal/shared/client/proxy-through-host.js.map +1 -0
  46. package/dist/internal/shared/client/remote-component.cjs +121 -137
  47. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  48. package/dist/internal/shared/client/remote-component.d.ts +7 -5
  49. package/dist/internal/shared/client/remote-component.js +120 -137
  50. package/dist/internal/shared/client/remote-component.js.map +1 -1
  51. package/dist/internal/shared/constants.cjs +3 -0
  52. package/dist/internal/shared/constants.cjs.map +1 -1
  53. package/dist/internal/shared/constants.d.ts +2 -1
  54. package/dist/internal/shared/constants.js +2 -0
  55. package/dist/internal/shared/constants.js.map +1 -1
  56. package/dist/internal/shared/error.cjs +70 -0
  57. package/dist/internal/shared/error.cjs.map +1 -1
  58. package/dist/internal/shared/error.d.ts +3 -1
  59. package/dist/internal/shared/error.js +71 -0
  60. package/dist/internal/shared/error.js.map +1 -1
  61. package/dist/internal/shared/ssr/fetch-with-hooks.cjs +7 -2
  62. package/dist/internal/shared/ssr/fetch-with-hooks.cjs.map +1 -1
  63. package/dist/internal/shared/ssr/fetch-with-hooks.js +7 -2
  64. package/dist/internal/shared/ssr/fetch-with-hooks.js.map +1 -1
  65. package/dist/internal/shared/utils/logger.cjs +26 -10
  66. package/dist/internal/shared/utils/logger.cjs.map +1 -1
  67. package/dist/internal/shared/utils/logger.d.ts +6 -1
  68. package/dist/internal/shared/utils/logger.js +24 -9
  69. package/dist/internal/shared/utils/logger.js.map +1 -1
  70. package/dist/next/config.cjs +2 -2
  71. package/dist/next/config.cjs.map +1 -1
  72. package/dist/next/config.js +2 -2
  73. package/dist/next/config.js.map +1 -1
  74. package/dist/next/host/client/index.cjs +270 -209
  75. package/dist/next/host/client/index.cjs.map +1 -1
  76. package/dist/next/host/client/index.d.ts +3 -1
  77. package/dist/next/host/client/index.js +244 -184
  78. package/dist/next/host/client/index.js.map +1 -1
  79. package/dist/next/host/pages-router-client.cjs +15 -2
  80. package/dist/next/host/pages-router-client.cjs.map +1 -1
  81. package/dist/next/host/pages-router-client.d.ts +12 -1
  82. package/dist/next/host/pages-router-client.js +15 -2
  83. package/dist/next/host/pages-router-client.js.map +1 -1
  84. package/dist/next/host/pages-router-server.cjs +2 -0
  85. package/dist/next/host/pages-router-server.cjs.map +1 -1
  86. package/dist/next/host/pages-router-server.d.ts +11 -0
  87. package/dist/next/host/pages-router-server.js +2 -0
  88. package/dist/next/host/pages-router-server.js.map +1 -1
  89. package/dist/next/proxy.cjs +33 -6
  90. package/dist/next/proxy.cjs.map +1 -1
  91. package/dist/next/proxy.js +33 -6
  92. package/dist/next/proxy.js.map +1 -1
  93. package/dist/proxy-through-host-a676a522.d.ts +52 -0
  94. package/dist/react/index.cjs +289 -209
  95. package/dist/react/index.cjs.map +1 -1
  96. package/dist/react/index.d.ts +28 -4
  97. package/dist/react/index.js +262 -184
  98. package/dist/react/index.js.map +1 -1
  99. package/dist/shared/host/proxy.cjs +32 -6
  100. package/dist/shared/host/proxy.cjs.map +1 -1
  101. package/dist/shared/host/proxy.js +36 -7
  102. package/dist/shared/host/proxy.js.map +1 -1
  103. package/package.json +1 -1
  104. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.cjs +0 -65
  105. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.cjs.map +0 -1
  106. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.d.ts +0 -13
  107. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.js +0 -41
  108. 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 provided to withRemoteComponentsHost.`,
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 regex = new RegExp(pattern);
53
- return regex.test(targetUrl);
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: remote component URL ${url} does not match any allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS in withRemoteComponentsHost.`,
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 contentType = response.headers.get("content-type");
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: contentType ? { "content-type": contentType } : void 0
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 { RC_PROTECTED_REMOTE_FETCH_PATHNAME } 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 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 provided to withRemoteComponentsHost.`,\n {\n status: 403,\n },\n );\n }\n\n // Validate URL against allowed patterns to prevent SSRF attacks\n const isUrlAllowed = allowedPatterns.some((pattern) => {\n try {\n const regex = new RegExp(pattern);\n return regex.test(targetUrl);\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: remote component URL ${url} does not match any allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS in withRemoteComponentsHost.`,\n {\n status: 403,\n },\n );\n }\n\n // Fetch the remote resource\n const response = await fetch(targetUrl, { headers: remoteFetchHeaders() });\n\n const contentType = response.headers.get('content-type');\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: contentType ? { 'content-type': contentType } : undefined,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,uBAAmD;AACnD,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;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;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAe,gBAAgB,KAAK,CAAC,YAAY;AACrD,QAAI;AACF,YAAM,QAAQ,IAAI,OAAO,OAAO;AAChC,aAAO,MAAM,KAAK,SAAS;AAAA,IAC7B,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,mCAAmC;AAAA,MACnC;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,MAAM,WAAW,EAAE,aAAS,yCAAmB,EAAE,CAAC;AAEzE,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AAEvD,SAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB,SAAS,cAAc,EAAE,gBAAgB,YAAY,IAAI;AAAA,EAC3D,CAAC;AACH;","names":[]}
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 { RC_PROTECTED_REMOTE_FETCH_PATHNAME } from "#internal/shared/constants";
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 provided to withRemoteComponentsHost.`,
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 regex = new RegExp(pattern);
30
- return regex.test(targetUrl);
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: remote component URL ${url} does not match any allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS in withRemoteComponentsHost.`,
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 contentType = response.headers.get("content-type");
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: contentType ? { "content-type": contentType } : void 0
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 { RC_PROTECTED_REMOTE_FETCH_PATHNAME } 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 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 provided to withRemoteComponentsHost.`,\n {\n status: 403,\n },\n );\n }\n\n // Validate URL against allowed patterns to prevent SSRF attacks\n const isUrlAllowed = allowedPatterns.some((pattern) => {\n try {\n const regex = new RegExp(pattern);\n return regex.test(targetUrl);\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: remote component URL ${url} does not match any allowedProxyUrls or REMOTE_COMPONENTS_ALLOWED_PROXY_URLS in withRemoteComponentsHost.`,\n {\n status: 403,\n },\n );\n }\n\n // Fetch the remote resource\n const response = await fetch(targetUrl, { headers: remoteFetchHeaders() });\n\n const contentType = response.headers.get('content-type');\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: contentType ? { 'content-type': contentType } : undefined,\n });\n}\n"],"mappings":"AAOA,SAAS,0CAA0C;AACnD,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;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;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAe,gBAAgB,KAAK,CAAC,YAAY;AACrD,QAAI;AACF,YAAM,QAAQ,IAAI,OAAO,OAAO;AAChC,aAAO,MAAM,KAAK,SAAS;AAAA,IAC7B,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,mCAAmC;AAAA,MACnC;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,MAAM,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAC;AAEzE,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AAEvD,SAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB,SAAS,cAAc,EAAE,gBAAgB,YAAY,IAAI;AAAA,EAC3D,CAAC;AACH;","names":[]}
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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-components",
3
- "version": "0.0.51",
3
+ "version": "0.1.0",
4
4
  "private": false,
5
5
  "description": "Compose remote components at runtime between microfrontends applications.",
6
6
  "keywords": [
@@ -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":[]}