remote-components 0.4.3 → 0.4.5

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 (139) hide show
  1. package/dist/{chunk-C5EYU7EQ.cjs → chunk-4MLJE6UP.cjs} +3 -3
  2. package/dist/{chunk-SECN7UAL.cjs → chunk-7OD5S534.cjs} +18 -18
  3. package/dist/{chunk-7XXO2DLF.cjs → chunk-I7VKDF3E.cjs} +115 -77
  4. package/dist/chunk-I7VKDF3E.cjs.map +1 -0
  5. package/dist/{chunk-55TEMSB5.js → chunk-JZRA6DPE.js} +116 -78
  6. package/dist/chunk-JZRA6DPE.js.map +1 -0
  7. package/dist/{chunk-HYVNEUIK.js → chunk-MJ2KYXGR.js} +3 -3
  8. package/dist/{chunk-KV5J7PNM.js → chunk-NZM2SI6U.js} +3 -3
  9. package/dist/{chunk-DGZVFKSQ.js → chunk-O4A6CJGI.js} +19 -11
  10. package/dist/chunk-O4A6CJGI.js.map +1 -0
  11. package/dist/{chunk-2W7JBTID.cjs → chunk-PNASFKWA.cjs} +39 -31
  12. package/dist/chunk-PNASFKWA.cjs.map +1 -0
  13. package/dist/{chunk-4NW46ZVD.js → chunk-PT3R275L.js} +93 -38
  14. package/dist/chunk-PT3R275L.js.map +1 -0
  15. package/dist/{chunk-4AH3KXDW.cjs → chunk-TWO3XB6H.cjs} +19 -19
  16. package/dist/{chunk-HMB3SIVJ.cjs → chunk-W5FSHVWU.cjs} +107 -52
  17. package/dist/chunk-W5FSHVWU.cjs.map +1 -0
  18. package/dist/{chunk-HL6BL5HY.js → chunk-WGSS7TJP.js} +2 -2
  19. package/dist/config/nextjs.cjs +98 -30
  20. package/dist/config/nextjs.cjs.map +1 -1
  21. package/dist/config/nextjs.d.ts +14 -1
  22. package/dist/config/nextjs.js +89 -21
  23. package/dist/config/nextjs.js.map +1 -1
  24. package/dist/host/html.cjs +19 -19
  25. package/dist/host/html.cjs.map +1 -1
  26. package/dist/host/html.js +7 -7
  27. package/dist/host/html.js.map +1 -1
  28. package/dist/host/nextjs/app/client-only.cjs +11 -11
  29. package/dist/host/nextjs/app/client-only.js +6 -6
  30. package/dist/host/nextjs/pages.cjs +32 -9
  31. package/dist/host/nextjs/pages.cjs.map +1 -1
  32. package/dist/host/nextjs/pages.js +39 -9
  33. package/dist/host/nextjs/pages.js.map +1 -1
  34. package/dist/host/react.cjs +7 -7
  35. package/dist/host/react.js +6 -6
  36. package/dist/internal/host/nextjs/app-client.d.ts +3 -1
  37. package/dist/internal/host/nextjs/dom-flight.cjs +17 -2
  38. package/dist/internal/host/nextjs/dom-flight.cjs.map +1 -1
  39. package/dist/internal/host/nextjs/dom-flight.d.ts +5 -1
  40. package/dist/internal/host/nextjs/dom-flight.js +18 -2
  41. package/dist/internal/host/nextjs/dom-flight.js.map +1 -1
  42. package/dist/internal/host/server/fetch-remote-component.cjs +4 -2
  43. package/dist/internal/host/server/fetch-remote-component.cjs.map +1 -1
  44. package/dist/internal/host/server/fetch-remote-component.d.ts +2 -0
  45. package/dist/internal/host/server/fetch-remote-component.js +4 -2
  46. package/dist/internal/host/server/fetch-remote-component.js.map +1 -1
  47. package/dist/internal/host/server/types.cjs.map +1 -1
  48. package/dist/internal/host/server/types.d.ts +4 -1
  49. package/dist/internal/host/shared/pipeline.cjs +7 -8
  50. package/dist/internal/host/shared/pipeline.cjs.map +1 -1
  51. package/dist/internal/host/shared/pipeline.d.ts +5 -3
  52. package/dist/internal/host/shared/pipeline.js +9 -8
  53. package/dist/internal/host/shared/pipeline.js.map +1 -1
  54. package/dist/internal/host/shared/shared-broker.cjs +51 -10
  55. package/dist/internal/host/shared/shared-broker.cjs.map +1 -1
  56. package/dist/internal/host/shared/shared-broker.d.ts +19 -3
  57. package/dist/internal/host/shared/shared-broker.js +48 -10
  58. package/dist/internal/host/shared/shared-broker.js.map +1 -1
  59. package/dist/internal/host/shared/shared-module-resolver.cjs.map +1 -1
  60. package/dist/internal/host/shared/shared-module-resolver.d.ts +2 -2
  61. package/dist/internal/host/shared/shared-module-resolver.js.map +1 -1
  62. package/dist/internal/remote/nextjs/app-client.cjs +28 -19
  63. package/dist/internal/remote/nextjs/app-client.cjs.map +1 -1
  64. package/dist/internal/remote/nextjs/app-client.d.ts +6 -1
  65. package/dist/internal/remote/nextjs/app-client.js +20 -11
  66. package/dist/internal/remote/nextjs/app-client.js.map +1 -1
  67. package/dist/internal/runtime/html/html-spec.cjs +6 -0
  68. package/dist/internal/runtime/html/html-spec.cjs.map +1 -1
  69. package/dist/internal/runtime/html/html-spec.d.ts +3 -1
  70. package/dist/internal/runtime/html/html-spec.js +4 -0
  71. package/dist/internal/runtime/html/html-spec.js.map +1 -1
  72. package/dist/internal/runtime/html/parse-remote-html.cjs +7 -1
  73. package/dist/internal/runtime/html/parse-remote-html.cjs.map +1 -1
  74. package/dist/internal/runtime/html/parse-remote-html.d.ts +5 -3
  75. package/dist/internal/runtime/html/parse-remote-html.js +9 -1
  76. package/dist/internal/runtime/html/parse-remote-html.js.map +1 -1
  77. package/dist/internal/runtime/loaders/component-loader.cjs.map +1 -1
  78. package/dist/internal/runtime/loaders/component-loader.d.ts +4 -2
  79. package/dist/internal/runtime/loaders/component-loader.js.map +1 -1
  80. package/dist/internal/runtime/turbopack/chunk-loader.cjs +39 -23
  81. package/dist/internal/runtime/turbopack/chunk-loader.cjs.map +1 -1
  82. package/dist/internal/runtime/turbopack/chunk-loader.js +39 -23
  83. package/dist/internal/runtime/turbopack/chunk-loader.js.map +1 -1
  84. package/dist/internal/runtime/turbopack/patterns.cjs +15 -5
  85. package/dist/internal/runtime/turbopack/patterns.cjs.map +1 -1
  86. package/dist/internal/runtime/turbopack/patterns.d.ts +10 -2
  87. package/dist/internal/runtime/turbopack/patterns.js +13 -4
  88. package/dist/internal/runtime/turbopack/patterns.js.map +1 -1
  89. package/dist/internal/runtime/turbopack/shared-modules.cjs +39 -10
  90. package/dist/internal/runtime/turbopack/shared-modules.cjs.map +1 -1
  91. package/dist/internal/runtime/turbopack/shared-modules.d.ts +2 -2
  92. package/dist/internal/runtime/turbopack/shared-modules.js +43 -11
  93. package/dist/internal/runtime/turbopack/shared-modules.js.map +1 -1
  94. package/dist/remote/defaults/app.cjs +4 -2
  95. package/dist/remote/defaults/app.cjs.map +1 -1
  96. package/dist/remote/defaults/app.d.ts +3 -1
  97. package/dist/remote/defaults/app.js +3 -2
  98. package/dist/remote/defaults/app.js.map +1 -1
  99. package/dist/remote/defaults/pages.cjs +4 -2
  100. package/dist/remote/defaults/pages.cjs.map +1 -1
  101. package/dist/remote/defaults/pages.d.ts +3 -1
  102. package/dist/remote/defaults/pages.js +3 -2
  103. package/dist/remote/defaults/pages.js.map +1 -1
  104. package/dist/remote/defaults/shared.cjs +5 -2
  105. package/dist/remote/defaults/shared.cjs.map +1 -1
  106. package/dist/remote/defaults/shared.d.ts +5 -1
  107. package/dist/remote/defaults/shared.js +3 -1
  108. package/dist/remote/defaults/shared.js.map +1 -1
  109. package/dist/remote/nextjs/pages.cjs +4 -1
  110. package/dist/remote/nextjs/pages.cjs.map +1 -1
  111. package/dist/remote/nextjs/pages.d.ts +5 -0
  112. package/dist/remote/nextjs/pages.js +8 -2
  113. package/dist/remote/nextjs/pages.js.map +1 -1
  114. package/dist/{server-handoff-8c89b856.d.ts → server-handoff-9e905049.d.ts} +2 -1
  115. package/dist/{turbopack-7F757Z7V.js → turbopack-55EJDSUT.js} +4 -4
  116. package/dist/turbopack-55EJDSUT.js.map +1 -0
  117. package/dist/{turbopack-DULMVTWV.cjs → turbopack-Q6KJAEOX.cjs} +11 -11
  118. package/dist/turbopack-Q6KJAEOX.cjs.map +1 -0
  119. package/dist/{webpack-WGVTKJ3W.js → webpack-AQ34DAJZ.js} +4 -4
  120. package/dist/webpack-AQ34DAJZ.js.map +1 -0
  121. package/dist/{webpack-6LXCB7WA.cjs → webpack-FWUNUWLF.cjs} +11 -11
  122. package/dist/webpack-FWUNUWLF.cjs.map +1 -0
  123. package/package.json +1 -1
  124. package/dist/chunk-2W7JBTID.cjs.map +0 -1
  125. package/dist/chunk-4NW46ZVD.js.map +0 -1
  126. package/dist/chunk-55TEMSB5.js.map +0 -1
  127. package/dist/chunk-7XXO2DLF.cjs.map +0 -1
  128. package/dist/chunk-DGZVFKSQ.js.map +0 -1
  129. package/dist/chunk-HMB3SIVJ.cjs.map +0 -1
  130. package/dist/turbopack-7F757Z7V.js.map +0 -1
  131. package/dist/turbopack-DULMVTWV.cjs.map +0 -1
  132. package/dist/webpack-6LXCB7WA.cjs.map +0 -1
  133. package/dist/webpack-WGVTKJ3W.js.map +0 -1
  134. /package/dist/{chunk-C5EYU7EQ.cjs.map → chunk-4MLJE6UP.cjs.map} +0 -0
  135. /package/dist/{chunk-SECN7UAL.cjs.map → chunk-7OD5S534.cjs.map} +0 -0
  136. /package/dist/{chunk-HYVNEUIK.js.map → chunk-MJ2KYXGR.js.map} +0 -0
  137. /package/dist/{chunk-KV5J7PNM.js.map → chunk-NZM2SI6U.js.map} +0 -0
  138. /package/dist/{chunk-4AH3KXDW.cjs.map → chunk-TWO3XB6H.cjs.map} +0 -0
  139. /package/dist/{chunk-HL6BL5HY.js.map → chunk-WGSS7TJP.js.map} +0 -0
