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.
Files changed (135) hide show
  1. package/dist/{component-loader-1838f572.d.ts → component-loader-21865da3.d.ts} +142 -16
  2. package/dist/host-config-58cdccea.d.ts +87 -0
  3. package/dist/html/host.cjs +589 -377
  4. package/dist/html/host.cjs.map +1 -1
  5. package/dist/html/host.d.ts +2 -0
  6. package/dist/html/host.js +588 -377
  7. package/dist/html/host.js.map +1 -1
  8. package/dist/html/remote.cjs +65 -57
  9. package/dist/html/remote.cjs.map +1 -1
  10. package/dist/html/remote.js +65 -57
  11. package/dist/html/remote.js.map +1 -1
  12. package/dist/internal/next/host/app-router-client.cjs +21 -10
  13. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  14. package/dist/internal/next/host/app-router-client.d.ts +36 -14
  15. package/dist/internal/next/host/app-router-client.js +21 -10
  16. package/dist/internal/next/host/app-router-client.js.map +1 -1
  17. package/dist/internal/next/remote/render-server.cjs.map +1 -1
  18. package/dist/internal/next/remote/render-server.d.ts +13 -14
  19. package/dist/internal/next/remote/render-server.js.map +1 -1
  20. package/dist/internal/react/context.cjs +43 -0
  21. package/dist/internal/react/context.cjs.map +1 -0
  22. package/dist/internal/react/context.d.ts +20 -0
  23. package/dist/internal/react/context.js +18 -0
  24. package/dist/internal/react/context.js.map +1 -0
  25. package/dist/internal/react/hooks/use-resolve-client-url.cjs +39 -0
  26. package/dist/internal/react/hooks/use-resolve-client-url.cjs.map +1 -0
  27. package/dist/internal/react/hooks/use-resolve-client-url.d.ts +5 -0
  28. package/dist/internal/react/hooks/use-resolve-client-url.js +15 -0
  29. package/dist/internal/react/hooks/use-resolve-client-url.js.map +1 -0
  30. package/dist/internal/shared/client/apply-origin.cjs +10 -5
  31. package/dist/internal/shared/client/apply-origin.cjs.map +1 -1
  32. package/dist/internal/shared/client/apply-origin.d.ts +3 -1
  33. package/dist/internal/shared/client/apply-origin.js +10 -5
  34. package/dist/internal/shared/client/apply-origin.js.map +1 -1
  35. package/dist/internal/shared/client/default-resolve-client-url.cjs +32 -0
  36. package/dist/internal/shared/client/default-resolve-client-url.cjs.map +1 -0
  37. package/dist/internal/shared/client/default-resolve-client-url.d.ts +5 -0
  38. package/dist/internal/shared/client/default-resolve-client-url.js +10 -0
  39. package/dist/internal/shared/client/default-resolve-client-url.js.map +1 -0
  40. package/dist/internal/shared/client/protected-rc-fallback.cjs +11 -2
  41. package/dist/internal/shared/client/protected-rc-fallback.cjs.map +1 -1
  42. package/dist/internal/shared/client/protected-rc-fallback.d.ts +2 -1
  43. package/dist/internal/shared/client/protected-rc-fallback.js +9 -1
  44. package/dist/internal/shared/client/protected-rc-fallback.js.map +1 -1
  45. package/dist/internal/shared/client/proxy-through-host.cjs +65 -0
  46. package/dist/internal/shared/client/proxy-through-host.cjs.map +1 -0
  47. package/dist/internal/shared/client/proxy-through-host.d.ts +62 -0
  48. package/dist/internal/shared/client/proxy-through-host.js +40 -0
  49. package/dist/internal/shared/client/proxy-through-host.js.map +1 -0
  50. package/dist/internal/shared/client/remote-component.cjs +121 -137
  51. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  52. package/dist/internal/shared/client/remote-component.d.ts +7 -5
  53. package/dist/internal/shared/client/remote-component.js +120 -137
  54. package/dist/internal/shared/client/remote-component.js.map +1 -1
  55. package/dist/internal/shared/constants.cjs +3 -0
  56. package/dist/internal/shared/constants.cjs.map +1 -1
  57. package/dist/internal/shared/constants.d.ts +2 -1
  58. package/dist/internal/shared/constants.js +2 -0
  59. package/dist/internal/shared/constants.js.map +1 -1
  60. package/dist/internal/shared/contract/host-state.cjs +38 -0
  61. package/dist/internal/shared/contract/host-state.cjs.map +1 -0
  62. package/dist/internal/shared/contract/host-state.d.ts +53 -0
  63. package/dist/internal/shared/contract/host-state.js +14 -0
  64. package/dist/internal/shared/contract/host-state.js.map +1 -0
  65. package/dist/internal/shared/contract/resolve-name-from-src.cjs +40 -0
  66. package/dist/internal/shared/contract/resolve-name-from-src.cjs.map +1 -0
  67. package/dist/internal/shared/contract/resolve-name-from-src.d.ts +13 -0
  68. package/dist/internal/shared/contract/resolve-name-from-src.js +16 -0
  69. package/dist/internal/shared/contract/resolve-name-from-src.js.map +1 -0
  70. package/dist/internal/shared/error.cjs +70 -0
  71. package/dist/internal/shared/error.cjs.map +1 -1
  72. package/dist/internal/shared/error.d.ts +3 -1
  73. package/dist/internal/shared/error.js +71 -0
  74. package/dist/internal/shared/error.js.map +1 -1
  75. package/dist/internal/shared/ssr/dom-flight.d.ts +1 -1
  76. package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
  77. package/dist/internal/shared/ssr/fetch-remote-component.d.ts +1 -1
  78. package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
  79. package/dist/internal/shared/ssr/fetch-with-hooks.cjs +7 -2
  80. package/dist/internal/shared/ssr/fetch-with-hooks.cjs.map +1 -1
  81. package/dist/internal/shared/ssr/fetch-with-hooks.d.ts +1 -1
  82. package/dist/internal/shared/ssr/fetch-with-hooks.js +7 -2
  83. package/dist/internal/shared/ssr/fetch-with-hooks.js.map +1 -1
  84. package/dist/internal/shared/utils/logger.cjs +26 -10
  85. package/dist/internal/shared/utils/logger.cjs.map +1 -1
  86. package/dist/internal/shared/utils/logger.d.ts +6 -1
  87. package/dist/internal/shared/utils/logger.js +24 -9
  88. package/dist/internal/shared/utils/logger.js.map +1 -1
  89. package/dist/next/config.cjs +2 -2
  90. package/dist/next/config.cjs.map +1 -1
  91. package/dist/next/config.js +2 -2
  92. package/dist/next/config.js.map +1 -1
  93. package/dist/next/host/app-router-server.cjs.map +1 -1
  94. package/dist/next/host/app-router-server.d.ts +11 -41
  95. package/dist/next/host/app-router-server.js.map +1 -1
  96. package/dist/next/host/client/index.cjs +467 -298
  97. package/dist/next/host/client/index.cjs.map +1 -1
  98. package/dist/next/host/client/index.d.ts +3 -1
  99. package/dist/next/host/client/index.js +445 -277
  100. package/dist/next/host/client/index.js.map +1 -1
  101. package/dist/next/host/pages-router-client.cjs +15 -2
  102. package/dist/next/host/pages-router-client.cjs.map +1 -1
  103. package/dist/next/host/pages-router-client.d.ts +14 -26
  104. package/dist/next/host/pages-router-client.js +15 -2
  105. package/dist/next/host/pages-router-client.js.map +1 -1
  106. package/dist/next/host/pages-router-server.cjs +2 -0
  107. package/dist/next/host/pages-router-server.cjs.map +1 -1
  108. package/dist/next/host/pages-router-server.d.ts +17 -31
  109. package/dist/next/host/pages-router-server.js +2 -0
  110. package/dist/next/host/pages-router-server.js.map +1 -1
  111. package/dist/next/index.cjs.map +1 -1
  112. package/dist/next/index.d.ts +13 -39
  113. package/dist/next/index.js.map +1 -1
  114. package/dist/next/proxy.cjs +33 -6
  115. package/dist/next/proxy.cjs.map +1 -1
  116. package/dist/next/proxy.js +33 -6
  117. package/dist/next/proxy.js.map +1 -1
  118. package/dist/next/remote/server.d.ts +4 -0
  119. package/dist/proxy-through-host-a676a522.d.ts +52 -0
  120. package/dist/react/index.cjs +486 -298
  121. package/dist/react/index.cjs.map +1 -1
  122. package/dist/react/index.d.ts +27 -40
  123. package/dist/react/index.js +463 -277
  124. package/dist/react/index.js.map +1 -1
  125. package/dist/shared/host/proxy.cjs +32 -6
  126. package/dist/shared/host/proxy.cjs.map +1 -1
  127. package/dist/shared/host/proxy.js +36 -7
  128. package/dist/shared/host/proxy.js.map +1 -1
  129. package/dist/{types-cbe44b51.d.ts → types-2b26a246.d.ts} +23 -6
  130. package/package.json +1 -1
  131. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.cjs +0 -65
  132. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.cjs.map +0 -1
  133. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.d.ts +0 -13
  134. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.js +0 -41
  135. package/dist/internal/shared/client/fetch-with-protected-rc-fallback.js.map +0 -1
