remote-components 0.2.0 → 0.2.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 (80) hide show
  1. package/dist/config/nextjs.cjs +1 -1
  2. package/dist/config/nextjs.cjs.map +1 -1
  3. package/dist/config/nextjs.js +1 -1
  4. package/dist/config/nextjs.js.map +1 -1
  5. package/dist/host/html.cjs +19 -17
  6. package/dist/host/html.cjs.map +1 -1
  7. package/dist/host/html.js +19 -17
  8. package/dist/host/html.js.map +1 -1
  9. package/dist/host/nextjs/app/client-only.cjs +93 -59
  10. package/dist/host/nextjs/app/client-only.cjs.map +1 -1
  11. package/dist/host/nextjs/app/client-only.d.ts +28 -9
  12. package/dist/host/nextjs/app/client-only.js +91 -58
  13. package/dist/host/nextjs/app/client-only.js.map +1 -1
  14. package/dist/host/nextjs/pages.cjs +4 -4
  15. package/dist/host/nextjs/pages.cjs.map +1 -1
  16. package/dist/host/nextjs/pages.js +4 -4
  17. package/dist/host/nextjs/pages.js.map +1 -1
  18. package/dist/host/react.cjs +33 -23
  19. package/dist/host/react.cjs.map +1 -1
  20. package/dist/host/react.d.ts +2 -366
  21. package/dist/host/react.js +33 -23
  22. package/dist/host/react.js.map +1 -1
  23. package/dist/index-4c65355c.d.ts +298 -0
  24. package/dist/internal/config/webpack/apply-shared-modules.cjs +6 -2
  25. package/dist/internal/config/webpack/apply-shared-modules.cjs.map +1 -1
  26. package/dist/internal/config/webpack/apply-shared-modules.js +6 -2
  27. package/dist/internal/config/webpack/apply-shared-modules.js.map +1 -1
  28. package/dist/internal/config/webpack/next-client-pages-loader.d.ts +3 -3
  29. package/dist/internal/host/nextjs/app-client.cjs +4 -3
  30. package/dist/internal/host/nextjs/app-client.cjs.map +1 -1
  31. package/dist/internal/host/nextjs/app-client.d.ts +1 -1
  32. package/dist/internal/host/nextjs/app-client.js +4 -3
  33. package/dist/internal/host/nextjs/app-client.js.map +1 -1
  34. package/dist/internal/host/nextjs/image-impl.cjs +8 -4
  35. package/dist/internal/host/nextjs/image-impl.cjs.map +1 -1
  36. package/dist/internal/host/nextjs/image-impl.d.ts +2 -2
  37. package/dist/internal/host/nextjs/image-impl.js +8 -4
  38. package/dist/internal/host/nextjs/image-impl.js.map +1 -1
  39. package/dist/internal/host/react/context.cjs +5 -10
  40. package/dist/internal/host/react/context.cjs.map +1 -1
  41. package/dist/internal/host/react/context.d.ts +7 -18
  42. package/dist/internal/host/react/context.js +4 -9
  43. package/dist/internal/host/react/context.js.map +1 -1
  44. package/dist/internal/host/react/hooks/use-resolve-client-url.cjs +5 -4
  45. package/dist/internal/host/react/hooks/use-resolve-client-url.cjs.map +1 -1
  46. package/dist/internal/host/react/hooks/use-resolve-client-url.d.ts +4 -1
  47. package/dist/internal/host/react/hooks/use-resolve-client-url.js +5 -4
  48. package/dist/internal/host/react/hooks/use-resolve-client-url.js.map +1 -1
  49. package/dist/internal/host/shared/config.cjs.map +1 -1
  50. package/dist/internal/host/shared/config.d.ts +7 -0
  51. package/dist/internal/host/shared/resolved-data.d.ts +2 -2
  52. package/dist/internal/runtime/loaders/component-loader.d.ts +1 -1
  53. package/dist/internal/runtime/loaders/script-loader.cjs +1 -6
  54. package/dist/internal/runtime/loaders/script-loader.cjs.map +1 -1
  55. package/dist/internal/runtime/loaders/script-loader.js +4 -9
  56. package/dist/internal/runtime/loaders/script-loader.js.map +1 -1
  57. package/dist/internal/runtime/turbopack/chunk-loader.cjs +1 -6
  58. package/dist/internal/runtime/turbopack/chunk-loader.cjs.map +1 -1
  59. package/dist/internal/runtime/turbopack/chunk-loader.js +4 -9
  60. package/dist/internal/runtime/turbopack/chunk-loader.js.map +1 -1
  61. package/dist/internal/runtime/turbopack/shared-modules.cjs +3 -2
  62. package/dist/internal/runtime/turbopack/shared-modules.cjs.map +1 -1
  63. package/dist/internal/runtime/turbopack/shared-modules.js +3 -2
  64. package/dist/internal/runtime/turbopack/shared-modules.js.map +1 -1
  65. package/dist/internal/utils/error.cjs +7 -0
  66. package/dist/internal/utils/error.cjs.map +1 -1
  67. package/dist/internal/utils/error.d.ts +2 -1
  68. package/dist/internal/utils/error.js +6 -0
  69. package/dist/internal/utils/error.js.map +1 -1
  70. package/dist/internal/utils/logger.cjs +1 -1
  71. package/dist/internal/utils/logger.cjs.map +1 -1
  72. package/dist/internal/utils/logger.d.ts +1 -1
  73. package/dist/internal/utils/logger.js +1 -1
  74. package/dist/internal/utils/logger.js.map +1 -1
  75. package/dist/remote/html.cjs +1 -1
  76. package/dist/remote/html.cjs.map +1 -1
  77. package/dist/remote/html.js +1 -1
  78. package/dist/remote/html.js.map +1 -1
  79. package/dist/{server-handoff-8c89b856.d.ts → server-handoff-ce13bebc.d.ts} +2 -2
  80. package/package.json +1 -9