@@ -1,8 +1,10 @@
1
1
  import { RSC } from '../nextjs/dom-flight.js';
2
2
  import { ScriptDescriptor, LinkDescriptor } from '../shared/asset-descriptors.js';
3
+ import { SharedModuleManifest, RemoteSharedModules } from '../shared/shared-broker.js';
3
4
  import { RemoteComponentMetadata } from '../../runtime/metadata.js';
4
5
  export { InternalResolveClientUrl, ResolveClientUrl } from '../../runtime/url/resolve-client-url.js';
5
6
  import 'parse5/dist/tree-adapters/default';
7
+ import '../../utils/logger.js';
6
8
 
7
9
  interface NextData {
8
10
  props: {
@@ -11,6 +13,7 @@ interface NextData {
11
13
  bundle: string;
12
14
  runtime: string;
13
15
  shared?: Record<string, string>;
16
+ sharedManifest?: SharedModuleManifest;
14
17
  };
15
18
  };
16
19
  page?: string;
@@ -27,7 +30,7 @@ interface FetchRemoteComponentResponse {
27
30
  nextData: NextData | undefined;
28
31
  component: React.ReactNode | undefined;
29
32
  html: string;
30
- remoteShared: Record<string, string>;
33
+ remoteShared: RemoteSharedModules;
31
34
  }
32
35
 
33
36
  export { FetchRemoteComponentResponse, NextData };
@@ -24,6 +24,7 @@ __export(pipeline_exports, {
24
24
  runPipelineFromParsed: () => runPipelineFromParsed
25
25
  });
26
26
  module.exports = __toCommonJS(pipeline_exports);
27
+ var import_shared_broker = require("#internal/host/shared/shared-broker");
27
28
  var import_shared_module_resolver = require("#internal/host/shared/shared-module-resolver");
28
29
  var import_apply_origin = require("#internal/runtime/html/apply-origin");
29
30
  var import_parse_remote_html = require("#internal/runtime/html/parse-remote-html");
@@ -37,10 +38,9 @@ function preparePipeline(input) {
37
38
  const doc = parser.parseFromString(input.html, "text/html");
38
39
  const parsed = (0, import_parse_remote_html.parseRemoteComponentDocument)(doc, input.name, input.url);
39
40
  const remoteShared = input.remoteShared ?? parsed.remoteShared;
40
- if ("__remote_components_missing_shared__" in remoteShared) {
41
- throw new import_error.RemoteComponentsError(
42
- remoteShared.__remote_components_missing_shared__
43
- );
41
+ const missingSharedModulesMessage = (0, import_shared_broker.getMissingSharedModulesMessage)(remoteShared);
42
+ if (missingSharedModulesMessage) {
43
+ throw new import_error.RemoteComponentsError(missingSharedModulesMessage);
44
44
  }
45
45
  (0, import_apply_origin.applyOriginToNodes)(doc, input.url, input.resolveClientUrl);
46
46
  const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);
@@ -109,10 +109,9 @@ async function runPipelineFromParsed(input) {
109
109
  return { status: "aborted" };
110
110
  }
111
111
  const remoteShared = input.remoteShared ?? input.payload.remoteShared ?? {};
112
- if ("__remote_components_missing_shared__" in remoteShared) {
113
- throw new import_error.RemoteComponentsError(
114
- remoteShared.__remote_components_missing_shared__
115
- );
112
+ const missingSharedModulesMessage = (0, import_shared_broker.getMissingSharedModulesMessage)(remoteShared);
113
+ if (missingSharedModulesMessage) {
114
+ throw new import_error.RemoteComponentsError(missingSharedModulesMessage);
116
115
  }
117
116
  const result = await (0, import_component_loader.loadRemoteComponent)({
118
117
  url: input.url,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/host/shared/pipeline.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ScriptDescriptor } from '#internal/host/shared/asset-descriptors';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport { buildHostShared } from '#internal/host/shared/shared-module-resolver';\nimport { applyOriginToNodes } from '#internal/runtime/html/apply-origin';\nimport {\n type ParsedRemoteComponent,\n parseRemoteComponentDocument,\n} from '#internal/runtime/html/parse-remote-html';\nimport { loadRemoteComponent } from '#internal/runtime/loaders/component-loader';\nimport { loadStaticRemoteComponent } from '#internal/runtime/loaders/static-loader';\nimport type { RemoteComponentMetadata } from '#internal/runtime/metadata';\nimport {\n collapseDoubleSlashes,\n REMOTE_COMPONENT_REGEX,\n} from '#internal/runtime/patterns';\nimport type { MountOrUnmountFunction } from '#internal/runtime/types';\nimport { escapeString } from '#internal/utils';\nimport { RemoteComponentsError } from '#internal/utils/error';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype SharedModuleMap = Record<string, (bundle?: string) => Promise<unknown>>;\n\n/**\n * Input for {@link runPipeline} — the full post-fetch pipeline that starts\n * from raw HTML.\n */\nexport interface PipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Raw HTML string returned by the remote. */\n html: string;\n /** Component name hint (may be refined during parsing). */\n name: string;\n /** Abort signal — the pipeline checks this between async steps. */\n signal: AbortSignal;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into (for script-based components). */\n container?: ShadowRoot | HTMLElement | null;\n}\n\n/**\n * Input for {@link runPipelineFromParsed} — the pipeline entry point for\n * hosts that receive pre-parsed SSR data (e.g. the App Router client).\n */\nexport interface ParsedPipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Component name. */\n name: string;\n /** Abort signal. */\n signal: AbortSignal;\n /** Pre-resolved loader payload from the server component. */\n payload: ConsumeLoaderPayload;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** Remote-requested shared modules. */\n remoteShared?: Record<string, string>;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into. */\n container?: ShadowRoot | HTMLElement | null;\n /** Optional RSC name override (used by App Router for scoped RSC data). */\n rscName?: string;\n}\n\n/**\n * Successful dynamic component load — the component is a React element tree\n * ready to render.\n */\nexport interface PipelineLoaded {\n status: 'loaded';\n component: React.ReactNode;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/**\n * Successful static component load — mount/unmount functions are returned\n * for the host to call.\n */\nexport interface PipelineStatic {\n status: 'static';\n mount: Set<MountOrUnmountFunction>;\n unmount: Set<MountOrUnmountFunction>;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/** The load was aborted before it could complete. */\nexport interface PipelineAborted {\n status: 'aborted';\n}\n\n/** The load failed with an error. */\nexport interface PipelineError {\n status: 'error';\n error: Error;\n}\n\nexport type PipelineResult =\n | PipelineLoaded\n | PipelineStatic\n | PipelineAborted\n | PipelineError;\n\n/**\n * Intermediate result from {@link preparePipeline}. Hosts that need to run\n * framework-specific logic between parse and load (e.g. inline script\n * execution in the React host) use this to split the pipeline into two\n * phases.\n */\nexport interface PreparedPipeline {\n doc: Document;\n parsed: ParsedRemoteComponent;\n /** Script descriptors ready to pass to `loadRemoteComponent`. */\n scriptDescriptors: ScriptDescriptor[];\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline phases\n// ---------------------------------------------------------------------------\n\n/**\n * Phase 1: Parse HTML, validate shared modules, and normalize URLs.\n *\n * This is the synchronous/cheap portion of the pipeline. Hosts that need to\n * inject logic between parse and load (e.g. executing inline scripts) call\n * this directly, then call {@link loadPrepared} when ready.\n */\nexport function preparePipeline(input: {\n html: string;\n name: string;\n url: URL;\n shared: SharedModuleMap;\n remoteShared?: Record<string, string>;\n resolveClientUrl?: InternalResolveClientUrl;\n}): PreparedPipeline {\n const parser = new DOMParser();\n const doc = parser.parseFromString(input.html, 'text/html');\n\n const parsed = parseRemoteComponentDocument(doc, input.name, input.url);\n\n // Validate shared modules — surface errors early before any script loading.\n // Only check *remote* shared modules here. The host-side marker\n // (`__remote_components_missing_shared__` in `input.shared`) is a callable\n // error signal that the host may intentionally leave in place when\n // `withRemoteComponentsConfig` is not used — blocking on it would break\n // framework-agnostic hosts that don't configure shared modules.\n const remoteShared = input.remoteShared ?? parsed.remoteShared;\n if ('__remote_components_missing_shared__' in remoteShared) {\n throw new RemoteComponentsError(\n remoteShared.__remote_components_missing_shared__,\n );\n }\n\n applyOriginToNodes(doc, input.url, input.resolveClientUrl);\n\n const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);\n\n return { doc, parsed, scriptDescriptors };\n}\n\n/**\n * Phase 2: Load the component from a prepared pipeline result.\n *\n * For dynamic components, delegates to `loadRemoteComponent`. For static\n * components (`isRemoteComponent`), delegates to `loadStaticRemoteComponent`.\n */\nexport async function loadPrepared(input: {\n prepared: PreparedPipeline;\n url: URL;\n signal: AbortSignal;\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineResult> {\n const { prepared, url, signal, resolveClientUrl, container, rscName } = input;\n const { doc, parsed, scriptDescriptors } = prepared;\n\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n const userShared = await input.shared;\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (parsed.isRemoteComponent) {\n return loadStaticPath({\n parsed,\n doc,\n url,\n resolveClientUrl,\n });\n }\n\n return loadDynamicPath({\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared: userShared,\n resolveClientUrl,\n container,\n rscName,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Full pipeline entry points\n// ---------------------------------------------------------------------------\n\n/**\n * Full post-fetch pipeline: parse → validate → normalize → load.\n *\n * Use this when starting from a raw HTML string (React host, HTML host).\n */\nexport async function runPipeline(\n input: PipelineInput,\n): Promise<PipelineResult> {\n try {\n const userShared = await input.shared;\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const prepared = preparePipeline({\n html: input.html,\n name: input.name,\n url: input.url,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n return await loadPrepared({\n prepared,\n url: input.url,\n signal: input.signal,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n container: input.container,\n });\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n/**\n * Pipeline entry point for pre-parsed SSR data (App Router client).\n *\n * Skips HTML parsing and goes straight to `loadRemoteComponent` with the\n * pre-resolved payload from the server component.\n */\nexport async function runPipelineFromParsed(\n input: ParsedPipelineInput,\n): Promise<\n | { status: 'loaded'; component: React.ReactNode }\n | PipelineAborted\n | PipelineError\n> {\n try {\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const remoteShared = input.remoteShared ?? input.payload.remoteShared ?? {};\n\n if ('__remote_components_missing_shared__' in remoteShared) {\n throw new RemoteComponentsError(\n remoteShared.__remote_components_missing_shared__,\n );\n }\n\n const result = await loadRemoteComponent({\n url: input.url,\n name: input.name,\n rscName: input.rscName,\n bundle: input.payload.bundle,\n route: input.payload.route,\n runtime: input.payload.runtime,\n data: input.payload.data,\n nextData: input.payload.nextData,\n scripts: input.payload.scripts,\n shared: input.shared,\n remoteShared,\n container: input.container,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return { status: 'loaded', component: result.component };\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts parsed `<script>` elements into the `ScriptDescriptor[]` format\n * expected by `loadRemoteComponent`. Handles the `[bundle] id` URL format\n * and collapses double slashes.\n */\nfunction buildScriptDescriptors(\n scripts: HTMLScriptElement[],\n url: URL,\n): ScriptDescriptor[] {\n return scripts.map((script) => {\n const scriptSrc =\n script.getAttribute('data-src') ||\n script.getAttribute('src') ||\n script.src;\n const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(scriptSrc)\n ?.groups ?? {\n prefix: undefined,\n id: scriptSrc,\n };\n return {\n src: new URL(collapseDoubleSlashes(`${prefix ?? ''}${path}`), url).href,\n };\n });\n}\n\nasync function loadStaticPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n resolveClientUrl?: InternalResolveClientUrl;\n}): Promise<PipelineStatic> {\n const { parsed, doc, url, resolveClientUrl } = input;\n const scripts = Array.from(\n parsed.component.querySelectorAll<HTMLScriptElement>('script'),\n );\n const { mount, unmount } = await loadStaticRemoteComponent(\n scripts,\n url,\n resolveClientUrl,\n );\n return {\n status: 'static',\n mount,\n unmount,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n\nasync function loadDynamicPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n scriptDescriptors: ScriptDescriptor[];\n shared: SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineLoaded | PipelineError> {\n const {\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared,\n resolveClientUrl,\n container,\n } = input;\n\n const rscName =\n input.rscName ??\n (parsed.rsc\n ? `__remote_component_rsc_${escapeString(url.href)}_${escapeString(parsed.name)}`\n : undefined);\n\n const rscData = parsed.rsc\n ? (parsed.rsc.textContent || '').split('\\n').filter(Boolean)\n : [];\n\n const result = await loadRemoteComponent({\n url,\n name: parsed.name,\n rscName,\n bundle: parsed.metadata.bundle,\n route: parsed.metadata.route,\n runtime: parsed.metadata.runtime,\n data: rscData,\n nextData: parsed.nextData,\n scripts: scriptDescriptors,\n shared: buildHostShared(shared, resolveClientUrl),\n remoteShared: parsed.remoteShared,\n container,\n resolveClientUrl,\n });\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return {\n status: 'loaded',\n component: result.component,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/host/shared/pipeline.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ScriptDescriptor } from '#internal/host/shared/asset-descriptors';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport {\n getMissingSharedModulesMessage,\n type RemoteSharedModules,\n} from '#internal/host/shared/shared-broker';\nimport { buildHostShared } from '#internal/host/shared/shared-module-resolver';\nimport { applyOriginToNodes } from '#internal/runtime/html/apply-origin';\nimport {\n type ParsedRemoteComponent,\n parseRemoteComponentDocument,\n} from '#internal/runtime/html/parse-remote-html';\nimport { loadRemoteComponent } from '#internal/runtime/loaders/component-loader';\nimport { loadStaticRemoteComponent } from '#internal/runtime/loaders/static-loader';\nimport type { RemoteComponentMetadata } from '#internal/runtime/metadata';\nimport {\n collapseDoubleSlashes,\n REMOTE_COMPONENT_REGEX,\n} from '#internal/runtime/patterns';\nimport type { MountOrUnmountFunction } from '#internal/runtime/types';\nimport { escapeString } from '#internal/utils';\nimport { RemoteComponentsError } from '#internal/utils/error';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype SharedModuleMap = Record<string, (bundle?: string) => Promise<unknown>>;\n\n/**\n * Input for {@link runPipeline} — the full post-fetch pipeline that starts\n * from raw HTML.\n */\nexport interface PipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Raw HTML string returned by the remote. */\n html: string;\n /** Component name hint (may be refined during parsing). */\n name: string;\n /** Abort signal — the pipeline checks this between async steps. */\n signal: AbortSignal;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into (for script-based components). */\n container?: ShadowRoot | HTMLElement | null;\n}\n\n/**\n * Input for {@link runPipelineFromParsed} — the pipeline entry point for\n * hosts that receive pre-parsed SSR data (e.g. the App Router client).\n */\nexport interface ParsedPipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Component name. */\n name: string;\n /** Abort signal. */\n signal: AbortSignal;\n /** Pre-resolved loader payload from the server component. */\n payload: ConsumeLoaderPayload;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** Remote-requested shared modules. */\n remoteShared?: RemoteSharedModules;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into. */\n container?: ShadowRoot | HTMLElement | null;\n /** Optional RSC name override (used by App Router for scoped RSC data). */\n rscName?: string;\n}\n\n/**\n * Successful dynamic component load — the component is a React element tree\n * ready to render.\n */\nexport interface PipelineLoaded {\n status: 'loaded';\n component: React.ReactNode;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/**\n * Successful static component load — mount/unmount functions are returned\n * for the host to call.\n */\nexport interface PipelineStatic {\n status: 'static';\n mount: Set<MountOrUnmountFunction>;\n unmount: Set<MountOrUnmountFunction>;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/** The load was aborted before it could complete. */\nexport interface PipelineAborted {\n status: 'aborted';\n}\n\n/** The load failed with an error. */\nexport interface PipelineError {\n status: 'error';\n error: Error;\n}\n\nexport type PipelineResult =\n | PipelineLoaded\n | PipelineStatic\n | PipelineAborted\n | PipelineError;\n\n/**\n * Intermediate result from {@link preparePipeline}. Hosts that need to run\n * framework-specific logic between parse and load (e.g. inline script\n * execution in the React host) use this to split the pipeline into two\n * phases.\n */\nexport interface PreparedPipeline {\n doc: Document;\n parsed: ParsedRemoteComponent;\n /** Script descriptors ready to pass to `loadRemoteComponent`. */\n scriptDescriptors: ScriptDescriptor[];\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline phases\n// ---------------------------------------------------------------------------\n\n/**\n * Phase 1: Parse HTML, validate shared modules, and normalize URLs.\n *\n * This is the synchronous/cheap portion of the pipeline. Hosts that need to\n * inject logic between parse and load (e.g. executing inline scripts) call\n * this directly, then call {@link loadPrepared} when ready.\n */\nexport function preparePipeline(input: {\n html: string;\n name: string;\n url: URL;\n shared: SharedModuleMap;\n remoteShared?: RemoteSharedModules;\n resolveClientUrl?: InternalResolveClientUrl;\n}): PreparedPipeline {\n const parser = new DOMParser();\n const doc = parser.parseFromString(input.html, 'text/html');\n\n const parsed = parseRemoteComponentDocument(doc, input.name, input.url);\n\n // Validate shared modules — surface errors early before any script loading.\n // Only check *remote* shared modules here. The host-side marker\n // (`__remote_components_missing_shared__` in `input.shared`) is a callable\n // error signal that the host may intentionally leave in place when\n // `withRemoteComponentsConfig` is not used — blocking on it would break\n // framework-agnostic hosts that don't configure shared modules.\n const remoteShared = input.remoteShared ?? parsed.remoteShared;\n const missingSharedModulesMessage =\n getMissingSharedModulesMessage(remoteShared);\n if (missingSharedModulesMessage) {\n throw new RemoteComponentsError(missingSharedModulesMessage);\n }\n\n applyOriginToNodes(doc, input.url, input.resolveClientUrl);\n\n const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);\n\n return { doc, parsed, scriptDescriptors };\n}\n\n/**\n * Phase 2: Load the component from a prepared pipeline result.\n *\n * For dynamic components, delegates to `loadRemoteComponent`. For static\n * components (`isRemoteComponent`), delegates to `loadStaticRemoteComponent`.\n */\nexport async function loadPrepared(input: {\n prepared: PreparedPipeline;\n url: URL;\n signal: AbortSignal;\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineResult> {\n const { prepared, url, signal, resolveClientUrl, container, rscName } = input;\n const { doc, parsed, scriptDescriptors } = prepared;\n\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n const userShared = await input.shared;\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (parsed.isRemoteComponent) {\n return loadStaticPath({\n parsed,\n doc,\n url,\n resolveClientUrl,\n });\n }\n\n return loadDynamicPath({\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared: userShared,\n resolveClientUrl,\n container,\n rscName,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Full pipeline entry points\n// ---------------------------------------------------------------------------\n\n/**\n * Full post-fetch pipeline: parse → validate → normalize → load.\n *\n * Use this when starting from a raw HTML string (React host, HTML host).\n */\nexport async function runPipeline(\n input: PipelineInput,\n): Promise<PipelineResult> {\n try {\n const userShared = await input.shared;\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const prepared = preparePipeline({\n html: input.html,\n name: input.name,\n url: input.url,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n return await loadPrepared({\n prepared,\n url: input.url,\n signal: input.signal,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n container: input.container,\n });\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n/**\n * Pipeline entry point for pre-parsed SSR data (App Router client).\n *\n * Skips HTML parsing and goes straight to `loadRemoteComponent` with the\n * pre-resolved payload from the server component.\n */\nexport async function runPipelineFromParsed(\n input: ParsedPipelineInput,\n): Promise<\n | { status: 'loaded'; component: React.ReactNode }\n | PipelineAborted\n | PipelineError\n> {\n try {\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const remoteShared = input.remoteShared ?? input.payload.remoteShared ?? {};\n\n const missingSharedModulesMessage =\n getMissingSharedModulesMessage(remoteShared);\n if (missingSharedModulesMessage) {\n throw new RemoteComponentsError(missingSharedModulesMessage);\n }\n\n const result = await loadRemoteComponent({\n url: input.url,\n name: input.name,\n rscName: input.rscName,\n bundle: input.payload.bundle,\n route: input.payload.route,\n runtime: input.payload.runtime,\n data: input.payload.data,\n nextData: input.payload.nextData,\n scripts: input.payload.scripts,\n shared: input.shared,\n remoteShared,\n container: input.container,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return { status: 'loaded', component: result.component };\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts parsed `<script>` elements into the `ScriptDescriptor[]` format\n * expected by `loadRemoteComponent`. Handles the `[bundle] id` URL format\n * and collapses double slashes.\n */\nfunction buildScriptDescriptors(\n scripts: HTMLScriptElement[],\n url: URL,\n): ScriptDescriptor[] {\n return scripts.map((script) => {\n const scriptSrc =\n script.getAttribute('data-src') ||\n script.getAttribute('src') ||\n script.src;\n const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(scriptSrc)\n ?.groups ?? {\n prefix: undefined,\n id: scriptSrc,\n };\n return {\n src: new URL(collapseDoubleSlashes(`${prefix ?? ''}${path}`), url).href,\n };\n });\n}\n\nasync function loadStaticPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n resolveClientUrl?: InternalResolveClientUrl;\n}): Promise<PipelineStatic> {\n const { parsed, doc, url, resolveClientUrl } = input;\n const scripts = Array.from(\n parsed.component.querySelectorAll<HTMLScriptElement>('script'),\n );\n const { mount, unmount } = await loadStaticRemoteComponent(\n scripts,\n url,\n resolveClientUrl,\n );\n return {\n status: 'static',\n mount,\n unmount,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n\nasync function loadDynamicPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n scriptDescriptors: ScriptDescriptor[];\n shared: SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineLoaded | PipelineError> {\n const {\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared,\n resolveClientUrl,\n container,\n } = input;\n\n const rscName =\n input.rscName ??\n (parsed.rsc\n ? `__remote_component_rsc_${escapeString(url.href)}_${escapeString(parsed.name)}`\n : undefined);\n\n const rscData = parsed.rsc\n ? (parsed.rsc.textContent || '').split('\\n').filter(Boolean)\n : [];\n\n const result = await loadRemoteComponent({\n url,\n name: parsed.name,\n rscName,\n bundle: parsed.metadata.bundle,\n route: parsed.metadata.route,\n runtime: parsed.metadata.runtime,\n data: rscData,\n nextData: parsed.nextData,\n scripts: scriptDescriptors,\n shared: buildHostShared(shared, resolveClientUrl),\n remoteShared: parsed.remoteShared,\n container,\n resolveClientUrl,\n });\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return {\n status: 'loaded',\n component: result.component,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +1,11 @@
1
+ import { RemoteSharedModules } from './shared-broker.js';
1
2
  import { RemoteComponentMetadata } from '../../runtime/metadata.js';
2
3
  import { ScriptDescriptor } from './asset-descriptors.js';
3
4
  import { InternalResolveClientUrl } from '../../runtime/url/resolve-client-url.js';
4
- import { a as ConsumeLoaderPayload } from '../../../server-handoff-8c89b856.js';
5
+ import { a as ConsumeLoaderPayload } from '../../../server-handoff-9e905049.js';
5
6
  import { ParsedRemoteComponent } from '../../runtime/html/parse-remote-html.js';
6
7
  import { M as MountOrUnmountFunction } from '../../../types-bd7be268.js';
8
+ import '../../utils/logger.js';
7
9
  import 'react';
8
10
  import './config.js';
9
11
  import './fetch-interceptors.js';
@@ -50,7 +52,7 @@ interface ParsedPipelineInput {
50
52
  /** Host-provided shared module factories (resolved or promise). */
51
53
  shared: Promise<SharedModuleMap> | SharedModuleMap;
52
54
  /** Remote-requested shared modules. */
53
- remoteShared?: Record<string, string>;
55
+ remoteShared?: RemoteSharedModules;
54
56
  /** URL rewriter for client-side asset URLs. */
55
57
  resolveClientUrl?: InternalResolveClientUrl;
56
58
  /** Shadow root or element to mount into. */
@@ -115,7 +117,7 @@ declare function preparePipeline(input: {
115
117
  name: string;
116
118
  url: URL;
117
119
  shared: SharedModuleMap;
118
- remoteShared?: Record<string, string>;
120
+ remoteShared?: RemoteSharedModules;
119
121
  resolveClientUrl?: InternalResolveClientUrl;
120
122
  }): PreparedPipeline;
121
123
  /**
@@ -1,3 +1,6 @@
1
+ import {
2
+ getMissingSharedModulesMessage
3
+ } from "#internal/host/shared/shared-broker";
1
4
  import { buildHostShared } from "#internal/host/shared/shared-module-resolver";
2
5
  import { applyOriginToNodes } from "#internal/runtime/html/apply-origin";
3
6
  import {
@@ -16,10 +19,9 @@ function preparePipeline(input) {
16
19
  const doc = parser.parseFromString(input.html, "text/html");
17
20
  const parsed = parseRemoteComponentDocument(doc, input.name, input.url);
18
21
  const remoteShared = input.remoteShared ?? parsed.remoteShared;
19
- if ("__remote_components_missing_shared__" in remoteShared) {
20
- throw new RemoteComponentsError(
21
- remoteShared.__remote_components_missing_shared__
22
- );
22
+ const missingSharedModulesMessage = getMissingSharedModulesMessage(remoteShared);
23
+ if (missingSharedModulesMessage) {
24
+ throw new RemoteComponentsError(missingSharedModulesMessage);
23
25
  }
24
26
  applyOriginToNodes(doc, input.url, input.resolveClientUrl);
25
27
  const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);
@@ -88,10 +90,9 @@ async function runPipelineFromParsed(input) {
88
90
  return { status: "aborted" };
89
91
  }
90
92
  const remoteShared = input.remoteShared ?? input.payload.remoteShared ?? {};
91
- if ("__remote_components_missing_shared__" in remoteShared) {
92
- throw new RemoteComponentsError(
93
- remoteShared.__remote_components_missing_shared__
94
- );
93
+ const missingSharedModulesMessage = getMissingSharedModulesMessage(remoteShared);
94
+ if (missingSharedModulesMessage) {
95
+ throw new RemoteComponentsError(missingSharedModulesMessage);
95
96
  }
96
97
  const result = await loadRemoteComponent({
97
98
  url: input.url,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/host/shared/pipeline.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ScriptDescriptor } from '#internal/host/shared/asset-descriptors';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport { buildHostShared } from '#internal/host/shared/shared-module-resolver';\nimport { applyOriginToNodes } from '#internal/runtime/html/apply-origin';\nimport {\n type ParsedRemoteComponent,\n parseRemoteComponentDocument,\n} from '#internal/runtime/html/parse-remote-html';\nimport { loadRemoteComponent } from '#internal/runtime/loaders/component-loader';\nimport { loadStaticRemoteComponent } from '#internal/runtime/loaders/static-loader';\nimport type { RemoteComponentMetadata } from '#internal/runtime/metadata';\nimport {\n collapseDoubleSlashes,\n REMOTE_COMPONENT_REGEX,\n} from '#internal/runtime/patterns';\nimport type { MountOrUnmountFunction } from '#internal/runtime/types';\nimport { escapeString } from '#internal/utils';\nimport { RemoteComponentsError } from '#internal/utils/error';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype SharedModuleMap = Record<string, (bundle?: string) => Promise<unknown>>;\n\n/**\n * Input for {@link runPipeline} — the full post-fetch pipeline that starts\n * from raw HTML.\n */\nexport interface PipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Raw HTML string returned by the remote. */\n html: string;\n /** Component name hint (may be refined during parsing). */\n name: string;\n /** Abort signal — the pipeline checks this between async steps. */\n signal: AbortSignal;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into (for script-based components). */\n container?: ShadowRoot | HTMLElement | null;\n}\n\n/**\n * Input for {@link runPipelineFromParsed} — the pipeline entry point for\n * hosts that receive pre-parsed SSR data (e.g. the App Router client).\n */\nexport interface ParsedPipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Component name. */\n name: string;\n /** Abort signal. */\n signal: AbortSignal;\n /** Pre-resolved loader payload from the server component. */\n payload: ConsumeLoaderPayload;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** Remote-requested shared modules. */\n remoteShared?: Record<string, string>;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into. */\n container?: ShadowRoot | HTMLElement | null;\n /** Optional RSC name override (used by App Router for scoped RSC data). */\n rscName?: string;\n}\n\n/**\n * Successful dynamic component load — the component is a React element tree\n * ready to render.\n */\nexport interface PipelineLoaded {\n status: 'loaded';\n component: React.ReactNode;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/**\n * Successful static component load — mount/unmount functions are returned\n * for the host to call.\n */\nexport interface PipelineStatic {\n status: 'static';\n mount: Set<MountOrUnmountFunction>;\n unmount: Set<MountOrUnmountFunction>;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/** The load was aborted before it could complete. */\nexport interface PipelineAborted {\n status: 'aborted';\n}\n\n/** The load failed with an error. */\nexport interface PipelineError {\n status: 'error';\n error: Error;\n}\n\nexport type PipelineResult =\n | PipelineLoaded\n | PipelineStatic\n | PipelineAborted\n | PipelineError;\n\n/**\n * Intermediate result from {@link preparePipeline}. Hosts that need to run\n * framework-specific logic between parse and load (e.g. inline script\n * execution in the React host) use this to split the pipeline into two\n * phases.\n */\nexport interface PreparedPipeline {\n doc: Document;\n parsed: ParsedRemoteComponent;\n /** Script descriptors ready to pass to `loadRemoteComponent`. */\n scriptDescriptors: ScriptDescriptor[];\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline phases\n// ---------------------------------------------------------------------------\n\n/**\n * Phase 1: Parse HTML, validate shared modules, and normalize URLs.\n *\n * This is the synchronous/cheap portion of the pipeline. Hosts that need to\n * inject logic between parse and load (e.g. executing inline scripts) call\n * this directly, then call {@link loadPrepared} when ready.\n */\nexport function preparePipeline(input: {\n html: string;\n name: string;\n url: URL;\n shared: SharedModuleMap;\n remoteShared?: Record<string, string>;\n resolveClientUrl?: InternalResolveClientUrl;\n}): PreparedPipeline {\n const parser = new DOMParser();\n const doc = parser.parseFromString(input.html, 'text/html');\n\n const parsed = parseRemoteComponentDocument(doc, input.name, input.url);\n\n // Validate shared modules — surface errors early before any script loading.\n // Only check *remote* shared modules here. The host-side marker\n // (`__remote_components_missing_shared__` in `input.shared`) is a callable\n // error signal that the host may intentionally leave in place when\n // `withRemoteComponentsConfig` is not used — blocking on it would break\n // framework-agnostic hosts that don't configure shared modules.\n const remoteShared = input.remoteShared ?? parsed.remoteShared;\n if ('__remote_components_missing_shared__' in remoteShared) {\n throw new RemoteComponentsError(\n remoteShared.__remote_components_missing_shared__,\n );\n }\n\n applyOriginToNodes(doc, input.url, input.resolveClientUrl);\n\n const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);\n\n return { doc, parsed, scriptDescriptors };\n}\n\n/**\n * Phase 2: Load the component from a prepared pipeline result.\n *\n * For dynamic components, delegates to `loadRemoteComponent`. For static\n * components (`isRemoteComponent`), delegates to `loadStaticRemoteComponent`.\n */\nexport async function loadPrepared(input: {\n prepared: PreparedPipeline;\n url: URL;\n signal: AbortSignal;\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineResult> {\n const { prepared, url, signal, resolveClientUrl, container, rscName } = input;\n const { doc, parsed, scriptDescriptors } = prepared;\n\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n const userShared = await input.shared;\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (parsed.isRemoteComponent) {\n return loadStaticPath({\n parsed,\n doc,\n url,\n resolveClientUrl,\n });\n }\n\n return loadDynamicPath({\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared: userShared,\n resolveClientUrl,\n container,\n rscName,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Full pipeline entry points\n// ---------------------------------------------------------------------------\n\n/**\n * Full post-fetch pipeline: parse → validate → normalize → load.\n *\n * Use this when starting from a raw HTML string (React host, HTML host).\n */\nexport async function runPipeline(\n input: PipelineInput,\n): Promise<PipelineResult> {\n try {\n const userShared = await input.shared;\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const prepared = preparePipeline({\n html: input.html,\n name: input.name,\n url: input.url,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n return await loadPrepared({\n prepared,\n url: input.url,\n signal: input.signal,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n container: input.container,\n });\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n/**\n * Pipeline entry point for pre-parsed SSR data (App Router client).\n *\n * Skips HTML parsing and goes straight to `loadRemoteComponent` with the\n * pre-resolved payload from the server component.\n */\nexport async function runPipelineFromParsed(\n input: ParsedPipelineInput,\n): Promise<\n | { status: 'loaded'; component: React.ReactNode }\n | PipelineAborted\n | PipelineError\n> {\n try {\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const remoteShared = input.remoteShared ?? input.payload.remoteShared ?? {};\n\n if ('__remote_components_missing_shared__' in remoteShared) {\n throw new RemoteComponentsError(\n remoteShared.__remote_components_missing_shared__,\n );\n }\n\n const result = await loadRemoteComponent({\n url: input.url,\n name: input.name,\n rscName: input.rscName,\n bundle: input.payload.bundle,\n route: input.payload.route,\n runtime: input.payload.runtime,\n data: input.payload.data,\n nextData: input.payload.nextData,\n scripts: input.payload.scripts,\n shared: input.shared,\n remoteShared,\n container: input.container,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return { status: 'loaded', component: result.component };\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts parsed `<script>` elements into the `ScriptDescriptor[]` format\n * expected by `loadRemoteComponent`. Handles the `[bundle] id` URL format\n * and collapses double slashes.\n */\nfunction buildScriptDescriptors(\n scripts: HTMLScriptElement[],\n url: URL,\n): ScriptDescriptor[] {\n return scripts.map((script) => {\n const scriptSrc =\n script.getAttribute('data-src') ||\n script.getAttribute('src') ||\n script.src;\n const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(scriptSrc)\n ?.groups ?? {\n prefix: undefined,\n id: scriptSrc,\n };\n return {\n src: new URL(collapseDoubleSlashes(`${prefix ?? ''}${path}`), url).href,\n };\n });\n}\n\nasync function loadStaticPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n resolveClientUrl?: InternalResolveClientUrl;\n}): Promise<PipelineStatic> {\n const { parsed, doc, url, resolveClientUrl } = input;\n const scripts = Array.from(\n parsed.component.querySelectorAll<HTMLScriptElement>('script'),\n );\n const { mount, unmount } = await loadStaticRemoteComponent(\n scripts,\n url,\n resolveClientUrl,\n );\n return {\n status: 'static',\n mount,\n unmount,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n\nasync function loadDynamicPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n scriptDescriptors: ScriptDescriptor[];\n shared: SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineLoaded | PipelineError> {\n const {\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared,\n resolveClientUrl,\n container,\n } = input;\n\n const rscName =\n input.rscName ??\n (parsed.rsc\n ? `__remote_component_rsc_${escapeString(url.href)}_${escapeString(parsed.name)}`\n : undefined);\n\n const rscData = parsed.rsc\n ? (parsed.rsc.textContent || '').split('\\n').filter(Boolean)\n : [];\n\n const result = await loadRemoteComponent({\n url,\n name: parsed.name,\n rscName,\n bundle: parsed.metadata.bundle,\n route: parsed.metadata.route,\n runtime: parsed.metadata.runtime,\n data: rscData,\n nextData: parsed.nextData,\n scripts: scriptDescriptors,\n shared: buildHostShared(shared, resolveClientUrl),\n remoteShared: parsed.remoteShared,\n container,\n resolveClientUrl,\n });\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return {\n status: 'loaded',\n component: result.component,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/host/shared/pipeline.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ScriptDescriptor } from '#internal/host/shared/asset-descriptors';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport {\n getMissingSharedModulesMessage,\n type RemoteSharedModules,\n} from '#internal/host/shared/shared-broker';\nimport { buildHostShared } from '#internal/host/shared/shared-module-resolver';\nimport { applyOriginToNodes } from '#internal/runtime/html/apply-origin';\nimport {\n type ParsedRemoteComponent,\n parseRemoteComponentDocument,\n} from '#internal/runtime/html/parse-remote-html';\nimport { loadRemoteComponent } from '#internal/runtime/loaders/component-loader';\nimport { loadStaticRemoteComponent } from '#internal/runtime/loaders/static-loader';\nimport type { RemoteComponentMetadata } from '#internal/runtime/metadata';\nimport {\n collapseDoubleSlashes,\n REMOTE_COMPONENT_REGEX,\n} from '#internal/runtime/patterns';\nimport type { MountOrUnmountFunction } from '#internal/runtime/types';\nimport { escapeString } from '#internal/utils';\nimport { RemoteComponentsError } from '#internal/utils/error';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype SharedModuleMap = Record<string, (bundle?: string) => Promise<unknown>>;\n\n/**\n * Input for {@link runPipeline} — the full post-fetch pipeline that starts\n * from raw HTML.\n */\nexport interface PipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Raw HTML string returned by the remote. */\n html: string;\n /** Component name hint (may be refined during parsing). */\n name: string;\n /** Abort signal — the pipeline checks this between async steps. */\n signal: AbortSignal;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into (for script-based components). */\n container?: ShadowRoot | HTMLElement | null;\n}\n\n/**\n * Input for {@link runPipelineFromParsed} — the pipeline entry point for\n * hosts that receive pre-parsed SSR data (e.g. the App Router client).\n */\nexport interface ParsedPipelineInput {\n /** Resolved URL of the remote component. */\n url: URL;\n /** Component name. */\n name: string;\n /** Abort signal. */\n signal: AbortSignal;\n /** Pre-resolved loader payload from the server component. */\n payload: ConsumeLoaderPayload;\n /** Host-provided shared module factories (resolved or promise). */\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n /** Remote-requested shared modules. */\n remoteShared?: RemoteSharedModules;\n /** URL rewriter for client-side asset URLs. */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Shadow root or element to mount into. */\n container?: ShadowRoot | HTMLElement | null;\n /** Optional RSC name override (used by App Router for scoped RSC data). */\n rscName?: string;\n}\n\n/**\n * Successful dynamic component load — the component is a React element tree\n * ready to render.\n */\nexport interface PipelineLoaded {\n status: 'loaded';\n component: React.ReactNode;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/**\n * Successful static component load — mount/unmount functions are returned\n * for the host to call.\n */\nexport interface PipelineStatic {\n status: 'static';\n mount: Set<MountOrUnmountFunction>;\n unmount: Set<MountOrUnmountFunction>;\n metadata: RemoteComponentMetadata;\n parsed: ParsedRemoteComponent;\n doc: Document;\n}\n\n/** The load was aborted before it could complete. */\nexport interface PipelineAborted {\n status: 'aborted';\n}\n\n/** The load failed with an error. */\nexport interface PipelineError {\n status: 'error';\n error: Error;\n}\n\nexport type PipelineResult =\n | PipelineLoaded\n | PipelineStatic\n | PipelineAborted\n | PipelineError;\n\n/**\n * Intermediate result from {@link preparePipeline}. Hosts that need to run\n * framework-specific logic between parse and load (e.g. inline script\n * execution in the React host) use this to split the pipeline into two\n * phases.\n */\nexport interface PreparedPipeline {\n doc: Document;\n parsed: ParsedRemoteComponent;\n /** Script descriptors ready to pass to `loadRemoteComponent`. */\n scriptDescriptors: ScriptDescriptor[];\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline phases\n// ---------------------------------------------------------------------------\n\n/**\n * Phase 1: Parse HTML, validate shared modules, and normalize URLs.\n *\n * This is the synchronous/cheap portion of the pipeline. Hosts that need to\n * inject logic between parse and load (e.g. executing inline scripts) call\n * this directly, then call {@link loadPrepared} when ready.\n */\nexport function preparePipeline(input: {\n html: string;\n name: string;\n url: URL;\n shared: SharedModuleMap;\n remoteShared?: RemoteSharedModules;\n resolveClientUrl?: InternalResolveClientUrl;\n}): PreparedPipeline {\n const parser = new DOMParser();\n const doc = parser.parseFromString(input.html, 'text/html');\n\n const parsed = parseRemoteComponentDocument(doc, input.name, input.url);\n\n // Validate shared modules — surface errors early before any script loading.\n // Only check *remote* shared modules here. The host-side marker\n // (`__remote_components_missing_shared__` in `input.shared`) is a callable\n // error signal that the host may intentionally leave in place when\n // `withRemoteComponentsConfig` is not used — blocking on it would break\n // framework-agnostic hosts that don't configure shared modules.\n const remoteShared = input.remoteShared ?? parsed.remoteShared;\n const missingSharedModulesMessage =\n getMissingSharedModulesMessage(remoteShared);\n if (missingSharedModulesMessage) {\n throw new RemoteComponentsError(missingSharedModulesMessage);\n }\n\n applyOriginToNodes(doc, input.url, input.resolveClientUrl);\n\n const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);\n\n return { doc, parsed, scriptDescriptors };\n}\n\n/**\n * Phase 2: Load the component from a prepared pipeline result.\n *\n * For dynamic components, delegates to `loadRemoteComponent`. For static\n * components (`isRemoteComponent`), delegates to `loadStaticRemoteComponent`.\n */\nexport async function loadPrepared(input: {\n prepared: PreparedPipeline;\n url: URL;\n signal: AbortSignal;\n shared: Promise<SharedModuleMap> | SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineResult> {\n const { prepared, url, signal, resolveClientUrl, container, rscName } = input;\n const { doc, parsed, scriptDescriptors } = prepared;\n\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n const userShared = await input.shared;\n if (signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (parsed.isRemoteComponent) {\n return loadStaticPath({\n parsed,\n doc,\n url,\n resolveClientUrl,\n });\n }\n\n return loadDynamicPath({\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared: userShared,\n resolveClientUrl,\n container,\n rscName,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Full pipeline entry points\n// ---------------------------------------------------------------------------\n\n/**\n * Full post-fetch pipeline: parse → validate → normalize → load.\n *\n * Use this when starting from a raw HTML string (React host, HTML host).\n */\nexport async function runPipeline(\n input: PipelineInput,\n): Promise<PipelineResult> {\n try {\n const userShared = await input.shared;\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const prepared = preparePipeline({\n html: input.html,\n name: input.name,\n url: input.url,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n return await loadPrepared({\n prepared,\n url: input.url,\n signal: input.signal,\n shared: userShared,\n resolveClientUrl: input.resolveClientUrl,\n container: input.container,\n });\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n/**\n * Pipeline entry point for pre-parsed SSR data (App Router client).\n *\n * Skips HTML parsing and goes straight to `loadRemoteComponent` with the\n * pre-resolved payload from the server component.\n */\nexport async function runPipelineFromParsed(\n input: ParsedPipelineInput,\n): Promise<\n | { status: 'loaded'; component: React.ReactNode }\n | PipelineAborted\n | PipelineError\n> {\n try {\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n const remoteShared = input.remoteShared ?? input.payload.remoteShared ?? {};\n\n const missingSharedModulesMessage =\n getMissingSharedModulesMessage(remoteShared);\n if (missingSharedModulesMessage) {\n throw new RemoteComponentsError(missingSharedModulesMessage);\n }\n\n const result = await loadRemoteComponent({\n url: input.url,\n name: input.name,\n rscName: input.rscName,\n bundle: input.payload.bundle,\n route: input.payload.route,\n runtime: input.payload.runtime,\n data: input.payload.data,\n nextData: input.payload.nextData,\n scripts: input.payload.scripts,\n shared: input.shared,\n remoteShared,\n container: input.container,\n resolveClientUrl: input.resolveClientUrl,\n });\n\n if (input.signal.aborted) {\n return { status: 'aborted' };\n }\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return { status: 'loaded', component: result.component };\n } catch (error) {\n return {\n status: 'error',\n error:\n error instanceof Error\n ? error\n : new RemoteComponentsError(String(error)),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts parsed `<script>` elements into the `ScriptDescriptor[]` format\n * expected by `loadRemoteComponent`. Handles the `[bundle] id` URL format\n * and collapses double slashes.\n */\nfunction buildScriptDescriptors(\n scripts: HTMLScriptElement[],\n url: URL,\n): ScriptDescriptor[] {\n return scripts.map((script) => {\n const scriptSrc =\n script.getAttribute('data-src') ||\n script.getAttribute('src') ||\n script.src;\n const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(scriptSrc)\n ?.groups ?? {\n prefix: undefined,\n id: scriptSrc,\n };\n return {\n src: new URL(collapseDoubleSlashes(`${prefix ?? ''}${path}`), url).href,\n };\n });\n}\n\nasync function loadStaticPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n resolveClientUrl?: InternalResolveClientUrl;\n}): Promise<PipelineStatic> {\n const { parsed, doc, url, resolveClientUrl } = input;\n const scripts = Array.from(\n parsed.component.querySelectorAll<HTMLScriptElement>('script'),\n );\n const { mount, unmount } = await loadStaticRemoteComponent(\n scripts,\n url,\n resolveClientUrl,\n );\n return {\n status: 'static',\n mount,\n unmount,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n\nasync function loadDynamicPath(input: {\n parsed: ParsedRemoteComponent;\n doc: Document;\n url: URL;\n scriptDescriptors: ScriptDescriptor[];\n shared: SharedModuleMap;\n resolveClientUrl?: InternalResolveClientUrl;\n container?: ShadowRoot | HTMLElement | null;\n rscName?: string;\n}): Promise<PipelineLoaded | PipelineError> {\n const {\n parsed,\n doc,\n url,\n scriptDescriptors,\n shared,\n resolveClientUrl,\n container,\n } = input;\n\n const rscName =\n input.rscName ??\n (parsed.rsc\n ? `__remote_component_rsc_${escapeString(url.href)}_${escapeString(parsed.name)}`\n : undefined);\n\n const rscData = parsed.rsc\n ? (parsed.rsc.textContent || '').split('\\n').filter(Boolean)\n : [];\n\n const result = await loadRemoteComponent({\n url,\n name: parsed.name,\n rscName,\n bundle: parsed.metadata.bundle,\n route: parsed.metadata.route,\n runtime: parsed.metadata.runtime,\n data: rscData,\n nextData: parsed.nextData,\n scripts: scriptDescriptors,\n shared: buildHostShared(shared, resolveClientUrl),\n remoteShared: parsed.remoteShared,\n container,\n resolveClientUrl,\n });\n\n if (result.error) {\n return { status: 'error', error: result.error };\n }\n return {\n status: 'loaded',\n component: result.component,\n metadata: parsed.metadata,\n parsed,\n doc,\n };\n}\n"],"mappings":"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","names":[]}
@@ -18,12 +18,25 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var shared_broker_exports = {};
20
20
  __export(shared_broker_exports, {
21
+ SHARED_MODULE_MANIFEST_PROTOCOL: () => SHARED_MODULE_MANIFEST_PROTOCOL,
21
22
  createSharedModulePlan: () => createSharedModulePlan,
23
+ getMissingSharedModulesMessage: () => getMissingSharedModulesMessage,
22
24
  installSharedModulePlan: () => installSharedModulePlan,
25
+ isSharedModuleManifest: () => isSharedModuleManifest,
23
26
  resolveSharedModulePlan: () => resolveSharedModulePlan
24
27
  });
25
28
  module.exports = __toCommonJS(shared_broker_exports);
26
29
  var import_logger = require("#internal/utils/logger");
30
+ const SHARED_MODULE_MANIFEST_PROTOCOL = "remote-components.shared.v1";
31
+ function isSharedModuleManifest(value) {
32
+ return typeof value === "object" && value !== null && "protocol" in value && value.protocol === SHARED_MODULE_MANIFEST_PROTOCOL && "requirements" in value && Array.isArray(value.requirements);
33
+ }
34
+ function getMissingSharedModulesMessage(remoteShared) {
35
+ if (isSharedModuleManifest(remoteShared))
36
+ return void 0;
37
+ const message = remoteShared.__remote_components_missing_shared__;
38
+ return typeof message === "string" ? message : void 0;
39
+ }
27
40
  function createSharedModulePlan({
28
41
  bundle,
29
42
  hostShared,
@@ -31,42 +44,63 @@ function createSharedModulePlan({
31
44
  scope = `remote:${bundle}`,
32
45
  callerTag = "SharedBroker"
33
46
  }) {
34
- const entries = Object.entries(remoteShared).map(([id, rawSpecifier]) => {
35
- const specifier = String(rawSpecifier);
47
+ const protocol = isSharedModuleManifest(remoteShared) ? remoteShared.protocol : "legacy";
48
+ const requirements = isSharedModuleManifest(remoteShared) ? remoteShared.requirements : (
49
+ // @legacy(remote-components<=0.4.x): normalize the historical shared
50
+ // map until hosts and remotes on 0.4.x are no longer supported.
51
+ Object.entries(remoteShared).map(([id, specifier]) => ({
52
+ id,
53
+ specifier: String(specifier),
54
+ required: true,
55
+ singleton: true
56
+ }))
57
+ );
58
+ const entries = requirements.map((requirement) => {
59
+ const specifier = String(requirement.specifier);
36
60
  const provider = hostShared[specifier];
37
61
  const entry = {
38
- id,
62
+ id: String(requirement.id),
39
63
  specifier,
40
- required: true,
41
- singleton: true,
42
- scope,
64
+ required: requirement.required ?? true,
65
+ singleton: requirement.singleton ?? true,
66
+ scope: requirement.scope ?? scope,
43
67
  provider,
44
68
  status: typeof provider === "undefined" ? "missing" : "resolved"
45
69
  };
46
70
  if (entry.status === "missing") {
47
71
  (0, import_logger.logDebug)(
48
72
  callerTag,
49
- `Remote "${bundle}" requests "${specifier}" for "${id}" but the host does not provide it`
73
+ `Remote "${bundle}" requests "${specifier}" for "${entry.id}" but the host does not provide it`
50
74
  );
51
75
  }
52
76
  return entry;
53
77
  });
54
78
  (0, import_logger.logDebug)(
55
79
  callerTag,
56
- `Share plan for "${bundle}": ${entries.map((entry) => `${entry.id}=>${entry.specifier}:${entry.status}`).join(", ")}`
80
+ `Share plan (${protocol}) for "${bundle}": ${entries.map((entry) => `${entry.id}=>${entry.specifier}:${entry.status}`).join(", ")}`
57
81
  );
58
82
  return {
59
- protocol: "v0",
83
+ protocol,
60
84
  bundle,
61
85
  entries
62
86
  };
63
87
  }
88
+ function missingRequiredSharedModuleMessage(plan, entry) {
89
+ return `Remote Component "${plan.bundle}" requires shared module "${entry.specifier}", but the host does not provide it. Add it to the host shared modules through \`withRemoteComponentsConfig({ shared: [...] })\` or the \`shared\` prop. This diagnostic runs when both host and remote support the shared-module manifest in remote-components >=0.5.0. The remote may load its bundled copy during the compatibility window; this will become a load error after remote-components <=0.4.x support is removed.`;
90
+ }
91
+ function logMissingRequiredSharedModule(callerTag, plan, entry) {
92
+ (0, import_logger.logError)(callerTag, missingRequiredSharedModuleMessage(plan, entry));
93
+ }
64
94
  async function resolveSharedModulePlan(plan) {
65
95
  const resolved = {};
66
96
  await Promise.all(
67
97
  plan.entries.map(async (entry) => {
68
- if (entry.status !== "resolved")
98
+ if (entry.status !== "resolved") {
99
+ if (plan.protocol === SHARED_MODULE_MANIFEST_PROTOCOL && entry.required) {
100
+ logMissingRequiredSharedModule("SharedBroker", plan, entry);
101
+ }
69
102
  return;
103
+ }
70
104
  const value = typeof entry.provider === "function" ? await entry.provider(plan.bundle) : entry.provider;
71
105
  resolved[entry.id] = value;
72
106
  })
@@ -82,6 +116,10 @@ async function installSharedModulePlan({
82
116
  return Promise.all(
83
117
  plan.entries.map(async (entry) => {
84
118
  if (entry.status !== "resolved") {
119
+ if (plan.protocol === SHARED_MODULE_MANIFEST_PROTOCOL && entry.required) {
120
+ logMissingRequiredSharedModule(callerTag, plan, entry);
121
+ return void 0;
122
+ }
85
123
  if (onMissing) {
86
124
  onMissing(entry);
87
125
  } else {
@@ -99,8 +137,11 @@ async function installSharedModulePlan({
99
137
  }
100
138
  // Annotate the CommonJS export names for ESM import in node:
101
139
  0 && (module.exports = {
140
+ SHARED_MODULE_MANIFEST_PROTOCOL,
102
141
  createSharedModulePlan,
142
+ getMissingSharedModulesMessage,
103
143
  installSharedModulePlan,
144
+ isSharedModuleManifest,
104
145
  resolveSharedModulePlan
105
146
  });
106
147
  //# sourceMappingURL=shared-broker.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/host/shared/shared-broker.ts"],"sourcesContent":["import type { LogLocation } from '#internal/utils/logger';\nimport { logDebug, logError } from '#internal/utils/logger';\n\nexport type SharedModuleFactory = (bundle?: string) => Promise<unknown>;\n\nexport interface SharedModuleRequirement {\n id: string;\n specifier: string;\n required: boolean;\n singleton: boolean;\n scope: string;\n}\n\nexport interface SharedModuleResolution extends SharedModuleRequirement {\n provider?: SharedModuleFactory | unknown;\n status: 'resolved' | 'missing';\n}\n\nexport interface SharedModulePlan {\n protocol: 'v0';\n bundle: string;\n entries: SharedModuleResolution[];\n}\n\nexport function createSharedModulePlan({\n bundle,\n hostShared,\n remoteShared,\n scope = `remote:${bundle}`,\n callerTag = 'SharedBroker',\n}: {\n bundle: string;\n hostShared: Record<string, SharedModuleFactory | unknown>;\n remoteShared: Record<string, string | number>;\n scope?: string;\n callerTag?: LogLocation;\n}): SharedModulePlan {\n const entries = Object.entries(remoteShared).map(([id, rawSpecifier]) => {\n const specifier = String(rawSpecifier);\n const provider = hostShared[specifier];\n const entry: SharedModuleResolution = {\n id,\n specifier,\n required: true,\n singleton: true,\n scope,\n provider,\n status: typeof provider === 'undefined' ? 'missing' : 'resolved',\n };\n\n if (entry.status === 'missing') {\n logDebug(\n callerTag,\n `Remote \"${bundle}\" requests \"${specifier}\" for \"${id}\" but the host does not provide it`,\n );\n }\n\n return entry;\n });\n\n logDebug(\n callerTag,\n `Share plan for \"${bundle}\": ${entries\n .map((entry) => `${entry.id}=>${entry.specifier}:${entry.status}`)\n .join(', ')}`,\n );\n\n return {\n protocol: 'v0',\n bundle,\n entries,\n };\n}\n\nexport async function resolveSharedModulePlan(\n plan: SharedModulePlan,\n): Promise<Record<string, unknown>> {\n const resolved: Record<string, unknown> = {};\n\n await Promise.all(\n plan.entries.map(async (entry) => {\n if (entry.status !== 'resolved') return;\n const value =\n typeof entry.provider === 'function'\n ? await (entry.provider as SharedModuleFactory)(plan.bundle)\n : entry.provider;\n resolved[entry.id] = value;\n }),\n );\n\n return resolved;\n}\n\nexport async function installSharedModulePlan({\n plan,\n target,\n callerTag = 'SharedBroker',\n onMissing,\n}: {\n plan: SharedModulePlan;\n target: Record<string, unknown>;\n callerTag?: LogLocation;\n onMissing?: (entry: SharedModuleResolution) => void;\n}): Promise<undefined[]> {\n return Promise.all(\n plan.entries.map(async (entry) => {\n if (entry.status !== 'resolved') {\n if (onMissing) {\n onMissing(entry);\n } else {\n logError(\n callerTag,\n `Shared module \"${entry.specifier}\" not found for \"${plan.bundle}\".`,\n );\n }\n return undefined;\n }\n\n target[entry.id] =\n typeof entry.provider === 'function'\n ? await (entry.provider as SharedModuleFactory)(plan.bundle)\n : entry.provider;\n return undefined;\n }),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAAmC;AAuB5B,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ,UAAU;AAAA,EAClB,YAAY;AACd,GAMqB;AACnB,QAAM,UAAU,OAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,IAAI,YAAY,MAAM;AACvE,UAAM,YAAY,OAAO,YAAY;AACrC,UAAM,WAAW,WAAW,SAAS;AACrC,UAAM,QAAgC;AAAA,MACpC;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,QAAQ,OAAO,aAAa,cAAc,YAAY;AAAA,IACxD;AAEA,QAAI,MAAM,WAAW,WAAW;AAC9B;AAAA,QACE;AAAA,QACA,WAAW,qBAAqB,mBAAmB;AAAA,MACrD;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AAED;AAAA,IACE;AAAA,IACA,mBAAmB,YAAY,QAC5B,IAAI,CAAC,UAAU,GAAG,MAAM,OAAO,MAAM,aAAa,MAAM,QAAQ,EAChE,KAAK,IAAI;AAAA,EACd;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,wBACpB,MACkC;AAClC,QAAM,WAAoC,CAAC;AAE3C,QAAM,QAAQ;AAAA,IACZ,KAAK,QAAQ,IAAI,OAAO,UAAU;AAChC,UAAI,MAAM,WAAW;AAAY;AACjC,YAAM,QACJ,OAAO,MAAM,aAAa,aACtB,MAAO,MAAM,SAAiC,KAAK,MAAM,IACzD,MAAM;AACZ,eAAS,MAAM,EAAE,IAAI;AAAA,IACvB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,eAAsB,wBAAwB;AAAA,EAC5C;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAKyB;AACvB,SAAO,QAAQ;AAAA,IACb,KAAK,QAAQ,IAAI,OAAO,UAAU;AAChC,UAAI,MAAM,WAAW,YAAY;AAC/B,YAAI,WAAW;AACb,oBAAU,KAAK;AAAA,QACjB,OAAO;AACL;AAAA,YACE;AAAA,YACA,kBAAkB,MAAM,6BAA6B,KAAK;AAAA,UAC5D;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAEA,aAAO,MAAM,EAAE,IACb,OAAO,MAAM,aAAa,aACtB,MAAO,MAAM,SAAiC,KAAK,MAAM,IACzD,MAAM;AACZ,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/host/shared/shared-broker.ts"],"sourcesContent":["import type { LogLocation } from '#internal/utils/logger';\nimport { logDebug, logError } from '#internal/utils/logger';\n\nexport type SharedModuleFactory = (bundle?: string) => Promise<unknown>;\n\nexport const SHARED_MODULE_MANIFEST_PROTOCOL =\n 'remote-components.shared.v1' as const;\n\nexport type LegacySharedModuleMap = Record<string, string | number>;\n\nexport interface SharedModuleManifestRequirement {\n id: string | number;\n specifier: string;\n required?: boolean;\n singleton?: boolean;\n scope?: string;\n}\n\nexport interface SharedModuleManifest {\n protocol: typeof SHARED_MODULE_MANIFEST_PROTOCOL;\n requirements: SharedModuleManifestRequirement[];\n}\n\nexport type RemoteSharedModules = LegacySharedModuleMap | SharedModuleManifest;\n\nexport interface SharedModuleRequirement {\n id: string;\n specifier: string;\n required: boolean;\n singleton: boolean;\n scope: string;\n}\n\nexport interface SharedModuleResolution extends SharedModuleRequirement {\n provider?: SharedModuleFactory | unknown;\n status: 'resolved' | 'missing';\n}\n\nexport interface SharedModulePlan {\n protocol: 'legacy' | typeof SHARED_MODULE_MANIFEST_PROTOCOL;\n bundle: string;\n entries: SharedModuleResolution[];\n}\n\nexport function isSharedModuleManifest(\n value: unknown,\n): value is SharedModuleManifest {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'protocol' in value &&\n value.protocol === SHARED_MODULE_MANIFEST_PROTOCOL &&\n 'requirements' in value &&\n Array.isArray(value.requirements)\n );\n}\n\nexport function getMissingSharedModulesMessage(\n remoteShared: RemoteSharedModules,\n): string | undefined {\n if (isSharedModuleManifest(remoteShared)) return undefined;\n const message = remoteShared.__remote_components_missing_shared__;\n return typeof message === 'string' ? message : undefined;\n}\n\nexport function createSharedModulePlan({\n bundle,\n hostShared,\n remoteShared,\n scope = `remote:${bundle}`,\n callerTag = 'SharedBroker',\n}: {\n bundle: string;\n hostShared: Record<string, SharedModuleFactory | unknown>;\n remoteShared: RemoteSharedModules;\n scope?: string;\n callerTag?: LogLocation;\n}): SharedModulePlan {\n const protocol = isSharedModuleManifest(remoteShared)\n ? remoteShared.protocol\n : 'legacy';\n const requirements: SharedModuleManifestRequirement[] =\n isSharedModuleManifest(remoteShared)\n ? remoteShared.requirements\n : // @legacy(remote-components<=0.4.x): normalize the historical shared\n // map until hosts and remotes on 0.4.x are no longer supported.\n Object.entries(remoteShared).map(([id, specifier]) => ({\n id,\n specifier: String(specifier),\n required: true,\n singleton: true,\n }));\n\n const entries = requirements.map((requirement) => {\n const specifier = String(requirement.specifier);\n const provider = hostShared[specifier];\n const entry: SharedModuleResolution = {\n id: String(requirement.id),\n specifier,\n required: requirement.required ?? true,\n singleton: requirement.singleton ?? true,\n scope: requirement.scope ?? scope,\n provider,\n status: typeof provider === 'undefined' ? 'missing' : 'resolved',\n };\n\n if (entry.status === 'missing') {\n logDebug(\n callerTag,\n `Remote \"${bundle}\" requests \"${specifier}\" for \"${entry.id}\" but the host does not provide it`,\n );\n }\n\n return entry;\n });\n\n logDebug(\n callerTag,\n `Share plan (${protocol}) for \"${bundle}\": ${entries\n .map((entry) => `${entry.id}=>${entry.specifier}:${entry.status}`)\n .join(', ')}`,\n );\n\n return {\n protocol,\n bundle,\n entries,\n };\n}\n\nfunction missingRequiredSharedModuleMessage(\n plan: SharedModulePlan,\n entry: SharedModuleResolution,\n): string {\n return (\n `Remote Component \"${plan.bundle}\" requires shared module \"${entry.specifier}\", but the host does not provide it. ` +\n 'Add it to the host shared modules through `withRemoteComponentsConfig({ shared: [...] })` or the `shared` prop. ' +\n 'This diagnostic runs when both host and remote support the shared-module manifest in remote-components >=0.5.0. ' +\n 'The remote may load its bundled copy during the compatibility window; this will become a load error after remote-components <=0.4.x support is removed.'\n );\n}\n\nfunction logMissingRequiredSharedModule(\n callerTag: LogLocation,\n plan: SharedModulePlan,\n entry: SharedModuleResolution,\n): void {\n logError(callerTag, missingRequiredSharedModuleMessage(plan, entry));\n}\n\nexport async function resolveSharedModulePlan(\n plan: SharedModulePlan,\n): Promise<Record<string, unknown>> {\n const resolved: Record<string, unknown> = {};\n\n await Promise.all(\n plan.entries.map(async (entry) => {\n if (entry.status !== 'resolved') {\n if (\n plan.protocol === SHARED_MODULE_MANIFEST_PROTOCOL &&\n entry.required\n ) {\n logMissingRequiredSharedModule('SharedBroker', plan, entry);\n }\n return;\n }\n const value =\n typeof entry.provider === 'function'\n ? await (entry.provider as SharedModuleFactory)(plan.bundle)\n : entry.provider;\n resolved[entry.id] = value;\n }),\n );\n\n return resolved;\n}\n\nexport async function installSharedModulePlan({\n plan,\n target,\n callerTag = 'SharedBroker',\n onMissing,\n}: {\n plan: SharedModulePlan;\n target: Record<string, unknown>;\n callerTag?: LogLocation;\n onMissing?: (entry: SharedModuleResolution) => void;\n}): Promise<undefined[]> {\n return Promise.all(\n plan.entries.map(async (entry) => {\n if (entry.status !== 'resolved') {\n if (\n plan.protocol === SHARED_MODULE_MANIFEST_PROTOCOL &&\n entry.required\n ) {\n logMissingRequiredSharedModule(callerTag, plan, entry);\n return undefined;\n }\n if (onMissing) {\n onMissing(entry);\n } else {\n logError(\n callerTag,\n `Shared module \"${entry.specifier}\" not found for \"${plan.bundle}\".`,\n );\n }\n return undefined;\n }\n\n target[entry.id] =\n typeof entry.provider === 'function'\n ? await (entry.provider as SharedModuleFactory)(plan.bundle)\n : entry.provider;\n return undefined;\n }),\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,20 @@
1
1
  import { LogLocation } from '../../utils/logger.js';
2
2
 
3
3
  type SharedModuleFactory = (bundle?: string) => Promise<unknown>;
4
+ declare const SHARED_MODULE_MANIFEST_PROTOCOL: "remote-components.shared.v1";
5
+ type LegacySharedModuleMap = Record<string, string | number>;
6
+ interface SharedModuleManifestRequirement {
7
+ id: string | number;
8
+ specifier: string;
9
+ required?: boolean;
10
+ singleton?: boolean;
11
+ scope?: string;
12
+ }
13
+ interface SharedModuleManifest {
14
+ protocol: typeof SHARED_MODULE_MANIFEST_PROTOCOL;
15
+ requirements: SharedModuleManifestRequirement[];
16
+ }
17
+ type RemoteSharedModules = LegacySharedModuleMap | SharedModuleManifest;
4
18
  interface SharedModuleRequirement {
5
19
  id: string;
6
20
  specifier: string;
@@ -13,14 +27,16 @@ interface SharedModuleResolution extends SharedModuleRequirement {
13
27
  status: 'resolved' | 'missing';
14
28
  }
15
29
  interface SharedModulePlan {
16
- protocol: 'v0';
30
+ protocol: 'legacy' | typeof SHARED_MODULE_MANIFEST_PROTOCOL;
17
31
  bundle: string;
18
32
  entries: SharedModuleResolution[];
19
33
  }
34
+ declare function isSharedModuleManifest(value: unknown): value is SharedModuleManifest;
35
+ declare function getMissingSharedModulesMessage(remoteShared: RemoteSharedModules): string | undefined;
20
36
  declare function createSharedModulePlan({ bundle, hostShared, remoteShared, scope, callerTag, }: {
21
37
  bundle: string;
22
38
  hostShared: Record<string, SharedModuleFactory | unknown>;
23
- remoteShared: Record<string, string | number>;
39
+ remoteShared: RemoteSharedModules;
24
40
  scope?: string;
25
41
  callerTag?: LogLocation;
26
42
  }): SharedModulePlan;
@@ -32,4 +48,4 @@ declare function installSharedModulePlan({ plan, target, callerTag, onMissing, }
32
48
  onMissing?: (entry: SharedModuleResolution) => void;
33
49
  }): Promise<undefined[]>;
34
50
 
35
- export { SharedModuleFactory, SharedModulePlan, SharedModuleRequirement, SharedModuleResolution, createSharedModulePlan, installSharedModulePlan, resolveSharedModulePlan };
51
+ export { LegacySharedModuleMap, RemoteSharedModules, SHARED_MODULE_MANIFEST_PROTOCOL, SharedModuleFactory, SharedModuleManifest, SharedModuleManifestRequirement, SharedModulePlan, SharedModuleRequirement, SharedModuleResolution, createSharedModulePlan, getMissingSharedModulesMessage, installSharedModulePlan, isSharedModuleManifest, resolveSharedModulePlan };
@@ -1,4 +1,14 @@
1
1
  import { logDebug, logError } from "#internal/utils/logger";
2
+ const SHARED_MODULE_MANIFEST_PROTOCOL = "remote-components.shared.v1";
3
+ function isSharedModuleManifest(value) {
4
+ return typeof value === "object" && value !== null && "protocol" in value && value.protocol === SHARED_MODULE_MANIFEST_PROTOCOL && "requirements" in value && Array.isArray(value.requirements);
5
+ }
6
+ function getMissingSharedModulesMessage(remoteShared) {
7
+ if (isSharedModuleManifest(remoteShared))
8
+ return void 0;
9
+ const message = remoteShared.__remote_components_missing_shared__;
10
+ return typeof message === "string" ? message : void 0;
11
+ }
2
12
  function createSharedModulePlan({
3
13
  bundle,
4
14
  hostShared,
@@ -6,42 +16,63 @@ function createSharedModulePlan({
6
16
  scope = `remote:${bundle}`,
7
17
  callerTag = "SharedBroker"
8
18
  }) {
9
- const entries = Object.entries(remoteShared).map(([id, rawSpecifier]) => {
10
- const specifier = String(rawSpecifier);
19
+ const protocol = isSharedModuleManifest(remoteShared) ? remoteShared.protocol : "legacy";
20
+ const requirements = isSharedModuleManifest(remoteShared) ? remoteShared.requirements : (
21
+ // @legacy(remote-components<=0.4.x): normalize the historical shared
22
+ // map until hosts and remotes on 0.4.x are no longer supported.
23
+ Object.entries(remoteShared).map(([id, specifier]) => ({
24
+ id,
25
+ specifier: String(specifier),
26
+ required: true,
27
+ singleton: true
28
+ }))
29
+ );
30
+ const entries = requirements.map((requirement) => {
31
+ const specifier = String(requirement.specifier);
11
32
  const provider = hostShared[specifier];
12
33
  const entry = {
13
- id,
34
+ id: String(requirement.id),
14
35
  specifier,
15
- required: true,
16
- singleton: true,
17
- scope,
36
+ required: requirement.required ?? true,
37
+ singleton: requirement.singleton ?? true,
38
+ scope: requirement.scope ?? scope,
18
39
  provider,
19
40
  status: typeof provider === "undefined" ? "missing" : "resolved"
20
41
  };
21
42
  if (entry.status === "missing") {
22
43
  logDebug(
23
44
  callerTag,
24
- `Remote "${bundle}" requests "${specifier}" for "${id}" but the host does not provide it`
45
+ `Remote "${bundle}" requests "${specifier}" for "${entry.id}" but the host does not provide it`
25
46
  );
26
47
  }
27
48
  return entry;
28
49
  });
29
50
  logDebug(
30
51
  callerTag,
31
- `Share plan for "${bundle}": ${entries.map((entry) => `${entry.id}=>${entry.specifier}:${entry.status}`).join(", ")}`
52
+ `Share plan (${protocol}) for "${bundle}": ${entries.map((entry) => `${entry.id}=>${entry.specifier}:${entry.status}`).join(", ")}`
32
53
  );
33
54
  return {
34
- protocol: "v0",
55
+ protocol,
35
56
  bundle,
36
57
  entries
37
58
  };
38
59
  }
60
+ function missingRequiredSharedModuleMessage(plan, entry) {
61
+ return `Remote Component "${plan.bundle}" requires shared module "${entry.specifier}", but the host does not provide it. Add it to the host shared modules through \`withRemoteComponentsConfig({ shared: [...] })\` or the \`shared\` prop. This diagnostic runs when both host and remote support the shared-module manifest in remote-components >=0.5.0. The remote may load its bundled copy during the compatibility window; this will become a load error after remote-components <=0.4.x support is removed.`;
62
+ }
63
+ function logMissingRequiredSharedModule(callerTag, plan, entry) {
64
+ logError(callerTag, missingRequiredSharedModuleMessage(plan, entry));
65
+ }
39
66
  async function resolveSharedModulePlan(plan) {
40
67
  const resolved = {};
41
68
  await Promise.all(
42
69
  plan.entries.map(async (entry) => {
43
- if (entry.status !== "resolved")
70
+ if (entry.status !== "resolved") {
71
+ if (plan.protocol === SHARED_MODULE_MANIFEST_PROTOCOL && entry.required) {
72
+ logMissingRequiredSharedModule("SharedBroker", plan, entry);
73
+ }
44
74
  return;
75
+ }
45
76
  const value = typeof entry.provider === "function" ? await entry.provider(plan.bundle) : entry.provider;
46
77
  resolved[entry.id] = value;
47
78
  })
@@ -57,6 +88,10 @@ async function installSharedModulePlan({
57
88
  return Promise.all(
58
89
  plan.entries.map(async (entry) => {
59
90
  if (entry.status !== "resolved") {
91
+ if (plan.protocol === SHARED_MODULE_MANIFEST_PROTOCOL && entry.required) {
92
+ logMissingRequiredSharedModule(callerTag, plan, entry);
93
+ return void 0;
94
+ }
60
95
  if (onMissing) {
61
96
  onMissing(entry);
62
97
  } else {
@@ -73,8 +108,11 @@ async function installSharedModulePlan({
73
108
  );
74
109
  }
75
110
  export {
111
+ SHARED_MODULE_MANIFEST_PROTOCOL,
76
112
  createSharedModulePlan,
113
+ getMissingSharedModulesMessage,
77
114
  installSharedModulePlan,
115
+ isSharedModuleManifest,
78
116
  resolveSharedModulePlan
79
117
  };
80
118
  //# sourceMappingURL=shared-broker.js.map