@@ -4,7 +4,7 @@ import {
4
4
  useEffect,
5
5
  useId,
6
6
  useLayoutEffect as useLayoutEffect2,
7
- useMemo,
7
+ useMemo as useMemo2,
8
8
  useRef as useRef2,
9
9
  useState as useState2
10
10
  } from "react";
@@ -22,7 +22,7 @@ var tagNames = [
22
22
  "script",
23
23
  "link"
24
24
  ];
25
- function applyOriginToNodes(doc, url) {
25
+ function applyOriginToNodes(doc, url, resolveClientUrl) {
26
26
  if (url.origin !== location.origin) {
27
27
  const nodes = doc.querySelectorAll(
28
28
  tagNames.map(
@@ -31,12 +31,15 @@ function applyOriginToNodes(doc, url) {
31
31
  );
32
32
  nodes.forEach((node) => {
33
33
  if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
34
- node.src = new URL(node.getAttribute("src") ?? "/", url).href;
34
+ const absoluteSrc = new URL(node.getAttribute("src") ?? "/", url).href;
35
+ const isScript = node.tagName.toLowerCase() === "script";
36
+ node.src = isScript ? absoluteSrc : resolveClientUrl?.(absoluteSrc) ?? absoluteSrc;
35
37
  }
36
38
  if (node.hasAttribute("href") && /^[./]+\/?/.test(node.getAttribute("href") ?? "")) {
39
+ const absoluteHref = new URL(node.getAttribute("href") ?? "/", url).href;
37
40
  node.setAttribute(
38
41
  "href",
39
- new URL(node.getAttribute("href") ?? "/", url).href
42
+ resolveClientUrl?.(absoluteHref) ?? absoluteHref
40
43
  );
41
44
  }
42
45
  if (node.hasAttribute("srcset")) {
@@ -45,7 +48,8 @@ function applyOriginToNodes(doc, url) {
45
48
  if (!urlPart)
46
49
  return entry;
47
50
  const absoluteUrl = new URL(urlPart, url).href;
48
- return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
51
+ const resolvedUrl = resolveClientUrl?.(absoluteUrl) ?? absoluteUrl;
52
+ return descriptor ? `${resolvedUrl} ${descriptor}` : resolvedUrl;
49
53
  }).join(", ");
50
54
  if (srcSet) {
51
55
  node.setAttribute("srcset", srcSet);
@@ -57,7 +61,8 @@ function applyOriginToNodes(doc, url) {
57
61
  if (!urlPart)
58
62
  return entry;
59
63
  const absoluteUrl = new URL(urlPart, url).href;
60
- return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
64
+ const resolvedUrl = resolveClientUrl?.(absoluteUrl) ?? absoluteUrl;
65
+ return descriptor ? `${resolvedUrl} ${descriptor}` : resolvedUrl;
61
66
  }).join(", ");
62
67
  if (srcSet) {
63
68
  node.setAttribute("imagesrcset", srcSet);
@@ -67,6 +72,34 @@ function applyOriginToNodes(doc, url) {
67
72
  }
68
73
  }
69
74
 
75
+ // src/shared/constants.ts
76
+ var RC_PROTECTED_REMOTE_FETCH_PATHNAME = "/rc-fetch-protected-remote";
77
+ var CORS_DOCS_URL = "https://vercel.com/docs/remote-components/concepts/cors-external-urls#accessing-cross-site-protected-remote-components";
78
+
79
+ // src/shared/client/protected-rc-fallback.ts
80
+ function generateProtectedRcFallbackSrc(url) {
81
+ return `${RC_PROTECTED_REMOTE_FETCH_PATHNAME}?url=${encodeURIComponent(url)}`;
82
+ }
83
+ function isProxiedUrl(url) {
84
+ try {
85
+ return new URL(url, location.href).pathname === RC_PROTECTED_REMOTE_FETCH_PATHNAME;
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
90
+
91
+ // src/shared/utils/abort.ts
92
+ function isAbortError(error) {
93
+ if (error instanceof DOMException && error.name === "AbortError") {
94
+ return true;
95
+ }
96
+ if (error !== null && typeof error === "object" && "name" in error && error.name === "AbortError" && "message" in error && typeof error.message === "string") {
97
+ const e = error;
98
+ return typeof e.code === "number" || e.constructor?.name === "DOMException";
99
+ }
100
+ return false;
101
+ }
102
+
70
103
  // src/shared/error.ts
71
104
  var RemoteComponentsError = class extends Error {
72
105
  code = "REMOTE_COMPONENTS_ERROR";
@@ -86,6 +119,185 @@ function failedToFetchRemoteComponentError(url, { status, statusText }, help = "
86
119
  { cause: new Error(`${status} ${statusText}`) }
87
120
  );
88
121
  }
122
+ async function errorFromFailedFetch(originalUrl, resolvedUrl, res) {
123
+ const isProxied = isProxiedUrl(resolvedUrl.href);
124
+ if (isProxied && res) {
125
+ const body = await res.text().catch(() => "");
126
+ return failedProxyFetchError(
127
+ originalUrl,
128
+ resolvedUrl.href,
129
+ res.status,
130
+ body
131
+ );
132
+ }
133
+ const fallback = failedToFetchRemoteComponentError(
134
+ originalUrl,
135
+ res ?? { status: 0, statusText: "No Response" }
136
+ );
137
+ if (!res)
138
+ return fallback;
139
+ try {
140
+ const body = await res.text();
141
+ const parser = new DOMParser();
142
+ const doc = parser.parseFromString(body, "text/html");
143
+ const errorTemplate = doc.querySelector(
144
+ "template[data-next-error-message]"
145
+ );
146
+ const errorMessage = errorTemplate?.getAttribute("data-next-error-message");
147
+ if (errorMessage) {
148
+ const error = new RemoteComponentsError(errorMessage);
149
+ const errorStack = errorTemplate?.getAttribute("data-next-error-stack");
150
+ if (errorStack) {
151
+ error.stack = errorStack;
152
+ }
153
+ return error;
154
+ }
155
+ } catch (parseError) {
156
+ if (isAbortError(parseError))
157
+ throw parseError;
158
+ }
159
+ return fallback;
160
+ }
161
+ function failedProxyFetchError(originalUrl, proxyUrl, status, responseBody) {
162
+ if (status === 404) {
163
+ return new RemoteComponentsError(
164
+ `Could not proxy the request to "${originalUrl}" \u2014 the proxy endpoint "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" returned 404.
165
+
166
+ The host server needs middleware or a route that handles "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}".
167
+
168
+ Proxying requires two pieces:
169
+ 1. resolveClientUrl={proxyClientRequestsThroughHost} on <RemoteComponent>
170
+ 2. Middleware or a route for "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" on the host server
171
+
172
+ Docs: ${CORS_DOCS_URL}`
173
+ );
174
+ }
175
+ if (status === 403) {
176
+ const detail = responseBody ? ` ${responseBody}` : "";
177
+ return new RemoteComponentsError(
178
+ `Proxied request to "${proxyUrl}" was forbidden.${detail} See: ${CORS_DOCS_URL}`
179
+ );
180
+ }
181
+ return new RemoteComponentsError(
182
+ `Proxied request for "${originalUrl}" via "${proxyUrl}" failed with status ${status}. See: ${CORS_DOCS_URL}`
183
+ );
184
+ }
185
+
186
+ // src/shared/utils/index.ts
187
+ function escapeString(str) {
188
+ return str.replace(/[^a-z0-9]/g, "_");
189
+ }
190
+ var attrToProp = {
191
+ fetchpriority: "fetchPriority",
192
+ crossorigin: "crossOrigin",
193
+ imagesrcset: "imageSrcSet",
194
+ imagesizes: "imageSizes",
195
+ srcset: "srcSet"
196
+ };
197
+
198
+ // src/shared/client/const.ts
199
+ var DEFAULT_ROUTE = "/";
200
+ var RUNTIME_WEBPACK = "webpack";
201
+ var RUNTIME_TURBOPACK = "turbopack";
202
+ var RUNTIME_SCRIPT = "script";
203
+ var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
204
+ function getBundleKey(bundle) {
205
+ return escapeString(bundle);
206
+ }
207
+
208
+ // src/shared/client/parse-remote-html.ts
209
+ function validateSingleComponent(doc, name, url) {
210
+ if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) || doc.querySelectorAll("remote-component:not([src])").length > 1 && !doc.querySelector(`remote-component[name="${name}"]`)) {
211
+ throw multipleRemoteComponentsError(url);
212
+ }
213
+ }
214
+ function findComponentElement(doc, name) {
215
+ return doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) ?? doc.querySelector("div[data-bundle][data-route]") ?? doc.querySelector("div#__next") ?? doc.querySelector(`remote-component[name="${name}"]:not([src])`) ?? doc.querySelector("remote-component:not([src])");
216
+ }
217
+ function parseNextData(doc) {
218
+ return JSON.parse(
219
+ (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
220
+ );
221
+ }
222
+ function resolveComponentName(component, nextData, fallbackName) {
223
+ const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
224
+ const name = component?.getAttribute("id")?.replace(/_ssr$/, "") || isRemoteComponent && component?.getAttribute("name") || (nextData ? "__next" : fallbackName);
225
+ return { name, isRemoteComponent };
226
+ }
227
+ function extractComponentMetadata(component, nextData, name, url) {
228
+ return {
229
+ name,
230
+ bundle: component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default",
231
+ route: component?.getAttribute("data-route") ?? nextData?.page ?? (url.pathname || DEFAULT_ROUTE),
232
+ runtime: component?.getAttribute("data-runtime") ?? (nextData?.props.__REMOTE_COMPONENT__?.runtime || RUNTIME_SCRIPT)
233
+ };
234
+ }
235
+ function extractRemoteShared(doc, name, nextData) {
236
+ const remoteSharedEl = doc.querySelector(
237
+ `#${name}_shared[data-remote-components-shared]`
238
+ );
239
+ const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
240
+ remoteSharedEl?.remove();
241
+ return remoteShared;
242
+ }
243
+ function validateComponentFound(component, rsc, nextData, isRemoteComponent, url, name) {
244
+ if (!component || !(rsc || nextData || isRemoteComponent)) {
245
+ throw new RemoteComponentsError(
246
+ `Remote Component not found on ${url}.${name !== "__vercel_remote_component" ? ` The name for the <RemoteComponent> is "${name}". Check <RemoteComponent> usage.` : ""} Did you forget to wrap the content in <RemoteComponent>?`
247
+ );
248
+ }
249
+ }
250
+ function extractLinks(doc, component) {
251
+ return Array.from(doc.querySelectorAll("link[href]")).filter(
252
+ (link) => !component.contains(link)
253
+ );
254
+ }
255
+ function extractScripts(doc, component, isRemoteComponent) {
256
+ return Array.from(
257
+ (isRemoteComponent ? component : doc).querySelectorAll(
258
+ "script[src],script[data-src]"
259
+ )
260
+ );
261
+ }
262
+ function parseRemoteComponentDocument(doc, name, url) {
263
+ validateSingleComponent(doc, name, url.href);
264
+ const component = findComponentElement(doc, name);
265
+ const nextData = parseNextData(doc);
266
+ const { name: resolvedName, isRemoteComponent } = resolveComponentName(
267
+ component,
268
+ nextData,
269
+ name
270
+ );
271
+ const rsc = doc.querySelector(`#${resolvedName}_rsc`);
272
+ const metadata = extractComponentMetadata(
273
+ component,
274
+ nextData,
275
+ resolvedName,
276
+ url
277
+ );
278
+ const remoteShared = extractRemoteShared(doc, resolvedName, nextData);
279
+ validateComponentFound(
280
+ component,
281
+ rsc,
282
+ nextData,
283
+ isRemoteComponent,
284
+ url.href,
285
+ resolvedName
286
+ );
287
+ const links = extractLinks(doc, component);
288
+ const scripts = extractScripts(doc, component, isRemoteComponent);
289
+ return {
290
+ component,
291
+ name: resolvedName,
292
+ isRemoteComponent,
293
+ metadata,
294
+ nextData,
295
+ rsc,
296
+ remoteShared,
297
+ links,
298
+ scripts
299
+ };
300
+ }
89
301
 
90
302
  // src/shared/utils/logger.ts
91
303
  var PREFIX = "remote-components";
@@ -95,9 +307,6 @@ function logDebug(location2, message) {
95
307
  console.debug(`[${PREFIX}:${location2}]: ${message}`);
96
308
  }
97
309
  }
98
- function logInfo(location2, message) {
99
- console.info(`[${PREFIX}:${location2}]: ${message}`);
100
- }
101
310
  function logWarn(location2, message) {
102
311
  console.warn(`[${PREFIX}:${location2}]: ${message}`);
103
312
  }
@@ -108,6 +317,19 @@ function logError(location2, message, cause) {
108
317
  })
109
318
  );
110
319
  }
320
+ function warnCrossOriginFetchError(logLocation, url) {
321
+ try {
322
+ const parsed = typeof url === "string" ? new URL(url) : url;
323
+ if (typeof location === "undefined" || parsed.origin === location.origin) {
324
+ return;
325
+ }
326
+ logWarn(
327
+ logLocation,
328
+ `Failed to fetch cross-origin resource "${parsed.href}". If this is a protected deployment, ensure withRemoteComponentsHost middleware is configured in your host and that the remote URL is included in allowedProxyUrls. See: ${CORS_DOCS_URL}`
329
+ );
330
+ } catch {
331
+ }
332
+ }
111
333
 
112
334
  // src/shared/client/polyfill.tsx
113
335
  import { jsx } from "react/jsx-runtime";
@@ -551,19 +773,11 @@ function createRSCStream(rscName, data) {
551
773
  });
552
774
  }