@@ -1,366 +1,2 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
-
3
- /**
4
- * Intercepts client-side URL resolution for remote component resources.
5
- * Called before each asset (script, stylesheet, chunk, module, image) is fetched.
6
- *
7
- * Return a new URL string to redirect the fetch (e.g., through a proxy),
8
- * or undefined to use the original URL.
9
- *
10
- * @param remoteSrc - The `src` of the remote component being loaded
11
- * @param url - The asset URL about to be fetched
12
- *
13
- * @example
14
- * // Proxy all assets from the remote's origin through the host
15
- * const resolveClientUrl = (remoteSrc, url) => {
16
- * const remoteOrigin = new URL(remoteSrc).origin;
17
- * const parsed = new URL(url);
18
- * if (parsed.origin !== location.origin && parsed.origin === remoteOrigin) {
19
- * return `/rc-fetch-protected-remote?url=${encodeURIComponent(url)}`;
20
- * }
21
- * };
22
- */
23
- type ResolveClientUrl = (remoteSrc: string, url: string) => string | undefined;
24
- /**
25
- * Internal bound resolver — `ResolveClientUrl` with `remoteSrc` already applied.
26
- * Used by internal loaders that don't need to know the remote src.
27
- */
28
- type InternalResolveClientUrl = (url: string) => string | undefined;
29
-
30
- /**
31
- * Hook types for intercepting remote component fetch requests and responses.
32
- *
33
- * These are part of the public host configuration surface ({@link ConsumeServerConfig})
34
- * and are used by both SSR and client-side host implementations.
35
- */
36
- /**
37
- * Options object passed to hook functions containing abort capabilities.
38
- * Uses standard AbortController/AbortSignal for compatibility with Web APIs.
39
- *
40
- * @example
41
- * // Abort on redirect
42
- * component.onResponse = (url, response, { signal, abort }) => {
43
- * if (response.redirected) {
44
- * abort();
45
- * }
46
- * };
47
- *
48
- * @example
49
- * // Check if already aborted
50
- * component.onRequest = (url, init, { signal }) => {
51
- * if (signal.aborted) return;
52
- * // ...
53
- * };
54
- *
55
- * @example
56
- * // Pass signal to fetch or other APIs
57
- * component.onRequest = async (url, init, { signal }) => {
58
- * const data = await fetch('/api/check', { signal });
59
- * // ...
60
- * };
61
- */
62
- interface HookOptions {
63
- /** Standard AbortSignal - can be passed to fetch and other Web APIs */
64
- signal: AbortSignal;
65
- /** Abort loading - prevents further processing and DOM attachment */
66
- abort(reason?: unknown): void;
67
- }
68
- /**
69
- * Hook function that intercepts remote component fetch requests.
70
- * Can be used to modify request options, provide a custom response, inspect the request,
71
- * or abort loading.
72
- *
73
- * @param url - The URL being fetched
74
- * @param init - The fetch init options being used
75
- * @param options - Options object containing the abort signal
76
- * @returns Optional Response to use instead of fetching, or void/undefined to proceed with normal fetch
77
- *
78
- * @example
79
- * // Log all remote component requests
80
- * const onRequest = async (url, init, { abort }) => {
81
- * console.log('Fetching remote component from:', url.href);
82
- * };
83
- *
84
- * @example
85
- * // Add custom headers
86
- * const onRequest = async (url, init) => {
87
- * (init.headers as Headers).set('X-Custom-Header', 'value');
88
- * };
89
- *
90
- * @example
91
- * // Provide a cached response
92
- * const onRequest = async (url) => {
93
- * const cached = cache.get(url.href);
94
- * if (cached) {
95
- * return new Response(cached);
96
- * }
97
- * };
98
- *
99
- * @example
100
- * // Block certain domains
101
- * const onRequest = async (url, init, { abort }) => {
102
- * if (isBlockedDomain(url)) {
103
- * abort('Domain is blocked');
104
- * }
105
- * };
106
- */
107
- type OnRequestHook = (url: URL, init: RequestInit, options: HookOptions) => Promise<Response | undefined> | Response | undefined;
108
- /**
109
- * Hook function that is called after a remote component fetch completes.
110
- * Can be used to inspect the response, check for redirects, transform the response,
111
- * or abort loading.
112
- *
113
- * @param url - The original URL that was requested
114
- * @param response - The Response object from the fetch
115
- * @param options - Options object containing the abort signal
116
- * @returns Optional Response to use instead of the original, or void/undefined to use the original response
117
- *
118
- * @example
119
- * // Check for redirects and abort
120
- * const onResponse = async (url, response, { abort }) => {
121
- * if (response.redirected) {
122
- * console.log(`Redirected from ${url.href} to ${response.url}`);
123
- * abort();
124
- * }
125
- * };
126
- *
127
- * @example
128
- * // Cache the response
129
- * const onResponse = async (url, response) => {
130
- * const cloned = response.clone();
131
- * cache.set(url.href, await cloned.text());
132
- * };
133
- *
134
- * @example
135
- * // Transform the response
136
- * const onResponse = async (url, response) => {
137
- * const text = await response.text();
138
- * const modified = text.replace(/foo/g, 'bar');
139
- * return new Response(modified, response);
140
- * };
141
- *
142
- * @example
143
- * // Abort on redirect to legacy routes
144
- * const onResponse = async (url, response, { abort }) => {
145
- * if (response.redirected && isLegacyRoute(response.url)) {
146
- * window.location.href = toLegacyUrl(response.url);
147
- * abort(); // Abort rendering - no flash!
148
- * }
149
- * };
150
- */
151
- type OnResponseHook = (url: URL, response: Response, options: HookOptions) => Promise<Response | undefined> | Response | undefined;
152
-
153
- /**
154
- * Configuration for Shadow DOM isolation of a remote component.
155
- *
156
- * Used by both the public {@link ConsumeRemoteComponentConfig} (user-facing props) and
157
- * {@link ConsumeServerData} (internal runtime data) to control
158
- * whether and how the remote component is wrapped in a shadow root.
159
- */
160
- interface ShadowDomConfig {
161
- /** Whether to isolate the remote component using a Shadow DOM wrapper. */
162
- isolate?: boolean;
163
- /** The Shadow DOM mode. Defaults to `'open'`. */
164
- mode?: 'open' | 'closed';
165
- /** Whether to include a CSS reset style in the Shadow DOM. Defaults to `false`. */
166
- reset?: boolean;
167
- }
168
- /**
169
- * Configuration accepted by server-rendered embed hosts (e.g. the Next.js App Router
170
- * `<ConsumeRemoteComponent>`). This is the minimal, serializable subset — no client-side
171
- * asset fetching fields, no lifecycle callbacks.
172
- *
173
- * `src` is optional here because not every host has a source at construction
174
- * time (e.g. the React host during SSR hydration, or a `<remote-component>`
175
- * element before its `src` attribute is set). Frameworks that require `src`
176
- * narrow it to required in their own props type.
177
- */
178
- interface ConsumeServerConfig extends ShadowDomConfig {
179
- /** The source URL of the remote component. Relative or absolute. */
180
- src?: string | URL;
181
- /** Selects a named remote component when multiple are exposed on a single page. */
182
- name?: string;
183
- /** Intercepts fetch requests before they are sent. */
184
- onRequest?: OnRequestHook;
185
- /** Inspects or transforms fetch responses after they arrive. */
186
- onResponse?: OnResponseHook;
187
- }
188
- /**
189
- * Client-only configuration fields — the subset of {@link ConsumeClientConfig}
190
- * that applies only to client-side asset fetching. Used directly in contexts where
191
- * the full server config is already present (e.g. {@link ConsumeRemoteComponentClient}).
192
- */
193
- interface ConsumeClientOnlyConfig {
194
- /** The credentials mode for the fetch request. Defaults to `'same-origin'`. */
195
- credentials?: RequestCredentials;
196
- /**
197
- * Rewrites client-side asset URLs (scripts, stylesheets, chunks, modules, images).
198
- * Return a new URL string to redirect the request (e.g. through a proxy),
199
- * or `undefined` to use the original URL.
200
- */
201
- resolveClientUrl?: ResolveClientUrl;
202
- }
203
- /**
204
- * Configuration accepted by client-side embed hosts (React host, Pages Router host,
205
- * HTML host). Extends {@link ConsumeServerConfig} with fields for
206
- * client-side asset fetching (`credentials`, `resolveClientUrl`).
207
- */
208
- interface ConsumeClientConfig extends ConsumeServerConfig, ConsumeClientOnlyConfig {
209
- }
210
- /**
211
- * Complete configuration for client-side embed hosts (React host, Pages Router host).
212
- * Combines {@link ConsumeClientConfig} with {@link ConsumeLifecycleCallbacks}.
213
- *
214
- * This is the base type for public-facing props on hosts that fetch and mount
215
- * remote components on the client. The App Router server host uses only
216
- * {@link ConsumeServerConfig} since RSC cannot accept function callbacks.
217
- */
218
- interface ConsumeRemoteComponentConfig extends ConsumeClientConfig, ConsumeLifecycleCallbacks {
219
- }
220
- /** Information provided to the `onChange` lifecycle callback. */
221
- interface ChangeInfo {
222
- previousSrc: string | URL | null;
223
- nextSrc: string | URL | null;
224
- previousName: string | undefined;
225
- nextName: string | undefined;
226
- }
227
- /**
228
- * Lifecycle callbacks shared by host and remote component implementations.
229
- *
230
- * On the host side, these fire during client-side loading (the React host
231
- * exposes them as callback props; the HTML host dispatches DOM events).
232
- * On the remote side (Next.js `<ExposeRemoteComponent>` wrapper), the callbacks
233
- * are forwarded as `data-on-*` attributes so the host can wire them up.
234
- *
235
- * Server-only components (e.g. Next.js App Router server host) do not
236
- * support these callbacks since they render once on the server.
237
- */
238
- interface ConsumeLifecycleCallbacks {
239
- /** Called right before a new remote component load starts. */
240
- onBeforeLoad?: (src: string | URL) => void;
241
- /** Called when the remote component has been successfully loaded and mounted. */
242
- onLoad?: (src: string | URL) => void;
243
- /** Called when an error occurs while loading or mounting the remote component. */
244
- onError?: (error: unknown) => void;
245
- /** Called when a different remote component is loaded into the same wrapper. */
246
- onChange?: (info: ChangeInfo) => void;
247
- }
248
-
249
- /**
250
- * Metadata embedded in the HTML response by a remote application.
251
- *
252
- * Extracted from a `<script type="application/json" data-remote-component>`
253
- * element during both SSR parsing ({@link fetchRemoteComponent}) and
254
- * client-side parsing ({@link parseRemoteComponentDocument}).
255
- */
256
- interface RemoteComponentMetadata {
257
- bundle: string;
258
- route: string;
259
- runtime: 'webpack' | 'turbopack' | 'script';
260
- id: string;
261
- type: 'nextjs' | 'remote-component' | 'unknown';
262
- }
263
-
264
- /**
265
- * Serialized descriptor for a `<script>` element extracted from a remote
266
- * component response. Used in both SSR fetch results and client-side props.
267
- */
268
- interface ScriptDescriptor {
269
- /** The script `src` URL. Empty string for inline scripts. */
270
- src: string;
271
- /** Inline script content (only present for scripts without a `src`). */
272
- textContent?: string;
273
- }
274
-
275
- /**
276
- * The subset of the remote component fetch response that the client-side
277
- * loader needs to hydrate or mount a remote component.
278
- *
279
- * Both {@link ConsumeServerData} and {@link ConsumeLoaderProps}
280
- * compose this interface — it is the shared base for the RSC→client handoff
281
- * and the loader function arguments.
282
- */
283
- interface ConsumeLoaderPayload {
284
- name: string;
285
- bundle: string;
286
- route?: string;
287
- runtime?: RemoteComponentMetadata['runtime'];
288
- data: string[];
289
- nextData?: {
290
- props: {
291
- pageProps: Record<string, unknown>;
292
- };
293
- buildId?: string;
294
- } | null;
295
- scripts?: ScriptDescriptor[];
296
- remoteShared?: Record<string, string>;
297
- }
298
-
299
- /**
300
- * Props accepted by {@link loadRemoteComponent}.
301
- *
302
- * Extends {@link ConsumeLoaderPayload} (the SSR-resolved fields needed for
303
- * hydration) with loader-specific fields (`url`, `shared`, `container`, etc.).
304
- * `remoteShared` is narrowed from optional to required (defaults to `{}` at
305
- * the call site).
306
- */
307
- interface ConsumeLoaderProps extends ConsumeLoaderPayload {
308
- url: URL;
309
- shared: Promise<Record<string, (bundle?: string) => Promise<unknown>>> | Record<string, (bundle?: string) => Promise<unknown>>;
310
- remoteShared: Record<string, string>;
311
- container?: HTMLHeadElement | ShadowRoot | null;
312
- rscName?: string;
313
- resolveClientUrl?: InternalResolveClientUrl;
314
- }
315
-
316
- /**
317
- * Props for the React remote component host.
318
- *
319
- * Extends {@link ConsumeRemoteComponentConfig} with `shared` for module sharing and
320
- * `children` for loading fallback content.
321
- */
322
- interface ConsumeRemoteComponentProps extends ConsumeRemoteComponentConfig {
323
- /** Shared modules to include in the remote component's context. */
324
- shared?: ConsumeLoaderProps['shared'];
325
- /** Loading fallback content displayed while the remote component is being fetched. */
326
- children?: React.ReactNode;
327
- }
328
- /**
329
- * ConsumeRemoteComponent is a React component that fetches and renders a remote component.
330
- * It supports SSR and can isolate the remote component in a shadow DOM.
331
- *
332
- * @param props - The properties for the remote component.
333
- * @returns A React component that renders the remote component.
334
- *
335
- * @example
336
- *
337
- * Use the `<ConsumeRemoteComponent>` in your React application to consume a remote component from a remote application:
338
- *
339
- * ```tsx
340
- * import { ConsumeRemoteComponent } from 'remote-components/host/react';
341
- *
342
- * export default function App() {
343
- * return (
344
- * <>
345
- * <h1>Welcome to My App</h1>
346
- * <p>This page consumes a remote component from another application.</p>
347
- * <ConsumeRemoteComponent src="/nextjs-app-remote/components/header" />
348
- * </>
349
- * );
350
- * }
351
- * ```
352
- *
353
- * To share modules, you can provide a shared module map with references to the shared modules:
354
- *
355
- * ```tsx
356
- * <ConsumeRemoteComponent
357
- * src="/nextjs-app-remote/components/header"
358
- * shared={{
359
- * '@/components/provider': () => import('@/components/host-provider')
360
- * }}
361
- * />
362
- * ```
363
- */
364
- declare function ConsumeRemoteComponent({ src, isolate, mode, reset, credentials, name: nameProp, shared, children, onBeforeLoad, onLoad, onError, onChange, onRequest, onResponse, resolveClientUrl: _resolveClientUrl, }: ConsumeRemoteComponentProps): react_jsx_runtime.JSX.Element;
365
-
366
- export { ConsumeRemoteComponent, ConsumeRemoteComponentProps, HookOptions, OnRequestHook, OnResponseHook };
1
+ import 'react/jsx-runtime';
2
+ export { b as ConsumeRemoteComponent, a as ConsumeRemoteComponentProps, H as HookOptions, O as OnRequestHook, c as OnResponseHook } from '../index-4c65355c.js';
@@ -9,6 +9,7 @@ import {
9
9
  useState as useState2
10
10
  } from "react";
