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
@@ -9,7 +9,7 @@ import {
9
9
  useEffect,
10
10
  useId,
11
11
  useLayoutEffect as useLayoutEffect2,
12
- useMemo,
12
+ useMemo as useMemo2,
13
13
  useRef as useRef2,
14
14
  useState as useState2
15
15
  } from "react";
@@ -27,7 +27,7 @@ var tagNames = [
27
27
  "script",
28
28
  "link"
29
29
  ];
30
- function applyOriginToNodes(doc, url) {
30
+ function applyOriginToNodes(doc, url, resolveClientUrl) {
31
31
  if (url.origin !== location.origin) {
32
32
  const nodes = doc.querySelectorAll(
33
33
  tagNames.map(
@@ -36,12 +36,15 @@ function applyOriginToNodes(doc, url) {
36
36
  );
37
37
  nodes.forEach((node) => {
38
38
  if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
39
- node.src = new URL(node.getAttribute("src") ?? "/", url).href;
39
+ const absoluteSrc = new URL(node.getAttribute("src") ?? "/", url).href;
40
+ const isScript = node.tagName.toLowerCase() === "script";
41
+ node.src = isScript ? absoluteSrc : resolveClientUrl?.(absoluteSrc) ?? absoluteSrc;
40
42
  }
41
43
  if (node.hasAttribute("href") && /^[./]+\/?/.test(node.getAttribute("href") ?? "")) {
44
+ const absoluteHref = new URL(node.getAttribute("href") ?? "/", url).href;
42
45
  node.setAttribute(
43
46
  "href",
44
- new URL(node.getAttribute("href") ?? "/", url).href
47
+ resolveClientUrl?.(absoluteHref) ?? absoluteHref
45
48
  );
46
49
  }
47
50
  if (node.hasAttribute("srcset")) {
@@ -50,7 +53,8 @@ function applyOriginToNodes(doc, url) {
50
53
  if (!urlPart)
51
54
  return entry;
52
55
  const absoluteUrl = new URL(urlPart, url).href;
53
- return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
56
+ const resolvedUrl = resolveClientUrl?.(absoluteUrl) ?? absoluteUrl;
57
+ return descriptor ? `${resolvedUrl} ${descriptor}` : resolvedUrl;
54
58
  }).join(", ");
55
59
  if (srcSet) {
56
60
  node.setAttribute("srcset", srcSet);
@@ -62,7 +66,8 @@ function applyOriginToNodes(doc, url) {
62
66
  if (!urlPart)
63
67
  return entry;
64
68
  const absoluteUrl = new URL(urlPart, url).href;
65
- return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
69
+ const resolvedUrl = resolveClientUrl?.(absoluteUrl) ?? absoluteUrl;
70
+ return descriptor ? `${resolvedUrl} ${descriptor}` : resolvedUrl;
66
71
  }).join(", ");
67
72
  if (srcSet) {
68
73
  node.setAttribute("imagesrcset", srcSet);
@@ -72,6 +77,31 @@ function applyOriginToNodes(doc, url) {
72
77
  }
73
78
  }
74
79
 
80
+ // src/shared/constants.ts
81
+ var RC_PROTECTED_REMOTE_FETCH_PATHNAME = "/rc-fetch-protected-remote";
82
+ var CORS_DOCS_URL = "https://vercel.com/docs/remote-components/concepts/cors-external-urls#accessing-cross-site-protected-remote-components";
83
+
84
+ // src/shared/client/protected-rc-fallback.ts
85
+ function isProxiedUrl(url) {
86
+ try {
87
+ return new URL(url, location.href).pathname === RC_PROTECTED_REMOTE_FETCH_PATHNAME;
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+
93
+ // src/shared/utils/abort.ts
94
+ function isAbortError(error) {
95
+ if (error instanceof DOMException && error.name === "AbortError") {
96
+ return true;
97
+ }
98
+ if (error !== null && typeof error === "object" && "name" in error && error.name === "AbortError" && "message" in error && typeof error.message === "string") {
99
+ const e = error;
100
+ return typeof e.code === "number" || e.constructor?.name === "DOMException";
101
+ }
102
+ return false;
103
+ }
104
+
75
105
  // src/shared/error.ts
76
106
  var RemoteComponentsError = class extends Error {
77
107
  code = "REMOTE_COMPONENTS_ERROR";
@@ -91,6 +121,185 @@ function failedToFetchRemoteComponentError(url, { status, statusText }, help = "
91
121
  { cause: new Error(`${status} ${statusText}`) }
92
122
  );
93
123
  }
124
+ async function errorFromFailedFetch(originalUrl, resolvedUrl, res) {
125
+ const isProxied = isProxiedUrl(resolvedUrl.href);
126
+ if (isProxied && res) {
127
+ const body = await res.text().catch(() => "");
128
+ return failedProxyFetchError(
129
+ originalUrl,
130
+ resolvedUrl.href,
131
+ res.status,
132
+ body
133
+ );
134
+ }
135
+ const fallback = failedToFetchRemoteComponentError(
136
+ originalUrl,
137
+ res ?? { status: 0, statusText: "No Response" }
138
+ );
139
+ if (!res)
140
+ return fallback;
141
+ try {
142
+ const body = await res.text();
143
+ const parser = new DOMParser();
144
+ const doc = parser.parseFromString(body, "text/html");
145
+ const errorTemplate = doc.querySelector(
146
+ "template[data-next-error-message]"
147
+ );
148
+ const errorMessage = errorTemplate?.getAttribute("data-next-error-message");
149
+ if (errorMessage) {
150
+ const error = new RemoteComponentsError(errorMessage);
151
+ const errorStack = errorTemplate?.getAttribute("data-next-error-stack");
152
+ if (errorStack) {
153
+ error.stack = errorStack;
154
+ }
155
+ return error;
156
+ }
157
+ } catch (parseError) {
158
+ if (isAbortError(parseError))
159
+ throw parseError;
160
+ }
161
+ return fallback;
162
+ }
163
+ function failedProxyFetchError(originalUrl, proxyUrl, status, responseBody) {
164
+ if (status === 404) {
165
+ return new RemoteComponentsError(
166
+ `Could not proxy the request to "${originalUrl}" \u2014 the proxy endpoint "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" returned 404.
167
+
168
+ The host server needs middleware or a route that handles "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}".
169
+
170
+ Proxying requires two pieces:
171
+ 1. resolveClientUrl={proxyClientRequestsThroughHost} on <RemoteComponent>
172
+ 2. Middleware or a route for "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" on the host server
173
+
174
+ Docs: ${CORS_DOCS_URL}`
175
+ );
176
+ }
177
+ if (status === 403) {
178
+ const detail = responseBody ? ` ${responseBody}` : "";
179
+ return new RemoteComponentsError(
180
+ `Proxied request to "${proxyUrl}" was forbidden.${detail} See: ${CORS_DOCS_URL}`
181
+ );
182
+ }
183
+ return new RemoteComponentsError(
184
+ `Proxied request for "${originalUrl}" via "${proxyUrl}" failed with status ${status}. See: ${CORS_DOCS_URL}`
185
+ );
186
+ }
187
+
188
+ // src/shared/utils/index.ts
189
+ function escapeString(str) {
190
+ return str.replace(/[^a-z0-9]/g, "_");
191
+ }
192
+ var attrToProp = {
193
+ fetchpriority: "fetchPriority",
194
+ crossorigin: "crossOrigin",
195
+ imagesrcset: "imageSrcSet",
196
+ imagesizes: "imageSizes",
197
+ srcset: "srcSet"
198
+ };
199
+
200
+ // src/shared/client/const.ts
201
+ var DEFAULT_ROUTE = "/";
202
+ var RUNTIME_WEBPACK = "webpack";
203
+ var RUNTIME_TURBOPACK = "turbopack";
204
+ var RUNTIME_SCRIPT = "script";
205
+ var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
206
+ function getBundleKey(bundle) {
207
+ return escapeString(bundle);
208
+ }
209
+
210
+ // src/shared/client/parse-remote-html.ts
211
+ function validateSingleComponent(doc, name, url) {
212
+ 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}"]`)) {
213
+ throw multipleRemoteComponentsError(url);
214
+ }
215
+ }
216
+ function findComponentElement(doc, name) {
217
+ 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])");
218
+ }
219
+ function parseNextData(doc) {
220
+ return JSON.parse(
221
+ (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
222
+ );
223
+ }
224
+ function resolveComponentName(component, nextData, fallbackName) {
225
+ const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
226
+ const name = component?.getAttribute("id")?.replace(/_ssr$/, "") || isRemoteComponent && component?.getAttribute("name") || (nextData ? "__next" : fallbackName);
227
+ return { name, isRemoteComponent };
228
+ }
229
+ function extractComponentMetadata(component, nextData, name, url) {
230
+ return {
231
+ name,
232
+ bundle: component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default",
233
+ route: component?.getAttribute("data-route") ?? nextData?.page ?? (url.pathname || DEFAULT_ROUTE),
234
+ runtime: component?.getAttribute("data-runtime") ?? (nextData?.props.__REMOTE_COMPONENT__?.runtime || RUNTIME_SCRIPT)
235
+ };
236
+ }
237
+ function extractRemoteShared(doc, name, nextData) {
238
+ const remoteSharedEl = doc.querySelector(
239
+ `#${name}_shared[data-remote-components-shared]`
240
+ );
241
+ const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
242
+ remoteSharedEl?.remove();
243
+ return remoteShared;
244
+ }
245
+ function validateComponentFound(component, rsc, nextData, isRemoteComponent, url, name) {
246
+ if (!component || !(rsc || nextData || isRemoteComponent)) {
247
+ throw new RemoteComponentsError(
248
+ `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>?`
249
+ );
250
+ }
251
+ }
252
+ function extractLinks(doc, component) {
253
+ return Array.from(doc.querySelectorAll("link[href]")).filter(
254
+ (link) => !component.contains(link)
255
+ );
256
+ }
257
+ function extractScripts(doc, component, isRemoteComponent) {
258
+ return Array.from(
259
+ (isRemoteComponent ? component : doc).querySelectorAll(
260
+ "script[src],script[data-src]"
261
+ )
262
+ );
263
+ }
264
+ function parseRemoteComponentDocument(doc, name, url) {
265
+ validateSingleComponent(doc, name, url.href);
266
+ const component = findComponentElement(doc, name);
267
+ const nextData = parseNextData(doc);
268
+ const { name: resolvedName, isRemoteComponent } = resolveComponentName(
269
+ component,
270
+ nextData,
271
+ name
272
+ );
273
+ const rsc = doc.querySelector(`#${resolvedName}_rsc`);
274
+ const metadata = extractComponentMetadata(
275
+ component,
276
+ nextData,
277
+ resolvedName,
278
+ url
279
+ );
280
+ const remoteShared = extractRemoteShared(doc, resolvedName, nextData);
281
+ validateComponentFound(
282
+ component,
283
+ rsc,
284
+ nextData,
285
+ isRemoteComponent,
286
+ url.href,
287
+ resolvedName
288
+ );
289
+ const links = extractLinks(doc, component);
290
+ const scripts = extractScripts(doc, component, isRemoteComponent);
291
+ return {
292
+ component,
293
+ name: resolvedName,
294
+ isRemoteComponent,
295
+ metadata,
296
+ nextData,
297
+ rsc,
298
+ remoteShared,
299
+ links,
300
+ scripts
301
+ };
302
+ }
94
303
 
95
304
  // src/shared/utils/logger.ts
96
305
  var PREFIX = "remote-components";
@@ -100,9 +309,6 @@ function logDebug(location2, message) {
100
309
  console.debug(`[${PREFIX}:${location2}]: ${message}`);
101
310
  }
102
311
  }
103
- function logInfo(location2, message) {
104
- console.info(`[${PREFIX}:${location2}]: ${message}`);
105
- }
106
312
  function logWarn(location2, message) {
107
313
  console.warn(`[${PREFIX}:${location2}]: ${message}`);
108
314
  }
@@ -113,6 +319,19 @@ function logError(location2, message, cause) {
113
319
  })
114
320
  );
115
321
  }
322
+ function warnCrossOriginFetchError(logLocation, url) {
323
+ try {
324
+ const parsed = typeof url === "string" ? new URL(url) : url;
325
+ if (typeof location === "undefined" || parsed.origin === location.origin) {
326
+ return;
327
+ }
328
+ logWarn(
329
+ logLocation,
330
+ `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}`
331
+ );
332
+ } catch {
333
+ }
334
+ }
116
335
 
117
336
  // src/shared/client/polyfill.tsx
118
337
  import { jsx } from "react/jsx-runtime";
@@ -556,19 +775,11 @@ function createRSCStream(rscName, data) {
556
775
  });