553
775
 
554
- // src/shared/constants.ts
555
- var RC_PROTECTED_REMOTE_FETCH_PATHNAME = "/rc-fetch-protected-remote";
556
-
557
- // src/shared/client/protected-rc-fallback.ts
558
- function generateProtectedRcFallbackSrc(url) {
559
- return `${RC_PROTECTED_REMOTE_FETCH_PATHNAME}?url=${encodeURIComponent(url)}`;
560
- }
561
-
562
776
  // src/shared/client/webpack-patterns.ts
563
777
  var NEXT_BUNDLE_PATH_RE = /\/_next\/\[.+\](?:%20| )/;
564
778
 
565
779
  // src/shared/client/script-loader.ts
566
- async function loadScripts(scripts) {
780
+ async function loadScripts(scripts, resolveClientUrl) {
567
781
  await Promise.all(
568
782
  scripts.map((script) => {
569
783
  return new Promise((resolve, reject) => {
@@ -572,117 +786,34 @@ async function loadScripts(scripts) {
572
786
  script.src.replace(NEXT_BUNDLE_PATH_RE, "/_next/"),
573
787
  location.origin
574
788
  ).href;
575
- const loadScriptWithProtectedRcFallback = (src, isFallback = false) => {
576
- const newScript = document.createElement("script");
577
- newScript.onload = () => {
578
- if (isFallback) {
579
- logInfo(
580
- "ScriptLoader",
581
- `Successfully loaded <script src="${newSrc}"> using fallback.`
582
- );
583
- }
584
- resolve();
585
- };
586
- newScript.onerror = () => {
587
- if (!isFallback) {
588
- const fallbackSrc = generateProtectedRcFallbackSrc(newSrc);
589
- logWarn(
590
- "ScriptLoader",
591
- `Failed to load <script src="${newSrc}"> for Remote Component. Trying fallback with ${RC_PROTECTED_REMOTE_FETCH_PATHNAME} (withRemoteComponentsHost)...`
592
- );
593
- loadScriptWithProtectedRcFallback(fallbackSrc, true);
594
- } else {
595
- logError(
596
- "ScriptLoader",
597
- `Failed to load fallback for <script src="${newSrc}"> for Remote Component.`
598
- );
599
- reject(
600
- new RemoteComponentsError(
601
- `Failed to load <script src="${newSrc}"> for Remote Component. Check the URL is correct.`
602
- )
603
- );
604
- }
605
- };
606
- newScript.src = src;
607
- newScript.async = true;
608
- document.head.appendChild(newScript);
789
+ const resolvedSrc = resolveClientUrl?.(newSrc) ?? newSrc;
790
+ const newScript = document.createElement("script");
791
+ newScript.onload = () => resolve();
792
+ newScript.onerror = () => {
793
+ const isProxied = isProxiedUrl(resolvedSrc);
794
+ if (isProxied) {
795
+ reject(
796
+ new RemoteComponentsError(
797
+ `Failed to load script "${newSrc}" via proxy "${resolvedSrc}". Ensure withRemoteComponentsHost middleware is configured and "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" is in the matcher. See: ${CORS_DOCS_URL}`
798
+ )
799
+ );
800
+ } else {
801
+ warnCrossOriginFetchError("ScriptLoader", newSrc);
802
+ reject(
803
+ new RemoteComponentsError(
804
+ `Failed to load <script src="${newSrc}"> for Remote Component. Check the URL is correct.`
805
+ )
806
+ );
807
+ }
609
808
  };
610
- loadScriptWithProtectedRcFallback(newSrc);
809
+ newScript.src = resolvedSrc;
810
+ newScript.async = true;
811
+ document.head.appendChild(newScript);
611
812
  });
612
813
  })
613
814
  );
614
815
  }
615
816
 
616
- // src/shared/utils/index.ts
617
- function escapeString(str) {
618
- return str.replace(/[^a-z0-9]/g, "_");
619
- }
620
- var attrToProp = {
621
- fetchpriority: "fetchPriority",
622
- crossorigin: "crossOrigin",
623
- imagesrcset: "imageSrcSet",
624
- imagesizes: "imageSizes",
625
- srcset: "srcSet"
626
- };
627
-
628
- // src/shared/client/const.ts
629
- var DEFAULT_ROUTE = "/";
630
- var RUNTIME_WEBPACK = "webpack";
631
- var RUNTIME_TURBOPACK = "turbopack";
632
- var RUNTIME_SCRIPT = "script";
633
- var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
634
- function getBundleKey(bundle) {
635
- return escapeString(bundle);
636
- }
637
-
638
- // src/shared/utils/abort.ts
639
- function isAbortError(error) {
640
- if (error instanceof DOMException && error.name === "AbortError") {
641
- return true;
642
- }
643
- if (error !== null && typeof error === "object" && "name" in error && error.name === "AbortError" && "message" in error && typeof error.message === "string") {
644
- const e = error;
645
- return typeof e.code === "number" || e.constructor?.name === "DOMException";
646
- }
647
- return false;
648
- }
649
-
650
- // src/shared/client/fetch-with-protected-rc-fallback.ts
651
- async function fetchWithProtectedRcFallback(url, init) {
652
- try {
653
- const res = await fetch(url, init);
654
- return res;
655
- } catch (error) {
656
- if (isAbortError(error)) {
657
- throw error;
658
- }
659
- const parsedUrl = new URL(url);
660
- if (typeof document === "object" && typeof document.location === "object" && document.location.origin !== parsedUrl.origin) {
661
- logWarn(
662
- "FetchRemoteComponent",
663
- "Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy."
664
- );
665
- const proxiedRes = await fetch(
666
- generateProtectedRcFallbackSrc(parsedUrl.href),
667
- init?.signal ? { signal: init.signal } : void 0
668
- );
669
- if (proxiedRes.status === 200) {
670
- logInfo(
671
- "FetchRemoteComponent",
672
- `Successfully fetched ${parsedUrl.href} with fallback withRemoteComponentsHost proxy`
673
- );
674
- return proxiedRes;
675
- } else {
676
- logError(
677
- "FetchRemoteComponent",
678
- `Could not proxy remote: [response status ${proxiedRes.status}] ${await proxiedRes.text()}`
679
- );
680
- }
681
- }
682
- throw error;
683
- }
684
- }
685
-
686
817
  // src/shared/client/turbopack-patterns.ts
687
818
  var REMOTE_SHARED_MARKER_RE = /(?:self|[a-z])\.TURBOPACK_REMOTE_SHARED/;
688
819
  var REMOTE_SHARED_ASSIGNMENT_RE = /\.TURBOPACK_REMOTE_SHARED=await (?:__turbopack_context__|e)\.A\((?<sharedModuleId>[0-9]+)\)/;
@@ -692,7 +823,7 @@ var ASYNC_MODULE_ALL_RE = /(?<ctx>__turbopack_context__|e)=>\{\k<ctx>\.v\((?<vCb
692
823
  var TURBOPACK_GLOBAL_RE = /(?:globalThis|self)\s*(?:\.TURBOPACK|\[\s*["']TURBOPACK["']\s*\])/;
693
824
 
694
825
  // src/shared/client/chunk-loader.ts
695
- function createChunkLoader(runtime) {
826
+ function createChunkLoader(runtime, resolveClientUrl) {
696
827
  return function __turbopack_chunk_load__(chunkId, scriptBundle) {
697
828
  logDebug("ChunkLoader", `Loading chunk: "${chunkId}"`);
698
829
  const self = globalThis;
@@ -732,9 +863,10 @@ function createChunkLoader(runtime) {
732
863
  logDebug("ChunkLoader", `Returning cached promise for: "${url}"`);
733
864
  return self.__remote_components_turbopack_chunk_loader_promise__[url];
734
865
  }
735
- logDebug("ChunkLoader", `Fetching chunk from: "${url}"`);
866
+ const resolvedUrl = resolveClientUrl?.(url) ?? url;
867
+ logDebug("ChunkLoader", `Fetching chunk from: "${resolvedUrl}"`);
736
868
  self.__remote_components_turbopack_chunk_loader_promise__[url] = new Promise((resolve, reject) => {
737
- fetchWithProtectedRcFallback(url).then((res) => res.text()).then((code) => {
869
+ fetch(resolvedUrl).then((res) => res.text()).then((code) => {
738
870
  const hasTurbopack = TURBOPACK_GLOBAL_RE.test(code);
739
871
  if (hasTurbopack) {
740
872
  return handleTurbopackChunk(code, bundle ?? "", url);
@@ -747,7 +879,19 @@ function createChunkLoader(runtime) {
747
879
  "ChunkLoader",
748
880
  `First 500 chars of chunk: ${code.slice(0, 500)}`
749
881
  );
750
- }).then(resolve).catch(reject);
882
+ }).then(resolve).catch((error) => {
883
+ const isProxied = isProxiedUrl(resolvedUrl);
884
+ if (isProxied) {
885
+ reject(
886
+ new RemoteComponentsError(
887
+ `Failed to load chunk "${url}" via proxy "${resolvedUrl}". Ensure withRemoteComponentsHost middleware is configured and "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" is in the matcher. See: ${CORS_DOCS_URL}`
888
+ )
889
+ );
890
+ } else {
891
+ warnCrossOriginFetchError("ChunkLoader", url);
892
+ reject(error);
893
+ }
894
+ });
751
895
  });
752
896
  return self.__remote_components_turbopack_chunk_loader_promise__[url];
753
897
  };
@@ -1240,7 +1384,7 @@ function getSharedModule(bundle, id) {
1240
1384
  }
1241
1385
 
1242
1386
  // src/shared/client/webpack-adapter.ts
1243
- async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location.href), bundle, shared = {}, remoteShared = {}) {
1387
+ async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location.href), bundle, shared = {}, remoteShared = {}, resolveClientUrl) {
1244
1388
  const self = globalThis;
1245
1389
  if (!self.__remote_bundle_url__) {
1246
1390
  self.__remote_bundle_url__ = {};
@@ -1252,7 +1396,7 @@ async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location
1252
1396
  self.__original_webpack_chunk_load__ = self.__webpack_chunk_load__;
1253
1397
  self.__original_webpack_require__ = self.__webpack_require__;
1254
1398
  }
1255
- self.__webpack_chunk_load__ = createChunkLoader(runtime);
1399
+ self.__webpack_chunk_load__ = createChunkLoader(runtime, resolveClientUrl);
1256
1400
  self.__webpack_require__ = createModuleRequire(runtime);
1257
1401
  self.__webpack_require_type__ = runtime;
1258
1402
  if (self.__remote_webpack_require__ && runtime === RUNTIME_TURBOPACK) {
@@ -1347,7 +1491,8 @@ async function loadRemoteComponent({
1347
1491
  scripts = [],
1348
1492
  shared = Promise.resolve({}),
1349
1493
  remoteShared = {},
1350
- container
1494
+ container,
1495
+ resolveClientUrl
1351
1496
  }) {
1352
1497
  try {
1353
1498
  if (runtime === "webpack") {
@@ -1356,7 +1501,7 @@ async function loadRemoteComponent({
1356
1501
  self.__DISABLE_WEBPACK_EXEC__ = {};
1357
1502
  }
1358
1503
  self.__DISABLE_WEBPACK_EXEC__[bundle] = true;
1359
- await loadScripts(scripts);
1504
+ await loadScripts(scripts, resolveClientUrl);
1360
1505
  }
1361
1506
  const hostShared = await shared;
1362
1507
  logDebug(
@@ -1377,7 +1522,8 @@ async function loadRemoteComponent({
1377
1522
  url,
1378
1523
  bundle,
1379
1524
  hostShared,
1380
- remoteShared
1525
+ remoteShared,
1526
+ resolveClientUrl
1381
1527
  );
1382
1528
  if (bundle) {
1383
1529
  const resolve = {
@@ -1466,6 +1612,42 @@ function loadNextPagesComponent(bundle, route, nextData, name, container) {
1466
1612
  return { component };
1467
1613
  }
1468
1614
 
1615
+ // src/shared/client/proxy-through-host.ts
1616
+ function withRemoteSrc(resolveClientUrl, remoteSrc) {
1617
+ const remoteOrigin = parseOrigin(remoteSrc);
1618
+ return (url) => {
1619
+ const urlOrigin = parseOrigin(url);
1620
+ if (remoteOrigin && urlOrigin && urlOrigin !== remoteOrigin) {
1621
+ return void 0;
1622
+ }
1623
+ return resolveClientUrl(remoteSrc, url);
1624
+ };
1625
+ }
1626
+ function parseOrigin(url) {
1627
+ try {
1628
+ return new URL(url).origin;
1629
+ } catch {
1630
+ return void 0;
1631
+ }
1632
+ }
1633
+ var proxyClientRequestsThroughHost = (remoteSrc, url) => {
1634
+ if (typeof location === "undefined") {
1635
+ return void 0;
1636
+ }
1637
+ const remoteOrigin = new URL(remoteSrc, location.href).origin;
1638
+ if (remoteOrigin === location.origin) {
1639
+ return void 0;
1640
+ }
1641
+ try {
1642
+ const parsed = new URL(url, location.href);
1643
+ if (parsed.origin === remoteOrigin) {
1644
+ return generateProtectedRcFallbackSrc(url);
1645
+ }
1646
+ } catch {
1647
+ }
1648
+ return void 0;
1649
+ };
1650
+
1469
1651
  // src/shared/client/set-attributes-from-props.ts
1470
1652
  var DOMAttributeNames = {
1471
1653
  acceptCharset: "accept-charset",
@@ -1509,27 +1691,21 @@ function setAttributesFromProps(el, props) {
1509
1691
  }
1510
1692
 
1511
1693
  // src/shared/client/static-loader.ts
1512
- async function importViaProxy(absoluteSrc) {
1513
- const proxyUrl = new URL(
1514
- generateProtectedRcFallbackSrc(absoluteSrc),
1515
- location.href
1516
- ).href;
1517
- const response = await fetch(proxyUrl);
1694
+ async function importViaCallback(absoluteSrc, resolveClientUrl) {
1695
+ const resolvedUrl = resolveClientUrl(absoluteSrc) ?? absoluteSrc;
1696
+ const fetchUrl = new URL(resolvedUrl, location.href).href;
1697
+ const response = await fetch(fetchUrl);
1518
1698
  if (!response.ok)
1519
- throw new Error(`Proxy fetch failed: ${response.status}`);
1520
- logInfo(
1521
- "StaticLoader",
1522
- `Successfully loaded ${absoluteSrc} via protected RC proxy fallback.`
1523
- );
1699
+ throw new Error(`Proxied fetch failed: ${response.status}`);
1524
1700
  const content = (await response.text()).replace(/import\.meta\.url/g, JSON.stringify(absoluteSrc)).replace(
1525
1701
  /\b(from|import)\s*(["'])(\.\.?\/[^"']+)\2/g,
1526
1702
  (_, keyword, quote, relativePath) => {
1527
1703
  const absoluteImportUrl = new URL(relativePath, absoluteSrc).href;
1528
- const absoluteProxyUrl = new URL(
1529
- generateProtectedRcFallbackSrc(absoluteImportUrl),
1704
+ const resolvedImportUrl = new URL(
1705
+ resolveClientUrl(absoluteImportUrl) ?? absoluteImportUrl,
1530
1706
  location.href
1531
1707
  ).href;
1532
- return `${keyword} ${quote}${absoluteProxyUrl}${quote}`;
1708
+ return `${keyword} ${quote}${resolvedImportUrl}${quote}`;
1533
1709
  }
1534
1710
  );
1535
1711
  const moduleBlobUrl = URL.createObjectURL(
@@ -1563,6 +1739,20 @@ async function importViaProxy(absoluteSrc) {
1563
1739
  delete registry[absoluteSrc];
1564
1740
  return mod;
1565
1741
  }
1742
+ async function importDirectly(absoluteSrc) {
1743
+ try {
1744
+ return await import(
1745
+ /* @vite-ignore */
1746
+ /* webpackIgnore: true */
1747
+ absoluteSrc
1748
+ );
1749
+ } catch (importError) {
1750
+ if (!absoluteSrc.startsWith("blob:")) {
1751
+ warnCrossOriginFetchError("StaticLoader", absoluteSrc);
1752
+ }
1753
+ throw importError;
1754
+ }
1755
+ }
1566
1756
  function resolveScriptSrc(script, url) {
1567
1757
  const rawSrc = typeof script.getAttribute === "function" ? script.getAttribute("src") ?? script.src : script.src;
1568
1758
  if (!rawSrc && script.textContent) {
@@ -1575,24 +1765,7 @@ function resolveScriptSrc(script, url) {
1575
1765
  }
1576
1766
  return rawSrc;
1577
1767
  }
1578
- async function importScriptMod(absoluteSrc) {
1579
- try {
1580
- return await import(
1581
- /* @vite-ignore */
1582
- /* webpackIgnore: true */
1583
- absoluteSrc
1584
- );
1585
- } catch (importError) {
1586
- if (absoluteSrc.startsWith("blob:"))
1587
- throw importError;
1588
- logWarn(
1589
- "StaticLoader",
1590
- `Direct import of ${absoluteSrc} failed, attempting via protected RC proxy fallback.`
1591
- );
1592
- return importViaProxy(absoluteSrc);
1593
- }
1594
- }
1595
- async function loadStaticRemoteComponent(scripts, url) {
1768
+ async function loadStaticRemoteComponent(scripts, url, resolveClientUrl) {
1596
1769
  const self = globalThis;
1597
1770
  if (self.__remote_script_entrypoint_mount__?.[url.href]) {
1598
1771
  self.__remote_script_entrypoint_mount__[url.href] = /* @__PURE__ */ new Set();
@@ -1605,7 +1778,7 @@ async function loadStaticRemoteComponent(scripts, url) {
1605
1778
  try {
1606
1779
  const src = resolveScriptSrc(script, url);
1607
1780
  const absoluteSrc = new URL(src, url).href;
1608
- const mod = await importScriptMod(absoluteSrc);
1781
+ const mod = resolveClientUrl ? await importViaCallback(absoluteSrc, resolveClientUrl) : await importDirectly(absoluteSrc);
1609
1782
  if (src.startsWith("blob:")) {
1610
1783
  URL.revokeObjectURL(src);
1611
1784
  }
@@ -1667,6 +1840,32 @@ async function loadStaticRemoteComponent(scripts, url) {
1667
1840
  );
1668
1841
  }
1669
1842
 
1843
+ // src/shared/contract/host-state.ts
1844
+ function createHostState() {
1845
+ return {
1846
+ stage: "idle",
1847
+ prevSrc: void 0,
1848
+ prevUrl: void 0,
1849
+ prevName: void 0,
1850
+ prevIsRemoteComponent: false,
1851
+ abortController: void 0
1852
+ };
1853
+ }
1854
+
1855
+ // src/shared/contract/resolve-name-from-src.ts
1856
+ function resolveNameFromSrc(src, defaultName) {
1857
+ if (!src) {
1858
+ return defaultName;
1859
+ }
1860
+ const hash = typeof src === "string" ? src : src.hash;
1861
+ const hashIndex = hash.indexOf("#");
1862
+ if (hashIndex < 0) {
1863
+ return defaultName;
1864
+ }
1865
+ const name = hash.slice(hashIndex + 1);
1866
+ return name || defaultName;
1867
+ }
1868
+
1670
1869
  // src/shared/ssr/fetch-headers.ts
1671
1870
  function remoteFetchHeaders() {
1672
1871
  return {
@@ -1703,7 +1902,12 @@ async function fetchWithHooks(url, additionalInit, options = {}) {
1703
1902
  };
1704
1903
  let res = await onRequest?.(url, init, hookOptions);
1705
1904
  if (!res) {
1706
- res = await fetchWithProtectedRcFallback(url, init);
1905
+ try {
1906
+ res = await fetch(url, init);
1907
+ } catch (error) {
1908
+ warnCrossOriginFetchError("FetchRemoteComponent", url);
1909
+ throw error;
1910
+ }
1707
1911
  }
1708
1912
  const transformedRes = await onResponse?.(url, res, hookOptions);
1709
1913
  if (transformedRes) {
@@ -1721,6 +1925,25 @@ function getClientOrServerUrl(src, serverFallback) {
1721
1925
  return typeof src === "string" ? new URL(src, fallback) : src;
1722
1926
  }
1723
1927
 
1928
+ // src/react/hooks/use-resolve-client-url.ts
1929
+ import { useMemo } from "react";
1930
+ import { useRemoteComponentsContext } from "#internal/react/context";
1931
+
1932
+ // src/shared/client/default-resolve-client-url.ts
1933
+ function bindResolveClientUrl(prop, remoteSrc) {
1934
+ return prop ? withRemoteSrc(prop, remoteSrc) : void 0;
1935
+ }
1936
+
1937
+ // src/react/hooks/use-resolve-client-url.ts
1938
+ function useResolveClientUrl(prop, urlHref) {
1939
+ const { resolveClientUrl: contextValue } = useRemoteComponentsContext();
1940
+ const resolveClientUrl = prop ?? contextValue;
1941
+ return useMemo(
1942
+ () => bindResolveClientUrl(resolveClientUrl, urlHref),
1943
+ [resolveClientUrl, urlHref]
1944
+ );
1945
+ }
1946
+
1724
1947
  // src/react/hooks/use-shadow-root.ts
1725
1948
  import { useLayoutEffect, useRef, useState } from "react";
1726
1949
  function useShadowRoot({
@@ -1770,7 +1993,7 @@ function useShadowRoot({
1770
1993
  return { shadowRoot, shadowRootContainerRef };
1771
1994
  }
1772
1995
 
1773
- // src/react/utils/parse-remote-html.ts
1996
+ // src/react/utils/extract-remote-html.ts
1774
1997
  var DUMMY_FALLBACK = "http://remote-components-dummy-fallback";
1775
1998
  function getRemoteComponentHtml(html) {
1776
1999
  if (typeof document === "undefined")
@@ -1793,6 +2016,7 @@ function getRemoteComponentHtml(html) {
1793
2016
  }
1794
2017
 
1795
2018
  // src/react/index.tsx
2019
+ import { RemoteComponentsProvider } from "#internal/react/context";
1796
2020
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
1797
2021
  import { createElement as createElement2 } from "react";
1798
2022
  function RemoteComponent({
@@ -1809,27 +2033,21 @@ function RemoteComponent({
1809
2033
  onError,
1810
2034
  onChange,
1811
2035
  onRequest,
1812
- onResponse
2036
+ onResponse,
2037
+ resolveClientUrl: _resolveClientUrl
1813
2038
  }) {
1814
2039
  const instanceId = useId();
1815
- const name = useMemo(() => {
1816
- if (typeof src === "string") {
1817
- const url2 = new URL(
1818
- src,
1819
- typeof document !== "undefined" ? location.href : DUMMY_FALLBACK
1820
- );
1821
- if (url2.hash) {
1822
- return url2.hash.slice(1);
1823
- }
1824
- } else if (typeof src === "object" && "hash" in src && src.hash) {
1825
- return src.hash.slice(1) || nameProp;
1826
- }
1827
- return nameProp;
1828
- }, [src, nameProp]);
2040
+ const name = useMemo2(
2041
+ () => resolveNameFromSrc(src, nameProp),
2042
+ [src, nameProp]
2043
+ );
1829
2044
  const [data, setData] = useState2(null);
1830
- const url = useMemo(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
2045
+ const url = useMemo2(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
2046
+ const resolveClientUrl = useResolveClientUrl(_resolveClientUrl, url.href);
1831
2047
  const id = url.origin === (typeof location !== "undefined" ? location.origin : DUMMY_FALLBACK) ? url.pathname : url.href;
1832
- const keySuffix = `${escapeString(id)}_${escapeString(data?.name ?? name)}_${escapeString(instanceId)}`;
2048
+ const keySuffix = `${escapeString(id)}_${escapeString(
2049
+ data?.name ?? name
2050
+ )}_${escapeString(instanceId)}`;
1833
2051
  const [remoteComponent, setRemoteComponent] = useState2(null);
1834
2052
  const { shadowRoot, shadowRootContainerRef } = useShadowRoot({
1835
2053
  isolate,
@@ -1855,13 +2073,10 @@ function RemoteComponent({
1855
2073
  return elements;
1856
2074
  })() : []
1857
2075
  );
1858
- const prevSrcRef = useRef2(null);
2076
+ const hostStateRef = useRef2(createHostState());
1859
2077
  const componentHydrationHtml = useRef2(null);
1860
- const prevIsRemoteComponentRef = useRef2(false);
1861
- const prevUrlRef = useRef2(null);
1862
2078
  const prevRemoteComponentContainerRef = useRef2(null);
1863
2079
  const unmountRef = useRef2(null);
1864
- const prevNameRef = useRef2(void 0);
1865
2080
  useLayoutEffect2(() => {
1866
2081
  const shadowRootKey = `__remote_components_shadowroot_${keySuffix}`;
1867
2082
  return () => {
@@ -1900,14 +2115,18 @@ function RemoteComponent({
1900
2115
  }
1901
2116
  }, [shadowRoot, remoteComponent, name]);
1902
2117
  useEffect(() => {
1903
- if (src && src !== prevSrcRef.current) {
1904
- const previousSrc = prevSrcRef.current;
1905
- const previousName = prevNameRef.current;
1906
- prevSrcRef.current = src;
2118
+ if (src && src !== hostStateRef.current.prevSrc) {
2119
+ const previousSrc = hostStateRef.current.prevSrc;
2120
+ const previousName = hostStateRef.current.prevName;
2121
+ hostStateRef.current.prevSrc = src;
1907
2122
  if (previousSrc !== null) {
1908
2123
  htmlRef.current = null;
1909
2124
  }
2125
+ hostStateRef.current.abortController?.abort();
2126
+ hostStateRef.current.abortController = new AbortController();
2127
+ const { signal } = hostStateRef.current.abortController;
1910
2128
  onBeforeLoad?.(src);
2129
+ hostStateRef.current.stage = "loading";
1911
2130
  startTransition(async () => {
1912
2131
  try {
1913
2132
  let html = getRemoteComponentHtml(
@@ -1917,86 +2136,45 @@ function RemoteComponent({
1917
2136
  const fetchInit = {
1918
2137
  credentials
1919
2138
  };
1920
- const abortController = new AbortController();
1921
- const res = await fetchWithHooks(url, fetchInit, {
2139
+ const resolvedUrl = new URL(
2140
+ resolveClientUrl?.(url.href) ?? url.href,
2141
+ location.href
2142
+ );
2143
+ const res = await fetchWithHooks(resolvedUrl, fetchInit, {
1922
2144
  onRequest,
1923
2145
  onResponse,
1924
- abortController
2146
+ abortController: hostStateRef.current.abortController
1925
2147
  });
1926
2148
  if (!res || !res.ok) {
1927
- let error = failedToFetchRemoteComponentError(
1928
- url.href,
1929
- res ?? new Response(null, { status: 0 })
1930
- );
1931
- try {
1932
- const body = await res.text();
1933
- const parser2 = new DOMParser();
1934
- const doc2 = parser2.parseFromString(body, "text/html");
1935
- const errorTemplate = doc2.querySelector(
1936
- "template[data-next-error-message]"
1937
- );
1938
- const errorMessage = errorTemplate?.getAttribute(
1939
- "data-next-error-message"
1940
- );
1941
- const errorStack = errorTemplate?.getAttribute(
1942
- "data-next-error-stack"
1943
- );
1944
- if (errorMessage) {
1945
- error = new RemoteComponentsError(errorMessage);
1946
- if (errorStack) {
1947
- error.stack = errorStack;
1948
- }
1949
- }
1950
- } catch (parseError) {
1951
- if (isAbortError(parseError))
1952
- throw parseError;
1953
- }
1954
- throw error;
2149
+ throw await errorFromFailedFetch(url.href, resolvedUrl, res);
1955
2150
  }
1956
2151
  const remoteHtml = await res.text();
2152
+ if (signal.aborted)
2153
+ return;
1957
2154
  htmlRef.current = remoteHtml;
1958
2155
  html = getRemoteComponentHtml(remoteHtml);
1959
2156
  }
2157
+ if (signal.aborted)
2158
+ return;
1960
2159
  const parser = new DOMParser();
1961
2160
  const doc = parser.parseFromString(html, "text/html");
1962
- if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(
1963
- `div[data-bundle][data-route][id^="${name}"]`
1964
- ) || doc.querySelectorAll("remote-component:not([src])").length > 1 && !doc.querySelector(`remote-component[name="${name}"]`)) {
1965
- throw multipleRemoteComponentsError(url.href);
1966
- }
1967
- const component = doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) ?? // fallback to the first element with the data-bundle and data-route attributes when not using a named remote component
1968
- doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
1969
- doc.querySelector("div#__next") ?? // fallback to the remote-component web component
1970
- doc.querySelector(`remote-component[name="${name}"]:not([src])`) ?? doc.querySelector("remote-component:not([src])");
1971
- const nextData = JSON.parse(
1972
- (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
1973
- );
1974
- const remoteName = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : name);
1975
- const rsc = doc.querySelector(`#${remoteName}_rsc`);
1976
- const bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default";
1977
- const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
1978
- const metadata = {
2161
+ const {
2162
+ component,
1979
2163
  name: remoteName,
1980
- bundle,
1981
- route: component?.getAttribute("data-route") ?? nextData?.page ?? (url.pathname || DEFAULT_ROUTE),
1982
- runtime: component?.getAttribute("data-runtime") ?? (nextData?.props.__REMOTE_COMPONENT__?.runtime || RUNTIME_SCRIPT)
1983
- };
1984
- const remoteSharedEl = doc.querySelector(
1985
- `#${remoteName}_shared[data-remote-components-shared]`
1986
- );
1987
- const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
1988
- remoteSharedEl?.remove();
1989
- if (!component || !(rsc || nextData || isRemoteComponent)) {
1990
- throw new RemoteComponentsError(
1991
- `Remote Component not found on ${url.href}.${remoteName !== "__vercel_remote_component" ? `The name for the <RemoteComponent> is "${remoteName}". Check <RemoteComponent> usage.` : ""} Did you forget to wrap the content in <RemoteComponent>?`
1992
- );
1993
- }
1994
- if (prevIsRemoteComponentRef.current) {
2164
+ isRemoteComponent,
2165
+ metadata,
2166
+ nextData,
2167
+ rsc,
2168
+ remoteShared,
2169
+ links: linkElements,
2170
+ scripts: scriptElements
2171
+ } = parseRemoteComponentDocument(doc, name, url);
2172
+ if (hostStateRef.current.prevIsRemoteComponent) {
1995
2173
  if (shadowRoot) {
1996
2174
  shadowRoot.innerHTML = "";
1997
2175
  }
1998
2176
  const self = globalThis;
1999
- const prevUrl = prevUrlRef.current;
2177
+ const prevUrl = hostStateRef.current.prevUrl;
2000
2178
  if (prevUrl && self.__remote_script_entrypoint_unmount__?.[prevUrl.href]) {
2001
2179
  const unmountPromises = Promise.all(
2002
2180
  Array.from(unmountRef.current ?? []).map(
@@ -2009,15 +2187,11 @@ function RemoteComponent({
2009
2187
  await unmountPromises;
2010
2188
  }
2011
2189
  }
2012
- prevIsRemoteComponentRef.current = isRemoteComponent;
2013
- prevUrlRef.current = url;
2014
- prevNameRef.current = remoteName;
2015
- applyOriginToNodes(doc, url);
2016
- const links = Array.from(
2017
- doc.querySelectorAll("link[href]")
2018
- ).filter((link) => {
2019
- return !component.contains(link);
2020
- }).map((link) => ({
2190
+ hostStateRef.current.prevIsRemoteComponent = isRemoteComponent;
2191
+ hostStateRef.current.prevUrl = url;
2192
+ hostStateRef.current.prevName = remoteName;
2193
+ applyOriginToNodes(doc, url, resolveClientUrl);
2194
+ const links = linkElements.map((link) => ({
2021
2195
  href: new URL(link.getAttribute("href") ?? link.href, url).href,
2022
2196
  ...link.getAttributeNames().reduce((acc, key) => {
2023
2197
  if (key !== "href") {
@@ -2026,7 +2200,7 @@ function RemoteComponent({
2026
2200
  return acc;
2027
2201
  }, {})
2028
2202
  }));
2029
- const scripts = (isRemoteComponent ? component : doc).querySelectorAll("script[src],script[data-src]");
2203
+ const scripts = scriptElements;
2030
2204
  const inlineScripts = (isRemoteComponent ? component : doc).querySelectorAll(
2031
2205
  "script:not([src]):not([data-src]):not([id*='_rsc']):not([id='__NEXT_DATA__']):not([id='__REMOTE_NEXT_DATA__'])"
2032
2206
  );
@@ -2117,7 +2291,7 @@ function RemoteComponent({
2117
2291
  );
2118
2292
  }
2119
2293
  if (isRemoteComponent) {
2120
- if (previousSrc !== null) {
2294
+ if (previousSrc !== void 0) {
2121
2295
  onChange?.({
2122
2296
  previousSrc,
2123
2297
  nextSrc: src,
@@ -2136,7 +2310,8 @@ function RemoteComponent({
2136
2310
  setRemoteComponent(null);
2137
2311
  const { mount, unmount } = await loadStaticRemoteComponent(
2138
2312
  Array.from(shadowRoot.querySelectorAll("script")),
2139
- url
2313
+ url,
2314
+ resolveClientUrl
2140
2315
  );
2141
2316
  unmountRef.current = unmount;
2142
2317
  await Promise.all(
@@ -2157,7 +2332,8 @@ function RemoteComponent({
2157
2332
  htmlRef.current = null;
2158
2333
  const { mount, unmount } = await loadStaticRemoteComponent(
2159
2334
  Array.from(component.querySelectorAll("script")),
2160
- url
2335
+ url,
2336
+ resolveClientUrl
2161
2337
  );
2162
2338
  unmountRef.current = unmount;
2163
2339
  await Promise.all(
@@ -2167,12 +2343,13 @@ function RemoteComponent({
2167
2343
  );
2168
2344
  onLoad?.(src);
2169
2345
  }
2346
+ hostStateRef.current.stage = "loaded";
2170
2347
  } else {
2171
2348
  const result = await loadRemoteComponent({
2172
2349
  url,
2173
2350
  name: remoteName,
2174
2351
  rscName,
2175
- bundle,
2352
+ bundle: metadata.bundle,
2176
2353
  route: metadata.route,
2177
2354
  runtime: metadata.runtime,
2178
2355
  data: newData.data,
@@ -2200,13 +2377,14 @@ function RemoteComponent({
2200
2377
  ...userShared
2201
2378
  },
2202
2379
  remoteShared,
2203
- container: shadowRoot
2380
+ container: shadowRoot,
2381
+ resolveClientUrl
2204
2382
  });
2205
2383
  if (rsc) {
2206
2384
  rsc.remove();
2207
2385
  }
2208
2386
  setData(newData);
2209
- if (previousSrc !== null) {
2387
+ if (previousSrc !== void 0) {
2210
2388
  onChange?.({
2211
2389
  previousSrc,
2212
2390
  nextSrc: src,
@@ -2215,17 +2393,21 @@ function RemoteComponent({
2215
2393
  });
2216
2394
  }
2217
2395
  if (result.error) {
2396
+ hostStateRef.current.stage = "error";
2218
2397
  setRemoteComponent(result.error);
2219
2398
  onError?.(result.error);
2220
2399
  } else {
2400
+ hostStateRef.current.stage = "loaded";
2221
2401
  setRemoteComponent(result.component);
2222
2402
  onLoad?.(src);
2223
2403
  }
2224
2404
  }
2225
2405
  } catch (error) {
2226
2406
  if (isAbortError(error)) {
2407
+ hostStateRef.current.stage = "idle";
2227
2408
  return;
2228
2409
  }
2410
+ hostStateRef.current.stage = "error";
2229
2411
  setRemoteComponent(error);
2230
2412
  onError?.(error);
2231
2413
  }
@@ -2246,7 +2428,8 @@ function RemoteComponent({
2246
2428
  onError,
2247
2429
  onChange,
2248
2430
  onRequest,
2249
- onResponse
2431
+ onResponse,
2432
+ resolveClientUrl
2250
2433
  ]);
2251
2434
  if (remoteComponent instanceof Error) {
2252
2435
  throw remoteComponent;
@@ -2255,7 +2438,7 @@ function RemoteComponent({
2255
2438
  name: data?.name || name,
2256
2439
  bundle: data?.bundle || "default",
2257
2440
  route: data?.route || DEFAULT_ROUTE,
2258
- runtime: prevIsRemoteComponentRef.current ? RUNTIME_SCRIPT : data?.runtime || RUNTIME_WEBPACK
2441
+ runtime: hostStateRef.current.prevIsRemoteComponent ? RUNTIME_SCRIPT : data?.runtime || RUNTIME_WEBPACK
2259
2442
  }) });
2260
2443
  const resetStyle = reset ? /* @__PURE__ */ jsx2("style", { "data-remote-components-reset": "react", children: `:host { all: initial; }` }) : null;
2261
2444
  const linksToRender = data?.links?.map((link) => /* @__PURE__ */ createElement2(
@@ -2274,10 +2457,11 @@ function RemoteComponent({
2274
2457
  if (componentHydrationHtml.current && shadowRoot && !shadowRoot.innerHTML) {
2275
2458
  shadowRoot.innerHTML = componentHydrationHtml.current;
2276
2459
  componentHydrationHtml.current = null;
2277
- if (prevIsRemoteComponentRef.current) {
2460
+ if (hostStateRef.current.prevIsRemoteComponent) {
2278
2461
  loadStaticRemoteComponent(
2279
2462
  Array.from(shadowRoot.querySelectorAll("script")),
2280
- url
2463
+ url,
2464
+ resolveClientUrl
2281
2465
  ).then(({ mount }) => {
2282
2466
  return Promise.all(
2283
2467
  Array.from(mount).map((mountFn) => mountFn(shadowRoot))
@@ -2360,6 +2544,8 @@ function RemoteComponent({
2360
2544
  ] });
2361
2545
  }
2362
2546
  export {
2363
- RemoteComponent
2547
+ RemoteComponent,
2548
+ RemoteComponentsProvider,
2549
+ proxyClientRequestsThroughHost
2364
2550
  };
2365
2551
  //# sourceMappingURL=index.js.map