11
11
  import { createPortal } from "react-dom";
12
+ import { useRemoteComponentsContext as useRemoteComponentsContext2 } from "#internal/host/react/context";
12
13
 
13
14
  // src/utils/constants.ts
14
15
  var RC_PROTECTED_REMOTE_FETCH_PATHNAME = "/rc-fetch-protected-remote";
@@ -93,6 +94,11 @@ async function errorFromFailedFetch(originalUrl, resolvedUrl, res) {
93
94
  }
94
95
  return fallback;
95
96
  }
97
+ function failedProxiedAssetError(kind, url, resolvedUrl) {
98
+ return new RemoteComponentsError(
99
+ `Failed to load ${kind} "${url}" via proxy "${resolvedUrl}". Ensure withRemoteComponentsHostProxy middleware is configured, "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" is in the matcher, and the remote URL is included in allowedProxyUrls. See: ${CORS_DOCS_URL}`
100
+ );
101
+ }
96
102
  function failedProxyFetchError(originalUrl, proxyUrl, status, responseBody) {
97
103
  if (status === 404) {
98
104
  return new RemoteComponentsError(
@@ -144,7 +150,7 @@ function warnCrossOriginFetchError(logLocation, url) {
144
150
  }
145
151
  logWarn(
146
152
  logLocation,
147
- `Failed to fetch cross-origin resource "${parsed.href}". If this is a protected deployment, ensure withRemoteComponentsHostProxy middleware is configured in your host and that the remote URL is included in allowedProxyUrls. See: ${CORS_DOCS_URL}`
153
+ `Failed to fetch cross-origin resource "${parsed.href}". To load assets from a protected deployment, two steps are required: (1) configure withRemoteComponentsHostProxy middleware in your host with the remote URL in allowedProxyUrls, and (2) provide a resolveClientUrl prop that rewrites cross-origin asset URLs to go through the proxy. See: ${CORS_DOCS_URL}`
148
154
  );
149
155
  } catch {
150
156
  }
@@ -657,6 +663,7 @@ import * as ReactDOM from "react-dom";
657
663
  import * as ReactDOMClient from "react-dom/client";
658
664
 
659
665
  // src/config/webpack/apply-shared-modules.ts
666
+ var DEDUPLICATION_SKIPPED = "shared module deduplication skipped. The remote may load its own copy of shared dependencies.";
660
667
  function applySharedModules(bundle, resolve) {
661
668
  logDebug(
662
669
  "SharedModules",
@@ -700,13 +707,16 @@ function applySharedModules(bundle, resolve) {
700
707
  } else {
701
708
  logWarn(
702
709
  "SharedModules",
703
- `webpackBundle.m is not available for bundle "${bundle}"`
710
+ `webpackBundle.m is not available for bundle "${bundle}" \u2014 ${DEDUPLICATION_SKIPPED}`
704
711
  );
705
712
  }
706
713
  }
707
714
  }
708
715
  } else {
709
- logWarn("SharedModules", `No webpack require found for bundle "${bundle}"`);
716
+ logWarn(
717
+ "SharedModules",
718
+ `No webpack require found for bundle "${bundle}" \u2014 ${DEDUPLICATION_SKIPPED}`
719
+ );
710
720
  logDebug(
711
721
  "SharedModules",
712
722
  `Available bundles: ${Object.keys(self.__remote_webpack_require__ ?? {})}`
@@ -960,11 +970,7 @@ function createChunkLoader(runtime, resolveClientUrl) {
960
970
  }).then(resolve).catch((error) => {
961
971
  const isProxied = isProxiedUrl(resolvedUrl);
962
972
  if (isProxied) {
963
- reject(
964
- new RemoteComponentsError(
965
- `Failed to load chunk "${url}" via proxy "${resolvedUrl}". Ensure withRemoteComponentsHostProxy middleware is configured and "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" is in the matcher. See: ${CORS_DOCS_URL}`
966
- )
967
- );
973
+ reject(failedProxiedAssetError("chunk", url, resolvedUrl));
968
974
  } else {
969
975
  warnCrossOriginFetchError("ChunkLoader", url);
970
976
  reject(error);
@@ -1342,6 +1348,7 @@ function createTurbopackContext(bundle, exports, moduleExports, modules, moduleI
1342
1348
  }
1343
1349
 
1344
1350
  // src/runtime/turbopack/shared-modules.ts
1351
+ var DEDUPLICATION_WARNING = "This module will not be deduplicated \u2014 the remote may load its own copy, which can cause duplicate instance errors (e.g. invalid hook calls if React is loaded twice).";
1345
1352
  async function initializeSharedModules(bundle, hostShared = {}, remoteShared = {}) {
1346
1353
  const self = globalThis;
1347
1354
  self.__remote_shared_modules__ = self.__remote_shared_modules__ ?? {};
@@ -1392,7 +1399,7 @@ async function initializeSharedModules(bundle, hostShared = {}, remoteShared = {
1392
1399
  } else {
1393
1400
  logError(
1394
1401
  "SharedModules",
1395
- `Host shared module "${module}" not found for ID ${id}`
1402
+ `Host shared module "${module}" not found for ID ${id}. ${DEDUPLICATION_WARNING}`
1396
1403
  );
1397
1404
  }
1398
1405
  }
@@ -1409,7 +1416,7 @@ async function initializeSharedModules(bundle, hostShared = {}, remoteShared = {
1409
1416
  } else {
1410
1417
  logError(
1411
1418
  "SharedModules",
1412
- `Shared module "${module}" not found for "${bundle}"`
1419
+ `Shared module "${module}" not found for "${bundle}". ${DEDUPLICATION_WARNING}`
1413
1420
  );
1414
1421
  }
1415
1422
  }
@@ -1572,11 +1579,7 @@ async function loadScripts(scripts, resolveClientUrl) {
1572
1579
  newScript.onerror = () => {
1573
1580
  const isProxied = isProxiedUrl(resolvedSrc);
1574
1581
  if (isProxied) {
1575
- reject(
1576
- new RemoteComponentsError(
1577
- `Failed to load script "${newSrc}" via proxy "${resolvedSrc}". Ensure withRemoteComponentsHostProxy middleware is configured and "${RC_PROTECTED_REMOTE_FETCH_PATHNAME}" is in the matcher. See: ${CORS_DOCS_URL}`
1578
- )
1579
- );
1582
+ reject(failedProxiedAssetError("script", newSrc, resolvedSrc));
1580
1583
  } else {
1581
1584
  warnCrossOriginFetchError("ScriptLoader", newSrc);
1582
1585
  reject(
@@ -1911,11 +1914,12 @@ function bindResolveClientUrl(prop, remoteSrc) {
1911
1914
  // src/host/react/hooks/use-resolve-client-url.ts
1912
1915
  function useResolveClientUrl(prop, urlHref) {
1913
1916
  const { resolveClientUrl: contextValue } = useRemoteComponentsContext();
1914
- const resolveClientUrl = prop ?? contextValue;
1915
- return useMemo(
1916
- () => bindResolveClientUrl(resolveClientUrl, urlHref),
1917
- [resolveClientUrl, urlHref]
1917
+ const raw = prop ?? contextValue;
1918
+ const bound = useMemo(
1919
+ () => bindResolveClientUrl(raw, urlHref),
1920
+ [raw, urlHref]
1918
1921
  );
1922
+ return { bound, raw };
1919
1923
  }
1920
1924
 
1921
1925
  // src/host/react/hooks/use-shadow-root.ts
@@ -1997,9 +2001,9 @@ function ConsumeRemoteComponent({
1997
2001
  isolate,
1998
2002
  mode = "open",
1999
2003
  reset,
2000
- credentials = "same-origin",
2004
+ credentials: credentialsProp,
2001
2005
  name: nameProp = "__vercel_remote_component",
2002
- shared = {},
2006
+ shared: sharedProp,
2003
2007
  children,
2004
2008
  onBeforeLoad,
2005
2009
  onLoad,
@@ -2007,9 +2011,12 @@ function ConsumeRemoteComponent({
2007
2011
  onChange,
2008
2012
  onRequest,
2009
2013
  onResponse,
2010
- resolveClientUrl: _resolveClientUrl
2014
+ resolveClientUrl: resolveClientUrlProp
2011
2015
  }) {
2012
2016
  const instanceId = useId();
2017
+ const { credentials: contextCredentials, shared: contextShared } = useRemoteComponentsContext2();
2018
+ const credentials = credentialsProp ?? contextCredentials ?? "same-origin";
2019
+ const shared = sharedProp ?? contextShared ?? {};
2013
2020
  const name = useMemo2(
2014
2021
  () => resolveNameFromSrc(src, nameProp),
2015
2022
  [src, nameProp]
@@ -2018,7 +2025,10 @@ function ConsumeRemoteComponent({
2018
2025
  null
2019
2026
  );
2020
2027
  const url = useMemo2(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
2021
- const resolveClientUrl = useResolveClientUrl(_resolveClientUrl, url.href);
2028
+ const { bound: resolveClientUrl } = useResolveClientUrl(
2029
+ resolveClientUrlProp,
2030
+ url.href
2031
+ );
2022
2032
  const id = url.origin === (typeof location !== "undefined" ? location.origin : DUMMY_FALLBACK) ? url.pathname : url.href;
2023
2033
  const keySuffix = `${escapeString(id)}_${escapeString(
2024
2034
  data?.name ?? name