557
776
  }
558
777
 
559
- // src/shared/constants.ts
560
- var RC_PROTECTED_REMOTE_FETCH_PATHNAME = "/rc-fetch-protected-remote";
561
-
562
- // src/shared/client/protected-rc-fallback.ts
563
- function generateProtectedRcFallbackSrc(url) {
564
- return `${RC_PROTECTED_REMOTE_FETCH_PATHNAME}?url=${encodeURIComponent(url)}`;
565
- }
566
-
567
778
  // src/shared/client/webpack-patterns.ts
568
779
  var NEXT_BUNDLE_PATH_RE = /\/_next\/\[.+\](?:%20| )/;
569
780
 
570
781
  // src/shared/client/script-loader.ts
571
- async function loadScripts(scripts) {
782
+ async function loadScripts(scripts, resolveClientUrl) {
572
783
  await Promise.all(
573
784
  scripts.map((script) => {
574
785
  return new Promise((resolve, reject) => {
@@ -577,117 +788,34 @@ async function loadScripts(scripts) {
577
788
  script.src.replace(NEXT_BUNDLE_PATH_RE, "/_next/"),
578
789
  location.origin
579
790
  ).href;
580
- const loadScriptWithProtectedRcFallback = (src, isFallback = false) => {
581
- const newScript = document.createElement("script");
582
- newScript.onload = () => {
583
- if (isFallback) {
584
- logInfo(
585
- "ScriptLoader",
586
- `Successfully loaded <script src="${newSrc}"> using fallback.`
587
- );
588
- }
589
- resolve();
590
- };
591
- newScript.onerror = () => {
592
- if (!isFallback) {
593
- const fallbackSrc = generateProtectedRcFallbackSrc(newSrc);
594
- logWarn(
595
- "ScriptLoader",
596
- `Failed to load <script src="${newSrc}"> for Remote Component. Trying fallback with ${RC_PROTECTED_REMOTE_FETCH_PATHNAME} (withRemoteComponentsHost)...`
597
- );
598
- loadScriptWithProtectedRcFallback(fallbackSrc, true);
599
- } else {
600
- logError(
601
- "ScriptLoader",
602
- `Failed to load fallback for <script src="${newSrc}"> for Remote Component.`
603
- );
604
- reject(
605
- new RemoteComponentsError(
606
- `Failed to load <script src="${newSrc}"> for Remote Component. Check the URL is correct.`
607
- )
608
- );
609
- }
610
- };
611
- newScript.src = src;
612
- newScript.async = true;
613
- document.head.appendChild(newScript);
791
+ const resolvedSrc = resolveClientUrl?.(newSrc) ?? newSrc;
792
+ const newScript = document.createElement("script");
793
+ newScript.onload = () => resolve();
794
+ newScript.onerror = () => {
795
+ const isProxied = isProxiedUrl(resolvedSrc);
796
+ if (isProxied) {
797
+ reject(
798
+ new RemoteComponentsError(
799
+ `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}`
800
+ )
801
+ );
802
+ } else {
803
+ warnCrossOriginFetchError("ScriptLoader", newSrc);
804
+ reject(
805
+ new RemoteComponentsError(
806
+ `Failed to load <script src="${newSrc}"> for Remote Component. Check the URL is correct.`
807
+ )
808
+ );
809
+ }
614
810
  };
615
- loadScriptWithProtectedRcFallback(newSrc);
811
+ newScript.src = resolvedSrc;
812
+ newScript.async = true;
813
+ document.head.appendChild(newScript);
616
814
  });
617
815
  })
618
816
  );
619
817
  }
620
818
 
621
- // src/shared/utils/index.ts
622
- function escapeString(str) {
623
- return str.replace(/[^a-z0-9]/g, "_");
624
- }
625
- var attrToProp = {
626
- fetchpriority: "fetchPriority",
627
- crossorigin: "crossOrigin",
628
- imagesrcset: "imageSrcSet",
629
- imagesizes: "imageSizes",
630
- srcset: "srcSet"
631
- };
632
-
633
- // src/shared/client/const.ts
634
- var DEFAULT_ROUTE = "/";
635
- var RUNTIME_WEBPACK = "webpack";
636
- var RUNTIME_TURBOPACK = "turbopack";
637
- var RUNTIME_SCRIPT = "script";
638
- var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
639
- function getBundleKey(bundle) {
640
- return escapeString(bundle);
641
- }
642
-
643
- // src/shared/utils/abort.ts
644
- function isAbortError(error) {
645
- if (error instanceof DOMException && error.name === "AbortError") {
646
- return true;
647
- }
648
- if (error !== null && typeof error === "object" && "name" in error && error.name === "AbortError" && "message" in error && typeof error.message === "string") {
649
- const e = error;
650
- return typeof e.code === "number" || e.constructor?.name === "DOMException";
651
- }
652
- return false;
653
- }
654
-
655
- // src/shared/client/fetch-with-protected-rc-fallback.ts
656
- async function fetchWithProtectedRcFallback(url, init) {
657
- try {
658
- const res = await fetch(url, init);
659
- return res;
660
- } catch (error) {
661
- if (isAbortError(error)) {
662
- throw error;
663
- }
664
- const parsedUrl = new URL(url);
665
- if (typeof document === "object" && typeof document.location === "object" && document.location.origin !== parsedUrl.origin) {
666
- logWarn(
667
- "FetchRemoteComponent",
668
- "Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy."
669
- );
670
- const proxiedRes = await fetch(
671
- generateProtectedRcFallbackSrc(parsedUrl.href),
672
- init?.signal ? { signal: init.signal } : void 0
673
- );
674
- if (proxiedRes.status === 200) {
675
- logInfo(
676
- "FetchRemoteComponent",
677
- `Successfully fetched ${parsedUrl.href} with fallback withRemoteComponentsHost proxy`
678
- );
679
- return proxiedRes;
680
- } else {
681
- logError(
682
- "FetchRemoteComponent",
683
- `Could not proxy remote: [response status ${proxiedRes.status}] ${await proxiedRes.text()}`
684
- );
685
- }
686
- }
687
- throw error;
688
- }
689
- }
690
-
691
819
  // src/shared/client/turbopack-patterns.ts
692
820
  var REMOTE_SHARED_MARKER_RE = /(?:self|[a-z])\.TURBOPACK_REMOTE_SHARED/;
693
821
  var REMOTE_SHARED_ASSIGNMENT_RE = /\.TURBOPACK_REMOTE_SHARED=await (?:__turbopack_context__|e)\.A\((?<sharedModuleId>[0-9]+)\)/;
@@ -697,7 +825,7 @@ var ASYNC_MODULE_ALL_RE = /(?<ctx>__turbopack_context__|e)=>\{\k<ctx>\.v\((?<vCb
697
825
  var TURBOPACK_GLOBAL_RE = /(?:globalThis|self)\s*(?:\.TURBOPACK|\[\s*["']TURBOPACK["']\s*\])/;
698
826
 
699
827
  // src/shared/client/chunk-loader.ts
700
- function createChunkLoader(runtime) {
828
+ function createChunkLoader(runtime, resolveClientUrl) {
701
829
  return function __turbopack_chunk_load__(chunkId, scriptBundle) {
702
830
  logDebug("ChunkLoader", `Loading chunk: "${chunkId}"`);
703
831
  const self = globalThis;
@@ -737,9 +865,10 @@ function createChunkLoader(runtime) {
737
865
  logDebug("ChunkLoader", `Returning cached promise for: "${url}"`);
738
866
  return self.__remote_components_turbopack_chunk_loader_promise__[url];
739
867
  }
740
- logDebug("ChunkLoader", `Fetching chunk from: "${url}"`);
868
+ const resolvedUrl = resolveClientUrl?.(url) ?? url;
869
+ logDebug("ChunkLoader", `Fetching chunk from: "${resolvedUrl}"`);
741
870
  self.__remote_components_turbopack_chunk_loader_promise__[url] = new Promise((resolve, reject) => {
742
- fetchWithProtectedRcFallback(url).then((res) => res.text()).then((code) => {
871
+ fetch(resolvedUrl).then((res) => res.text()).then((code) => {
743
872
  const hasTurbopack = TURBOPACK_GLOBAL_RE.test(code);
744
873
  if (hasTurbopack) {
745
874
  return handleTurbopackChunk(code, bundle ?? "", url);
@@ -752,7 +881,19 @@ function createChunkLoader(runtime) {
752
881
  "ChunkLoader",
753
882
  `First 500 chars of chunk: ${code.slice(0, 500)}`
754
883
  );
755
- }).then(resolve).catch(reject);
884
+ }).then(resolve).catch((error) => {
885
+ const isProxied = isProxiedUrl(resolvedUrl);
886
+ if (isProxied) {
887
+ reject(
888
+ new RemoteComponentsError(
889
+ `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}`
890
+ )
891
+ );
892
+ } else {
893
+ warnCrossOriginFetchError("ChunkLoader", url);
894
+ reject(error);
895
+ }
896
+ });
756
897
  });
757
898
  return self.__remote_components_turbopack_chunk_loader_promise__[url];
758
899
  };
@@ -1245,7 +1386,7 @@ function getSharedModule(bundle, id) {
1245
1386
  }
1246
1387
 
1247
1388
  // src/shared/client/webpack-adapter.ts
1248
- async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location.href), bundle, shared = {}, remoteShared = {}) {
1389
+ async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location.href), bundle, shared = {}, remoteShared = {}, resolveClientUrl) {
1249
1390
  const self = globalThis;
1250
1391
  if (!self.__remote_bundle_url__) {
1251
1392
  self.__remote_bundle_url__ = {};
@@ -1257,7 +1398,7 @@ async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location
1257
1398
  self.__original_webpack_chunk_load__ = self.__webpack_chunk_load__;
1258
1399
  self.__original_webpack_require__ = self.__webpack_require__;
1259
1400
  }
1260
- self.__webpack_chunk_load__ = createChunkLoader(runtime);
1401
+ self.__webpack_chunk_load__ = createChunkLoader(runtime, resolveClientUrl);
1261
1402
  self.__webpack_require__ = createModuleRequire(runtime);
1262
1403
  self.__webpack_require_type__ = runtime;
1263
1404
  if (self.__remote_webpack_require__ && runtime === RUNTIME_TURBOPACK) {
@@ -1352,7 +1493,8 @@ async function loadRemoteComponent({
1352
1493
  scripts = [],
1353
1494
  shared = Promise.resolve({}),
1354
1495
  remoteShared = {},
1355
- container
1496
+ container,
1497
+ resolveClientUrl
1356
1498
  }) {
1357
1499
  try {
1358
1500
  if (runtime === "webpack") {
@@ -1361,7 +1503,7 @@ async function loadRemoteComponent({
1361
1503
  self.__DISABLE_WEBPACK_EXEC__ = {};
1362
1504
  }
1363
1505
  self.__DISABLE_WEBPACK_EXEC__[bundle] = true;
1364
- await loadScripts(scripts);
1506
+ await loadScripts(scripts, resolveClientUrl);
1365
1507
  }
1366
1508
  const hostShared = await shared;
1367
1509
  logDebug(
@@ -1382,7 +1524,8 @@ async function loadRemoteComponent({
1382
1524
  url,
1383
1525
  bundle,
1384
1526
  hostShared,
1385
- remoteShared
1527
+ remoteShared,
1528
+ resolveClientUrl
1386
1529
  );
1387
1530
  if (bundle) {
1388
1531
  const resolve = {
@@ -1471,6 +1614,25 @@ function loadNextPagesComponent(bundle, route, nextData, name, container) {
1471
1614
  return { component };
1472
1615
  }
1473
1616
 
1617
+ // src/shared/client/proxy-through-host.ts
1618
+ function withRemoteSrc(resolveClientUrl, remoteSrc) {
1619
+ const remoteOrigin = parseOrigin(remoteSrc);
1620
+ return (url) => {
1621
+ const urlOrigin = parseOrigin(url);
1622
+ if (remoteOrigin && urlOrigin && urlOrigin !== remoteOrigin) {
1623
+ return void 0;
1624
+ }
1625
+ return resolveClientUrl(remoteSrc, url);
1626
+ };
1627
+ }
1628
+ function parseOrigin(url) {
1629
+ try {
1630
+ return new URL(url).origin;
1631
+ } catch {
1632
+ return void 0;
1633
+ }
1634
+ }
1635
+
1474
1636
  // src/shared/client/set-attributes-from-props.ts
1475
1637
  var DOMAttributeNames = {
1476
1638
  acceptCharset: "accept-charset",
@@ -1514,27 +1676,21 @@ function setAttributesFromProps(el, props) {
1514
1676
  }
1515
1677
 
1516
1678
  // src/shared/client/static-loader.ts
1517
- async function importViaProxy(absoluteSrc) {
1518
- const proxyUrl = new URL(
1519
- generateProtectedRcFallbackSrc(absoluteSrc),
1520
- location.href
1521
- ).href;
1522
- const response = await fetch(proxyUrl);
1679
+ async function importViaCallback(absoluteSrc, resolveClientUrl) {
1680
+ const resolvedUrl = resolveClientUrl(absoluteSrc) ?? absoluteSrc;
1681
+ const fetchUrl = new URL(resolvedUrl, location.href).href;
1682
+ const response = await fetch(fetchUrl);
1523
1683
  if (!response.ok)
1524
- throw new Error(`Proxy fetch failed: ${response.status}`);
1525
- logInfo(
1526
- "StaticLoader",
1527
- `Successfully loaded ${absoluteSrc} via protected RC proxy fallback.`
1528
- );
1684
+ throw new Error(`Proxied fetch failed: ${response.status}`);
1529
1685
  const content = (await response.text()).replace(/import\.meta\.url/g, JSON.stringify(absoluteSrc)).replace(
1530
1686
  /\b(from|import)\s*(["'])(\.\.?\/[^"']+)\2/g,
1531
1687
  (_, keyword, quote, relativePath) => {
1532
1688
  const absoluteImportUrl = new URL(relativePath, absoluteSrc).href;
1533
- const absoluteProxyUrl = new URL(
1534
- generateProtectedRcFallbackSrc(absoluteImportUrl),
1689
+ const resolvedImportUrl = new URL(
1690
+ resolveClientUrl(absoluteImportUrl) ?? absoluteImportUrl,
1535
1691
  location.href
1536
1692
  ).href;
1537
- return `${keyword} ${quote}${absoluteProxyUrl}${quote}`;
1693
+ return `${keyword} ${quote}${resolvedImportUrl}${quote}`;
1538
1694
  }
1539
1695
  );
1540
1696
  const moduleBlobUrl = URL.createObjectURL(
@@ -1568,6 +1724,20 @@ async function importViaProxy(absoluteSrc) {
1568
1724
  delete registry[absoluteSrc];
1569
1725
  return mod;
1570
1726
  }
1727
+ async function importDirectly(absoluteSrc) {
1728
+ try {
1729
+ return await import(
1730
+ /* @vite-ignore */
1731
+ /* webpackIgnore: true */
1732
+ absoluteSrc
1733
+ );
1734
+ } catch (importError) {
1735
+ if (!absoluteSrc.startsWith("blob:")) {
1736
+ warnCrossOriginFetchError("StaticLoader", absoluteSrc);
1737
+ }
1738
+ throw importError;
1739
+ }
1740
+ }
1571
1741
  function resolveScriptSrc(script, url) {
1572
1742
  const rawSrc = typeof script.getAttribute === "function" ? script.getAttribute("src") ?? script.src : script.src;
1573
1743
  if (!rawSrc && script.textContent) {
@@ -1580,24 +1750,7 @@ function resolveScriptSrc(script, url) {
1580
1750
  }
1581
1751
  return rawSrc;
1582
1752
  }
1583
- async function importScriptMod(absoluteSrc) {
1584
- try {
1585
- return await import(
1586
- /* @vite-ignore */
1587
- /* webpackIgnore: true */
1588
- absoluteSrc
1589
- );
1590
- } catch (importError) {
1591
- if (absoluteSrc.startsWith("blob:"))
1592
- throw importError;
1593
- logWarn(
1594
- "StaticLoader",
1595
- `Direct import of ${absoluteSrc} failed, attempting via protected RC proxy fallback.`
1596
- );
1597
- return importViaProxy(absoluteSrc);
1598
- }
1599
- }
1600
- async function loadStaticRemoteComponent(scripts, url) {
1753
+ async function loadStaticRemoteComponent(scripts, url, resolveClientUrl) {
1601
1754
  const self = globalThis;
1602
1755
  if (self.__remote_script_entrypoint_mount__?.[url.href]) {
1603
1756
  self.__remote_script_entrypoint_mount__[url.href] = /* @__PURE__ */ new Set();
@@ -1610,7 +1763,7 @@ async function loadStaticRemoteComponent(scripts, url) {
1610
1763
  try {
1611
1764
  const src = resolveScriptSrc(script, url);
1612
1765
  const absoluteSrc = new URL(src, url).href;
1613
- const mod = await importScriptMod(absoluteSrc);
1766
+ const mod = resolveClientUrl ? await importViaCallback(absoluteSrc, resolveClientUrl) : await importDirectly(absoluteSrc);
1614
1767
  if (src.startsWith("blob:")) {
1615
1768
  URL.revokeObjectURL(src);
1616
1769
  }
@@ -1672,6 +1825,32 @@ async function loadStaticRemoteComponent(scripts, url) {
1672
1825
  );
1673
1826
  }
1674
1827
 
1828
+ // src/shared/contract/host-state.ts
1829
+ function createHostState() {
1830
+ return {
1831
+ stage: "idle",
1832
+ prevSrc: void 0,
1833
+ prevUrl: void 0,
1834
+ prevName: void 0,
1835
+ prevIsRemoteComponent: false,
1836
+ abortController: void 0
1837
+ };
1838
+ }
1839
+
1840
+ // src/shared/contract/resolve-name-from-src.ts
1841
+ function resolveNameFromSrc(src, defaultName) {
1842
+ if (!src) {
1843
+ return defaultName;
1844
+ }
1845
+ const hash = typeof src === "string" ? src : src.hash;
1846
+ const hashIndex = hash.indexOf("#");
1847
+ if (hashIndex < 0) {
1848
+ return defaultName;
1849
+ }
1850
+ const name = hash.slice(hashIndex + 1);
1851
+ return name || defaultName;
1852
+ }
1853
+
1675
1854
  // src/shared/ssr/fetch-headers.ts
1676
1855
  function remoteFetchHeaders() {
1677
1856
  return {
@@ -1708,7 +1887,12 @@ async function fetchWithHooks(url, additionalInit, options = {}) {
1708
1887
  };
1709
1888
  let res = await onRequest?.(url, init, hookOptions);
1710
1889
  if (!res) {
1711
- res = await fetchWithProtectedRcFallback(url, init);
1890
+ try {
1891
+ res = await fetch(url, init);
1892
+ } catch (error) {
1893
+ warnCrossOriginFetchError("FetchRemoteComponent", url);
1894
+ throw error;
1895
+ }
1712
1896
  }
1713
1897
  const transformedRes = await onResponse?.(url, res, hookOptions);
1714
1898
  if (transformedRes) {
@@ -1726,6 +1910,25 @@ function getClientOrServerUrl(src, serverFallback) {
1726
1910
  return typeof src === "string" ? new URL(src, fallback) : src;
1727
1911
  }
1728
1912
 
1913
+ // src/react/hooks/use-resolve-client-url.ts
1914
+ import { useMemo } from "react";
1915
+ import { useRemoteComponentsContext } from "#internal/react/context";
1916
+
1917
+ // src/shared/client/default-resolve-client-url.ts
1918
+ function bindResolveClientUrl(prop, remoteSrc) {
1919
+ return prop ? withRemoteSrc(prop, remoteSrc) : void 0;
1920
+ }
1921
+
1922
+ // src/react/hooks/use-resolve-client-url.ts
1923
+ function useResolveClientUrl(prop, urlHref) {
1924
+ const { resolveClientUrl: contextValue } = useRemoteComponentsContext();
1925
+ const resolveClientUrl = prop ?? contextValue;
1926
+ return useMemo(
1927
+ () => bindResolveClientUrl(resolveClientUrl, urlHref),
1928
+ [resolveClientUrl, urlHref]
1929
+ );
1930
+ }
1931
+
1729
1932
  // src/react/hooks/use-shadow-root.ts
1730
1933
  import { useLayoutEffect, useRef, useState } from "react";
1731
1934
  function useShadowRoot({
@@ -1775,7 +1978,7 @@ function useShadowRoot({
1775
1978
  return { shadowRoot, shadowRootContainerRef };
1776
1979
  }
1777
1980
 
1778
- // src/react/utils/parse-remote-html.ts
1981
+ // src/react/utils/extract-remote-html.ts
1779
1982
  var DUMMY_FALLBACK = "http://remote-components-dummy-fallback";
1780
1983
  function getRemoteComponentHtml(html) {
1781
1984
  if (typeof document === "undefined")
@@ -1798,6 +2001,7 @@ function getRemoteComponentHtml(html) {
1798
2001
  }
1799
2002
 
1800
2003
  // src/react/index.tsx
2004
+ import { RemoteComponentsProvider } from "#internal/react/context";
1801
2005
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
1802
2006
  import { createElement as createElement2 } from "react";
1803
2007
  function RemoteComponent({
@@ -1814,27 +2018,21 @@ function RemoteComponent({
1814
2018
  onError,
1815
2019
  onChange,
1816
2020
  onRequest,
1817
- onResponse
2021
+ onResponse,
2022
+ resolveClientUrl: _resolveClientUrl
1818
2023
  }) {
1819
2024
  const instanceId = useId();
1820
- const name = useMemo(() => {
1821
- if (typeof src === "string") {
1822
- const url2 = new URL(
1823
- src,
1824
- typeof document !== "undefined" ? location.href : DUMMY_FALLBACK
1825
- );
1826
- if (url2.hash) {
1827
- return url2.hash.slice(1);
1828
- }
1829
- } else if (typeof src === "object" && "hash" in src && src.hash) {
1830
- return src.hash.slice(1) || nameProp;
1831
- }
1832
- return nameProp;
1833
- }, [src, nameProp]);
2025
+ const name = useMemo2(
2026
+ () => resolveNameFromSrc(src, nameProp),
2027
+ [src, nameProp]
2028
+ );
1834
2029
  const [data, setData] = useState2(null);
1835
- const url = useMemo(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
2030
+ const url = useMemo2(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
2031
+ const resolveClientUrl = useResolveClientUrl(_resolveClientUrl, url.href);
1836
2032
  const id = url.origin === (typeof location !== "undefined" ? location.origin : DUMMY_FALLBACK) ? url.pathname : url.href;
1837
- const keySuffix = `${escapeString(id)}_${escapeString(data?.name ?? name)}_${escapeString(instanceId)}`;
2033
+ const keySuffix = `${escapeString(id)}_${escapeString(
2034
+ data?.name ?? name
2035
+ )}_${escapeString(instanceId)}`;
1838
2036
  const [remoteComponent, setRemoteComponent] = useState2(null);
1839
2037
  const { shadowRoot, shadowRootContainerRef } = useShadowRoot({
1840
2038
  isolate,
@@ -1860,13 +2058,10 @@ function RemoteComponent({
1860
2058
  return elements;
1861
2059
  })() : []
1862
2060
  );
1863
- const prevSrcRef = useRef2(null);
2061
+ const hostStateRef = useRef2(createHostState());
1864
2062
  const componentHydrationHtml = useRef2(null);
1865
- const prevIsRemoteComponentRef = useRef2(false);
1866
- const prevUrlRef = useRef2(null);
1867
2063
  const prevRemoteComponentContainerRef = useRef2(null);
1868
2064
  const unmountRef = useRef2(null);
1869
- const prevNameRef = useRef2(void 0);
1870
2065
  useLayoutEffect2(() => {
1871
2066
  const shadowRootKey = `__remote_components_shadowroot_${keySuffix}`;
1872
2067
  return () => {
@@ -1905,14 +2100,18 @@ function RemoteComponent({
1905
2100
  }
1906
2101
  }, [shadowRoot, remoteComponent, name]);
1907
2102
  useEffect(() => {
1908
- if (src && src !== prevSrcRef.current) {
1909
- const previousSrc = prevSrcRef.current;
1910
- const previousName = prevNameRef.current;
1911
- prevSrcRef.current = src;
2103
+ if (src && src !== hostStateRef.current.prevSrc) {
2104
+ const previousSrc = hostStateRef.current.prevSrc;
2105
+ const previousName = hostStateRef.current.prevName;
2106
+ hostStateRef.current.prevSrc = src;
1912
2107
  if (previousSrc !== null) {
1913
2108
  htmlRef.current = null;
1914
2109
  }
2110
+ hostStateRef.current.abortController?.abort();
2111
+ hostStateRef.current.abortController = new AbortController();
2112
+ const { signal } = hostStateRef.current.abortController;
1915
2113
  onBeforeLoad?.(src);
2114
+ hostStateRef.current.stage = "loading";
1916
2115
  startTransition(async () => {
1917
2116
  try {
1918
2117
  let html = getRemoteComponentHtml(
@@ -1922,86 +2121,45 @@ function RemoteComponent({
1922
2121
  const fetchInit = {
1923
2122
  credentials
1924
2123
  };
1925
- const abortController = new AbortController();
1926
- const res = await fetchWithHooks(url, fetchInit, {
2124
+ const resolvedUrl = new URL(
2125
+ resolveClientUrl?.(url.href) ?? url.href,
2126
+ location.href
2127
+ );
2128
+ const res = await fetchWithHooks(resolvedUrl, fetchInit, {
1927
2129
  onRequest,
1928
2130
  onResponse,
1929
- abortController
2131
+ abortController: hostStateRef.current.abortController
1930
2132
  });
1931
2133
  if (!res || !res.ok) {
1932
- let error = failedToFetchRemoteComponentError(
1933
- url.href,
1934
- res ?? new Response(null, { status: 0 })
1935
- );
1936
- try {
1937
- const body = await res.text();
1938
- const parser2 = new DOMParser();
1939
- const doc2 = parser2.parseFromString(body, "text/html");
1940
- const errorTemplate = doc2.querySelector(
1941
- "template[data-next-error-message]"
1942
- );
1943
- const errorMessage = errorTemplate?.getAttribute(
1944
- "data-next-error-message"
1945
- );
1946
- const errorStack = errorTemplate?.getAttribute(
1947
- "data-next-error-stack"
1948
- );
1949
- if (errorMessage) {
1950
- error = new RemoteComponentsError(errorMessage);
1951
- if (errorStack) {
1952
- error.stack = errorStack;
1953
- }
1954
- }
1955
- } catch (parseError) {
1956
- if (isAbortError(parseError))
1957
- throw parseError;
1958
- }
1959
- throw error;
2134
+ throw await errorFromFailedFetch(url.href, resolvedUrl, res);
1960
2135
  }
1961
2136
  const remoteHtml = await res.text();
2137
+ if (signal.aborted)
2138
+ return;
1962
2139
  htmlRef.current = remoteHtml;
1963
2140
  html = getRemoteComponentHtml(remoteHtml);
1964
2141
  }
2142
+ if (signal.aborted)
2143
+ return;
1965
2144
  const parser = new DOMParser();
1966
2145
  const doc = parser.parseFromString(html, "text/html");
1967
- if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(
1968
- `div[data-bundle][data-route][id^="${name}"]`
1969
- ) || doc.querySelectorAll("remote-component:not([src])").length > 1 && !doc.querySelector(`remote-component[name="${name}"]`)) {
1970
- throw multipleRemoteComponentsError(url.href);
1971
- }
1972
- 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
1973
- doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
1974
- doc.querySelector("div#__next") ?? // fallback to the remote-component web component
1975
- doc.querySelector(`remote-component[name="${name}"]:not([src])`) ?? doc.querySelector("remote-component:not([src])");
1976
- const nextData = JSON.parse(
1977
- (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
1978
- );
1979
- const remoteName = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : name);
1980
- const rsc = doc.querySelector(`#${remoteName}_rsc`);
1981
- const bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default";
1982
- const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
1983
- const metadata = {
2146
+ const {
2147
+ component,
1984
2148
  name: remoteName,
1985
- bundle,
1986
- route: component?.getAttribute("data-route") ?? nextData?.page ?? (url.pathname || DEFAULT_ROUTE),
1987
- runtime: component?.getAttribute("data-runtime") ?? (nextData?.props.__REMOTE_COMPONENT__?.runtime || RUNTIME_SCRIPT)
1988
- };
1989
- const remoteSharedEl = doc.querySelector(
1990
- `#${remoteName}_shared[data-remote-components-shared]`
1991
- );
1992
- const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
1993
- remoteSharedEl?.remove();
1994
- if (!component || !(rsc || nextData || isRemoteComponent)) {
1995
- throw new RemoteComponentsError(
1996
- `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>?`
1997
- );
1998
- }
1999
- if (prevIsRemoteComponentRef.current) {
2149
+ isRemoteComponent,
2150
+ metadata,
2151
+ nextData,
2152
+ rsc,
2153
+ remoteShared,
2154
+ links: linkElements,
2155
+ scripts: scriptElements
2156
+ } = parseRemoteComponentDocument(doc, name, url);
2157
+ if (hostStateRef.current.prevIsRemoteComponent) {
2000
2158
  if (shadowRoot) {
2001
2159
  shadowRoot.innerHTML = "";
2002
2160
  }
2003
2161
  const self = globalThis;
2004
- const prevUrl = prevUrlRef.current;
2162
+ const prevUrl = hostStateRef.current.prevUrl;
2005
2163
  if (prevUrl && self.__remote_script_entrypoint_unmount__?.[prevUrl.href]) {
2006
2164
  const unmountPromises = Promise.all(
2007
2165
  Array.from(unmountRef.current ?? []).map(
@@ -2014,15 +2172,11 @@ function RemoteComponent({
2014
2172
  await unmountPromises;
2015
2173
  }
2016
2174
  }
2017
- prevIsRemoteComponentRef.current = isRemoteComponent;
2018
- prevUrlRef.current = url;
2019
- prevNameRef.current = remoteName;
2020
- applyOriginToNodes(doc, url);
2021
- const links = Array.from(
2022
- doc.querySelectorAll("link[href]")
2023
- ).filter((link) => {
2024
- return !component.contains(link);
2025
- }).map((link) => ({
2175
+ hostStateRef.current.prevIsRemoteComponent = isRemoteComponent;
2176
+ hostStateRef.current.prevUrl = url;
2177
+ hostStateRef.current.prevName = remoteName;
2178
+ applyOriginToNodes(doc, url, resolveClientUrl);
2179
+ const links = linkElements.map((link) => ({
2026
2180
  href: new URL(link.getAttribute("href") ?? link.href, url).href,
2027
2181
  ...link.getAttributeNames().reduce((acc, key) => {
2028
2182
  if (key !== "href") {
@@ -2031,7 +2185,7 @@ function RemoteComponent({
2031
2185
  return acc;
2032
2186
  }, {})
2033
2187
  }));
2034
- const scripts = (isRemoteComponent ? component : doc).querySelectorAll("script[src],script[data-src]");
2188
+ const scripts = scriptElements;
2035
2189
  const inlineScripts = (isRemoteComponent ? component : doc).querySelectorAll(
2036
2190
  "script:not([src]):not([data-src]):not([id*='_rsc']):not([id='__NEXT_DATA__']):not([id='__REMOTE_NEXT_DATA__'])"
2037
2191
  );
@@ -2122,7 +2276,7 @@ function RemoteComponent({
2122
2276
  );
2123
2277
  }
2124
2278
  if (isRemoteComponent) {
2125
- if (previousSrc !== null) {
2279
+ if (previousSrc !== void 0) {
2126
2280
  onChange?.({
2127
2281
  previousSrc,
2128
2282
  nextSrc: src,
@@ -2141,7 +2295,8 @@ function RemoteComponent({
2141
2295
  setRemoteComponent(null);
2142
2296
  const { mount, unmount } = await loadStaticRemoteComponent(
2143
2297
  Array.from(shadowRoot.querySelectorAll("script")),
2144
- url
2298
+ url,
2299
+ resolveClientUrl
2145
2300
  );
2146
2301
  unmountRef.current = unmount;
2147
2302
  await Promise.all(
@@ -2162,7 +2317,8 @@ function RemoteComponent({
2162
2317
  htmlRef.current = null;
2163
2318
  const { mount, unmount } = await loadStaticRemoteComponent(
2164
2319
  Array.from(component.querySelectorAll("script")),
2165
- url
2320
+ url,
2321
+ resolveClientUrl
2166
2322
  );
2167
2323
  unmountRef.current = unmount;
2168
2324
  await Promise.all(
@@ -2172,12 +2328,13 @@ function RemoteComponent({
2172
2328
  );
2173
2329
  onLoad?.(src);
2174
2330
  }
2331
+ hostStateRef.current.stage = "loaded";
2175
2332
  } else {
2176
2333
  const result = await loadRemoteComponent({
2177
2334
  url,
2178
2335
  name: remoteName,
2179
2336
  rscName,
2180
- bundle,
2337
+ bundle: metadata.bundle,
2181
2338
  route: metadata.route,
2182
2339
  runtime: metadata.runtime,
2183
2340
  data: newData.data,
@@ -2205,13 +2362,14 @@ function RemoteComponent({
2205
2362
  ...userShared
2206
2363
  },
2207
2364
  remoteShared,
2208
- container: shadowRoot
2365
+ container: shadowRoot,
2366
+ resolveClientUrl
2209
2367
  });
2210
2368
  if (rsc) {
2211
2369
  rsc.remove();
2212
2370
  }
2213
2371
  setData(newData);
2214
- if (previousSrc !== null) {
2372
+ if (previousSrc !== void 0) {
2215
2373
  onChange?.({
2216
2374
  previousSrc,
2217
2375
  nextSrc: src,
@@ -2220,17 +2378,21 @@ function RemoteComponent({
2220
2378
  });
2221
2379
  }
2222
2380
  if (result.error) {
2381
+ hostStateRef.current.stage = "error";
2223
2382
  setRemoteComponent(result.error);
2224
2383
  onError?.(result.error);
2225
2384
  } else {
2385
+ hostStateRef.current.stage = "loaded";
2226
2386
  setRemoteComponent(result.component);
2227
2387
  onLoad?.(src);
2228
2388
  }
2229
2389
  }
2230
2390
  } catch (error) {
2231
2391
  if (isAbortError(error)) {
2392
+ hostStateRef.current.stage = "idle";
2232
2393
  return;
2233
2394
  }
2395
+ hostStateRef.current.stage = "error";
2234
2396
  setRemoteComponent(error);
2235
2397
  onError?.(error);
2236
2398
  }
@@ -2251,7 +2413,8 @@ function RemoteComponent({
2251
2413
  onError,
2252
2414
  onChange,
2253
2415
  onRequest,
2254
- onResponse
2416
+ onResponse,
2417
+ resolveClientUrl
2255
2418
  ]);
2256
2419
  if (remoteComponent instanceof Error) {
2257
2420
  throw remoteComponent;
@@ -2260,7 +2423,7 @@ function RemoteComponent({
2260
2423
  name: data?.name || name,
2261
2424
  bundle: data?.bundle || "default",
2262
2425
  route: data?.route || DEFAULT_ROUTE,
2263
- runtime: prevIsRemoteComponentRef.current ? RUNTIME_SCRIPT : data?.runtime || RUNTIME_WEBPACK
2426
+ runtime: hostStateRef.current.prevIsRemoteComponent ? RUNTIME_SCRIPT : data?.runtime || RUNTIME_WEBPACK
2264
2427
  }) });
2265
2428
  const resetStyle = reset ? /* @__PURE__ */ jsx2("style", { "data-remote-components-reset": "react", children: `:host { all: initial; }` }) : null;
2266
2429
  const linksToRender = data?.links?.map((link) => /* @__PURE__ */ createElement2(
@@ -2279,10 +2442,11 @@ function RemoteComponent({
2279
2442
  if (componentHydrationHtml.current && shadowRoot && !shadowRoot.innerHTML) {
2280
2443
  shadowRoot.innerHTML = componentHydrationHtml.current;
2281
2444
  componentHydrationHtml.current = null;
2282
- if (prevIsRemoteComponentRef.current) {
2445
+ if (hostStateRef.current.prevIsRemoteComponent) {
2283
2446
  loadStaticRemoteComponent(
2284
2447
  Array.from(shadowRoot.querySelectorAll("script")),
2285
- url
2448
+ url,
2449
+ resolveClientUrl
2286
2450
  ).then(({ mount }) => {
2287
2451
  return Promise.all(
2288
2452
  Array.from(mount).map((mountFn) => mountFn(shadowRoot))
@@ -2365,6 +2529,9 @@ function RemoteComponent({
2365
2529
  ] });
2366
2530
  }
2367
2531
 
2532
+ // src/next/host/client/index.tsx
2533
+ import { RemoteComponentsProvider as RemoteComponentsProvider2 } from "#internal/react/context";
2534
+
2368
2535
  // src/next/host/app-router-compat.tsx
2369
2536
  import { usePathname, useSearchParams } from "next/navigation";
2370
2537
  import { jsx as jsx3 } from "react/jsx-runtime";
@@ -2474,6 +2641,7 @@ function RemoteComponent2(props) {
2474
2641
  return /* @__PURE__ */ jsx4(RemoteComponent, { ...props, shared: sharedModules(props.shared) });
2475
2642
  }
2476
2643
  export {
2477
- RemoteComponent2 as RemoteComponent
2644
+ RemoteComponent2 as RemoteComponent,
2645
+ RemoteComponentsProvider2 as RemoteComponentsProvider
2478
2646
  };
2479
2647
  //# sourceMappingURL=index.js.map