@bleedingdev/modern-js-runtime 3.5.0-ultramodern.10 → 3.5.0-ultramodern.101

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 (155) hide show
  1. package/dist/cjs/boundary-debugger/index.js +13 -3
  2. package/dist/cjs/cli/index.js +1 -11
  3. package/dist/cjs/cli/registry.js +18 -0
  4. package/dist/cjs/cli/ssr/index.js +3 -2
  5. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +8 -4
  6. package/dist/cjs/core/browser/hydrate.js +16 -2
  7. package/dist/cjs/core/browser/index.js +19 -18
  8. package/dist/cjs/core/context/index.js +3 -0
  9. package/dist/cjs/core/context/public.js +49 -0
  10. package/dist/cjs/core/context/runtime.js +6 -8
  11. package/dist/cjs/core/react/wrapper.js +57 -0
  12. package/dist/cjs/core/server/federatedCss.js +7 -3
  13. package/dist/cjs/core/server/requestHandler.js +15 -45
  14. package/dist/cjs/core/server/requestResponse.js +83 -0
  15. package/dist/cjs/core/server/routerCleanup.js +16 -6
  16. package/dist/cjs/core/server/scriptOrder.js +13 -10
  17. package/dist/cjs/core/server/stream/afterTemplate.js +9 -5
  18. package/dist/cjs/core/server/stream/template.js +3 -3
  19. package/dist/cjs/core/server/string/index.js +3 -3
  20. package/dist/cjs/core/server/string/loadable.js +3 -11
  21. package/dist/cjs/document/cli/index.js +5 -2
  22. package/dist/cjs/index.js +7 -6
  23. package/dist/cjs/module-federation/consume-surface.js +199 -0
  24. package/dist/cjs/module-federation/distributed-ssr.js +134 -0
  25. package/dist/cjs/module-federation/index.js +258 -120
  26. package/dist/cjs/module-federation/last-known-good.js +124 -0
  27. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +140 -0
  28. package/dist/cjs/module-federation/surface-resolution-types.js +61 -0
  29. package/dist/cjs/router/cli/code/nestedRoutes.js +3 -0
  30. package/dist/cjs/router/cli/code/templates.js +3 -2
  31. package/dist/cjs/router/cli/constants.js +1 -0
  32. package/dist/cjs/router/cli/nestedRoutesSpec.js +3 -1
  33. package/dist/cjs/router/runtime/hooks.js +7 -6
  34. package/dist/cjs/router/runtime/internal.js +30 -16
  35. package/dist/cjs/router/runtime/plugin.js +6 -7
  36. package/dist/cjs/router/runtime/provider.js +58 -12
  37. package/dist/esm/boundary-debugger/index.mjs +13 -3
  38. package/dist/esm/cli/code.mjs +12 -12
  39. package/dist/esm/cli/index.mjs +2 -12
  40. package/dist/esm/cli/registry.mjs +0 -0
  41. package/dist/esm/cli/ssr/index.mjs +3 -2
  42. package/dist/esm/cli/ssr/loadable-bundler-plugin.mjs +8 -4
  43. package/dist/esm/core/browser/hydrate.mjs +15 -4
  44. package/dist/esm/core/browser/index.mjs +15 -17
  45. package/dist/esm/core/context/index.mjs +1 -1
  46. package/dist/esm/core/context/public.mjs +5 -0
  47. package/dist/esm/core/context/runtime.mjs +4 -6
  48. package/dist/esm/core/react/wrapper.mjs +58 -1
  49. package/dist/esm/core/server/federatedCss.mjs +7 -3
  50. package/dist/esm/core/server/requestHandler.mjs +15 -45
  51. package/dist/esm/core/server/requestResponse.mjs +39 -0
  52. package/dist/esm/core/server/routerCleanup.mjs +11 -4
  53. package/dist/esm/core/server/scriptOrder.mjs +11 -8
  54. package/dist/esm/core/server/stream/afterTemplate.mjs +10 -6
  55. package/dist/esm/core/server/stream/template.mjs +3 -3
  56. package/dist/esm/core/server/string/index.mjs +3 -3
  57. package/dist/esm/core/server/string/loadable.mjs +3 -8
  58. package/dist/esm/document/cli/index.mjs +1 -1
  59. package/dist/esm/exports/loadable.mjs +3 -3
  60. package/dist/esm/index.mjs +2 -1
  61. package/dist/esm/module-federation/consume-surface.mjs +158 -0
  62. package/dist/esm/module-federation/distributed-ssr.mjs +81 -0
  63. package/dist/esm/module-federation/index.mjs +6 -0
  64. package/dist/esm/module-federation/last-known-good.mjs +80 -0
  65. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +100 -0
  66. package/dist/esm/module-federation/surface-resolution-types.mjs +8 -0
  67. package/dist/esm/router/cli/code/index.mjs +5 -5
  68. package/dist/esm/router/cli/code/nestedRoutes.mjs +3 -0
  69. package/dist/esm/router/cli/code/templates.mjs +3 -2
  70. package/dist/esm/router/cli/constants.mjs +1 -0
  71. package/dist/esm/router/cli/handler.mjs +3 -3
  72. package/dist/esm/router/cli/nestedRoutesSpec.mjs +3 -1
  73. package/dist/esm/router/runtime/hooks.mjs +7 -6
  74. package/dist/esm/router/runtime/internal.mjs +26 -18
  75. package/dist/esm/router/runtime/plugin.mjs +6 -7
  76. package/dist/esm/router/runtime/provider.mjs +56 -13
  77. package/dist/esm-node/boundary-debugger/index.mjs +13 -3
  78. package/dist/esm-node/cli/code.mjs +12 -12
  79. package/dist/esm-node/cli/index.mjs +2 -12
  80. package/dist/esm-node/cli/registry.mjs +1 -0
  81. package/dist/esm-node/cli/ssr/index.mjs +3 -2
  82. package/dist/esm-node/cli/ssr/loadable-bundler-plugin.mjs +8 -4
  83. package/dist/esm-node/core/browser/hydrate.mjs +15 -4
  84. package/dist/esm-node/core/browser/index.mjs +15 -17
  85. package/dist/esm-node/core/context/index.mjs +1 -1
  86. package/dist/esm-node/core/context/public.mjs +6 -0
  87. package/dist/esm-node/core/context/runtime.mjs +4 -6
  88. package/dist/esm-node/core/react/wrapper.mjs +58 -1
  89. package/dist/esm-node/core/server/federatedCss.mjs +7 -3
  90. package/dist/esm-node/core/server/requestHandler.mjs +15 -45
  91. package/dist/esm-node/core/server/requestResponse.mjs +40 -0
  92. package/dist/esm-node/core/server/routerCleanup.mjs +11 -4
  93. package/dist/esm-node/core/server/scriptOrder.mjs +11 -8
  94. package/dist/esm-node/core/server/stream/afterTemplate.mjs +10 -6
  95. package/dist/esm-node/core/server/stream/template.mjs +3 -3
  96. package/dist/esm-node/core/server/string/index.mjs +3 -3
  97. package/dist/esm-node/core/server/string/loadable.mjs +3 -8
  98. package/dist/esm-node/document/cli/index.mjs +1 -1
  99. package/dist/esm-node/exports/loadable.mjs +3 -3
  100. package/dist/esm-node/index.mjs +2 -1
  101. package/dist/esm-node/module-federation/consume-surface.mjs +159 -0
  102. package/dist/esm-node/module-federation/distributed-ssr.mjs +82 -0
  103. package/dist/esm-node/module-federation/index.mjs +6 -0
  104. package/dist/esm-node/module-federation/last-known-good.mjs +81 -0
  105. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +101 -0
  106. package/dist/esm-node/module-federation/surface-resolution-types.mjs +9 -0
  107. package/dist/esm-node/router/cli/code/index.mjs +5 -5
  108. package/dist/esm-node/router/cli/code/nestedRoutes.mjs +3 -0
  109. package/dist/esm-node/router/cli/code/templates.mjs +3 -2
  110. package/dist/esm-node/router/cli/constants.mjs +1 -0
  111. package/dist/esm-node/router/cli/handler.mjs +3 -3
  112. package/dist/esm-node/router/cli/nestedRoutesSpec.mjs +3 -1
  113. package/dist/esm-node/router/runtime/hooks.mjs +7 -6
  114. package/dist/esm-node/router/runtime/internal.mjs +26 -18
  115. package/dist/esm-node/router/runtime/plugin.mjs +6 -7
  116. package/dist/esm-node/router/runtime/provider.mjs +56 -13
  117. package/dist/types/boundary-debugger/index.d.ts +1 -1
  118. package/dist/types/cli/registry.d.ts +2 -0
  119. package/dist/types/common.d.ts +8 -1
  120. package/dist/types/core/browser/hydrate.d.ts +2 -1
  121. package/dist/types/core/browser/index.d.ts +4 -1
  122. package/dist/types/core/context/index.d.ts +26 -10
  123. package/dist/types/core/context/monitors/default.d.ts +10 -2
  124. package/dist/types/core/context/monitors/index.d.ts +1 -1
  125. package/dist/types/core/context/monitors/index.server.d.ts +2 -2
  126. package/dist/types/core/context/public.d.ts +27 -0
  127. package/dist/types/core/context/runtime.d.ts +12 -22
  128. package/dist/types/core/react/index.d.ts +1 -1
  129. package/dist/types/core/server/requestResponse.d.ts +15 -0
  130. package/dist/types/core/server/routerCleanup.d.ts +2 -1
  131. package/dist/types/core/server/scriptOrder.d.ts +1 -1
  132. package/dist/types/core/server/stream/shared.d.ts +2 -2
  133. package/dist/types/core/server/string/loadable.d.ts +0 -2
  134. package/dist/types/document/cli/index.d.ts +1 -0
  135. package/dist/types/exports/head.d.ts +1 -1
  136. package/dist/types/index.d.ts +5 -5
  137. package/dist/types/internal.d.ts +0 -1
  138. package/dist/types/module-federation/consume-surface.d.ts +104 -0
  139. package/dist/types/module-federation/distributed-ssr.d.ts +61 -0
  140. package/dist/types/module-federation/index.d.ts +6 -0
  141. package/dist/types/module-federation/last-known-good.d.ts +72 -0
  142. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +25 -0
  143. package/dist/types/module-federation/surface-resolution-types.d.ts +23 -0
  144. package/dist/types/router/cli/constants.d.ts +1 -0
  145. package/dist/types/router/runtime/hooks.d.ts +10 -6
  146. package/dist/types/router/runtime/internal.d.ts +13 -3
  147. package/dist/types/router/runtime/plugin.d.ts +1 -1
  148. package/dist/types/router/runtime/plugin.node.d.ts +1 -1
  149. package/dist/types/router/runtime/provider.d.ts +28 -11
  150. package/dist/types/router/runtime/types.d.ts +27 -5
  151. package/package.json +47 -27
  152. package/dist/cjs/exports/tanstack-router.js +0 -83
  153. package/dist/esm/exports/tanstack-router.mjs +0 -30
  154. package/dist/esm-node/exports/tanstack-router.mjs +0 -31
  155. package/dist/types/exports/tanstack-router.d.ts +0 -88
@@ -0,0 +1,159 @@
1
+ import "node:module";
2
+ import { classifyModuleFederationFallback, createModuleFederationFallbackTelemetry, emitModuleFederationFallbackTelemetry } from "./index.mjs";
3
+ import { createDiscoveryError, formatSurfaceRef, parseSurfaceRef, validateSurfaceRef } from "./surface-resolution-types.mjs";
4
+ function classifyDiscoveryError(code) {
5
+ switch(code){
6
+ case 'major-not-published':
7
+ case 'stale-record':
8
+ return 'version-skew';
9
+ case 'identity-mismatch':
10
+ return 'contract';
11
+ case 'unknown-unit':
12
+ case 'unknown-surface':
13
+ case 'provider-unavailable':
14
+ return 'remote-unavailable';
15
+ default:
16
+ return 'remote-unavailable';
17
+ }
18
+ }
19
+ function toRemoteString(ref) {
20
+ return void 0 === validateSurfaceRef(ref) ? formatSurfaceRef(ref) : `${ref.unitId}#${ref.surfaceId}`;
21
+ }
22
+ async function reportFailure(options, ref, base) {
23
+ const remote = toRemoteString(ref);
24
+ const telemetry = createModuleFederationFallbackTelemetry({
25
+ appName: options.appName,
26
+ classification: base.classification,
27
+ error: base.error ?? base.discoveryError,
28
+ metadata: {
29
+ env: options.env,
30
+ surfaceRef: remote,
31
+ ...base.discoveryError ? {
32
+ discoveryErrorCode: base.discoveryError.code
33
+ } : {},
34
+ ...base.resolved ? {
35
+ buildMarker: base.resolved.buildMarker
36
+ } : {}
37
+ },
38
+ phase: base.phase,
39
+ remote,
40
+ status: 'degraded'
41
+ });
42
+ try {
43
+ await emitModuleFederationFallbackTelemetry({
44
+ appName: options.appName,
45
+ classification: base.classification,
46
+ error: base.error ?? base.discoveryError,
47
+ metadata: telemetry.metadata,
48
+ phase: base.phase,
49
+ remote,
50
+ status: 'degraded'
51
+ }, options.telemetry ?? {});
52
+ } catch {}
53
+ const failure = {
54
+ ref,
55
+ env: options.env,
56
+ phase: base.phase,
57
+ classification: base.classification,
58
+ telemetry
59
+ };
60
+ if (base.discoveryError) failure.discoveryError = base.discoveryError;
61
+ if (void 0 !== base.error) failure.error = base.error;
62
+ if (base.resolved) failure.resolved = base.resolved;
63
+ const critical = (options.classification ?? 'critical') === 'critical';
64
+ const reason = base.discoveryError ?? (void 0 !== base.error ? base.error : createDiscoveryError('identity-mismatch', remote, `resolved record for "${remote}" is incompatible`, {
65
+ env: options.env
66
+ }));
67
+ let degradedValue;
68
+ try {
69
+ degradedValue = await options.degraded(failure);
70
+ } catch (handlerError) {
71
+ try {
72
+ await emitModuleFederationFallbackTelemetry({
73
+ appName: options.appName,
74
+ classification: base.classification,
75
+ error: handlerError,
76
+ metadata: {
77
+ ...telemetry.metadata,
78
+ degradedHandlerFailed: true
79
+ },
80
+ phase: base.phase,
81
+ remote,
82
+ status: 'failed'
83
+ }, options.telemetry ?? {});
84
+ } catch {}
85
+ if (critical) throw reason;
86
+ return;
87
+ }
88
+ if (critical) throw reason;
89
+ return degradedValue;
90
+ }
91
+ async function consumeSurface(options) {
92
+ let ref;
93
+ if ('string' == typeof options.ref) {
94
+ const parsed = parseSurfaceRef(options.ref);
95
+ if (!parsed.ok) {
96
+ const hashIndex = options.ref.indexOf('#');
97
+ const echoed = -1 === hashIndex ? {
98
+ unitId: options.ref,
99
+ surfaceId: ''
100
+ } : {
101
+ unitId: options.ref.slice(0, hashIndex),
102
+ surfaceId: options.ref.slice(hashIndex + 1)
103
+ };
104
+ return reportFailure(options, echoed, {
105
+ phase: 'discovery',
106
+ classification: 'remote-unavailable',
107
+ discoveryError: createDiscoveryError('unknown-surface', options.ref, `SurfaceRef "${options.ref}" is not a valid canonical reference (${parsed.error.code}).`, {
108
+ parseError: parsed.error,
109
+ env: options.env
110
+ })
111
+ });
112
+ }
113
+ ref = parsed.ref;
114
+ } else ref = options.ref;
115
+ let resolution;
116
+ try {
117
+ resolution = await options.provider.resolve(ref, options.env);
118
+ } catch (error) {
119
+ return reportFailure(options, ref, {
120
+ phase: 'discovery',
121
+ classification: classifyModuleFederationFallback(error),
122
+ error
123
+ });
124
+ }
125
+ if (!resolution.ok) return reportFailure(options, ref, {
126
+ phase: 'discovery',
127
+ classification: classifyDiscoveryError(resolution.error.code),
128
+ discoveryError: resolution.error
129
+ });
130
+ const resolved = resolution.unit;
131
+ if ('incompatible' === resolved.compatibility.status) return reportFailure(options, ref, {
132
+ phase: 'discovery',
133
+ classification: 'contract',
134
+ resolved
135
+ });
136
+ try {
137
+ return await options.load({
138
+ resolved,
139
+ ref,
140
+ env: options.env
141
+ });
142
+ } catch (error) {
143
+ return reportFailure(options, ref, {
144
+ phase: 'load',
145
+ classification: classifyModuleFederationFallback(error),
146
+ error,
147
+ resolved
148
+ });
149
+ }
150
+ }
151
+ function createSurfaceConsumer(base) {
152
+ return function(options) {
153
+ return consumeSurface({
154
+ ...base,
155
+ ...options
156
+ });
157
+ };
158
+ }
159
+ export { consumeSurface, createSurfaceConsumer };
@@ -0,0 +1,82 @@
1
+ import "node:module";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useRuntimeContext } from "../core/context/runtime.mjs";
4
+ const DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY = '__modernDistributedSsrFragments';
5
+ const DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY = '__modernDistributedSsrFragmentRequest';
6
+ function distributedSsrFragmentKey(remote, expose) {
7
+ return `${remote}::${expose}`;
8
+ }
9
+ function getDistributedSsrFragmentContext(response) {
10
+ const locals = response?.locals;
11
+ if (!locals || 'object' != typeof locals) return;
12
+ const context = locals[DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY];
13
+ if (!context || 'object' != typeof context) return;
14
+ return context;
15
+ }
16
+ function useDistributedSsrFragmentProps({ boundaryId, expose }) {
17
+ const runtimeContext = useRuntimeContext();
18
+ const locals = runtimeContext.requestContext?.response?.locals;
19
+ const request = locals && 'object' == typeof locals ? locals[DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY] : void 0;
20
+ if (!request || 'object' != typeof request || request.boundaryId !== boundaryId || request.expose !== expose) throw new Error(`Distributed SSR fragment request contract mismatch for ${boundaryId} ${expose}.`);
21
+ const props = request.props;
22
+ if (!props || 'object' != typeof props || Array.isArray(props)) throw new Error(`Distributed SSR fragment request props must be an object for ${boundaryId} ${expose}.`);
23
+ return props;
24
+ }
25
+ function isThenable(value) {
26
+ return 'function' == typeof value.then;
27
+ }
28
+ function DistributedSsrBoundary({ children, expose, fallback, fragmentProps = {}, remote }) {
29
+ const runtimeContext = useRuntimeContext();
30
+ const key = distributedSsrFragmentKey(remote, expose);
31
+ const attributes = {
32
+ 'data-modern-distributed-ssr-boundary': key
33
+ };
34
+ if (runtimeContext.isBrowser) return /*#__PURE__*/ jsx("div", {
35
+ ...attributes,
36
+ children: children
37
+ });
38
+ const fragmentContext = getDistributedSsrFragmentContext(runtimeContext.requestContext?.response);
39
+ if (!fragmentContext) return /*#__PURE__*/ jsx("div", {
40
+ ...attributes,
41
+ children: children
42
+ });
43
+ const fragmentOrPromise = fragmentContext.resolve?.(remote, expose, fragmentProps) ?? fragmentContext.fragments?.[key];
44
+ if (fragmentOrPromise && isThenable(fragmentOrPromise)) throw fragmentOrPromise;
45
+ const fragment = fragmentOrPromise;
46
+ if (fragment?.status === 'ready') return /*#__PURE__*/ jsx("div", {
47
+ ...attributes,
48
+ "data-modern-distributed-ssr-build": fragment.buildMarker,
49
+ "data-modern-distributed-ssr-digest": fragment.digest,
50
+ "data-modern-distributed-ssr-status": "ready",
51
+ dangerouslySetInnerHTML: {
52
+ __html: fragment.html
53
+ }
54
+ });
55
+ return /*#__PURE__*/ jsx("div", {
56
+ ...attributes,
57
+ "data-modern-distributed-ssr-reason": fragment?.reason ?? 'missing',
58
+ "data-modern-distributed-ssr-status": "degraded",
59
+ children: fallback
60
+ });
61
+ }
62
+ function createDistributedSsrComponent({ createComponent, expose, fallback, remote }) {
63
+ let RemoteComponent;
64
+ function DeferredRemoteComponent(props) {
65
+ RemoteComponent ??= createComponent();
66
+ return /*#__PURE__*/ jsx(RemoteComponent, {
67
+ ...props
68
+ });
69
+ }
70
+ return function(props) {
71
+ return /*#__PURE__*/ jsx(DistributedSsrBoundary, {
72
+ expose: expose,
73
+ fallback: fallback,
74
+ fragmentProps: props,
75
+ remote: remote,
76
+ children: /*#__PURE__*/ jsx(DeferredRemoteComponent, {
77
+ ...props
78
+ })
79
+ });
80
+ };
81
+ }
82
+ export { DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY, DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY, DistributedSsrBoundary, createDistributedSsrComponent, distributedSsrFragmentKey, useDistributedSsrFragmentProps };
@@ -1,4 +1,9 @@
1
1
  import "node:module";
2
+ export * from "./consume-surface.mjs";
3
+ export * from "./distributed-ssr.mjs";
4
+ export * from "./last-known-good.mjs";
5
+ export * from "./manifest-recovery-runtime-plugin.mjs";
6
+ export * from "./surface-resolution-types.mjs";
2
7
  const MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT = 'modernjs:mf-runtime-fallback';
3
8
  const MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT = 'modernjs:mf-runtime-recovery';
4
9
  const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = '/_modern/contract-gates/runtime-fallback';
@@ -107,4 +112,5 @@ async function emitModuleFederationFallbackTelemetry(input, options = {}) {
107
112
  postStatus: response.status
108
113
  };
109
114
  }
115
+ export { DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY, useDistributedSsrFragmentProps } from "./distributed-ssr.mjs";
110
116
  export { DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER, DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT, MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT, ModuleFederationRemoteComponentContractError, ModuleFederationRemoteLoadError, ModuleFederationRemoteLoadTimeoutError, classifyModuleFederationFallback, createModuleFederationFallbackTelemetry, emitModuleFederationFallbackTelemetry, toModuleFederationFallbackAttributes };
@@ -0,0 +1,81 @@
1
+ import "node:module";
2
+ import { createDiscoveryError, deliveryUnitResolutionKey } from "./surface-resolution-types.mjs";
3
+ const LAST_KNOWN_GOOD_PROVIDER_NAME = 'last-known-good';
4
+ function createInMemoryLkgStorage() {
5
+ const map = new Map();
6
+ return {
7
+ read (key) {
8
+ return map.get(key);
9
+ },
10
+ write (key, record) {
11
+ map.set(key, record);
12
+ }
13
+ };
14
+ }
15
+ function markDegraded(resolved, reason) {
16
+ return {
17
+ ...resolved,
18
+ compatibility: {
19
+ ...resolved.compatibility,
20
+ status: 'degraded',
21
+ reason
22
+ }
23
+ };
24
+ }
25
+ function staleRecordResult(ref, env, ageMs, maxStaleMs) {
26
+ return {
27
+ ok: false,
28
+ error: createDiscoveryError('stale-record', ref, `Last-known-good record for surface is stale: age ${ageMs}ms exceeds maxStaleMs ${maxStaleMs}ms`, {
29
+ env,
30
+ ageMs,
31
+ maxStaleMs
32
+ })
33
+ };
34
+ }
35
+ function createLastKnownGoodProvider(options) {
36
+ const storage = options.storage ?? createInMemoryLkgStorage();
37
+ const now = options.now ?? (()=>Date.now());
38
+ const maxStaleMs = options.freshness?.maxStaleMs;
39
+ async function serveFromCache(ref, env, fallback) {
40
+ const key = deliveryUnitResolutionKey(ref.unitId, env);
41
+ const cached = await storage.read(key);
42
+ if (!cached) return fallback();
43
+ if (cached.major !== ref.major) return fallback();
44
+ if ('incompatible' === cached.resolved.compatibility.status) return fallback();
45
+ const ageMs = now() - cached.storedAt;
46
+ if (void 0 !== maxStaleMs && ageMs > maxStaleMs) return staleRecordResult(ref, env, ageMs, maxStaleMs);
47
+ return {
48
+ ok: true,
49
+ unit: markDegraded(cached.resolved, `served last-known-good record (age ${ageMs}ms) after provider failure`)
50
+ };
51
+ }
52
+ return {
53
+ name: LAST_KNOWN_GOOD_PROVIDER_NAME,
54
+ async resolve (ref, env) {
55
+ const key = deliveryUnitResolutionKey(ref.unitId, env);
56
+ let resolution;
57
+ try {
58
+ resolution = await options.provider.resolve(ref, env);
59
+ } catch (error) {
60
+ return serveFromCache(ref, env, ()=>({
61
+ ok: false,
62
+ error: createDiscoveryError('provider-unavailable', ref, error instanceof Error ? error.message : 'provider threw a non-error value', {
63
+ env,
64
+ provider: options.provider.name
65
+ })
66
+ }));
67
+ }
68
+ if (!resolution.ok) {
69
+ const failure = resolution;
70
+ return serveFromCache(ref, env, ()=>failure);
71
+ }
72
+ if ('incompatible' !== resolution.unit.compatibility.status) await storage.write(key, {
73
+ resolved: resolution.unit,
74
+ storedAt: now(),
75
+ major: ref.major
76
+ });
77
+ return resolution;
78
+ }
79
+ };
80
+ }
81
+ export { LAST_KNOWN_GOOD_PROVIDER_NAME, createInMemoryLkgStorage, createLastKnownGoodProvider };
@@ -0,0 +1,101 @@
1
+ import "node:module";
2
+ const DEFAULT_ATTEMPTS = 3;
3
+ const DEFAULT_RETRY_DELAY_MS = 100;
4
+ const DEFAULT_TIMEOUT_MS = 1000;
5
+ const MAX_ATTEMPTS = 5;
6
+ const MAX_RETRY_DELAY_MS = 1000;
7
+ const MAX_TIMEOUT_MS = 5000;
8
+ const RETRYABLE_HTTP_STATUSES = new Set([
9
+ 408,
10
+ 425,
11
+ 429,
12
+ 500,
13
+ 502,
14
+ 503,
15
+ 504
16
+ ]);
17
+ const NON_RETRYABLE_ERROR_PATTERNS = [
18
+ /RUNTIME-013/i,
19
+ /invalid manifest/i,
20
+ /manifest (?:schema|contract|version|identity)/i,
21
+ /(?:incompatible|mismatch).*(?:manifest|remote)/i
22
+ ];
23
+ const clampInteger = (value, fallback, minimum, maximum)=>{
24
+ if (void 0 === value || !Number.isFinite(value)) return fallback;
25
+ return Math.min(maximum, Math.max(minimum, Math.floor(value)));
26
+ };
27
+ const getErrorMessage = (error)=>{
28
+ if (error instanceof Error) return error.message;
29
+ return 'string' == typeof error ? error : '';
30
+ };
31
+ const getErrorStatus = (error)=>{
32
+ if ('object' == typeof error && null !== error && 'status' in error && 'number' == typeof error.status) return error.status;
33
+ };
34
+ const isRetryableError = (error)=>{
35
+ if (error instanceof SyntaxError) return false;
36
+ const message = getErrorMessage(error);
37
+ if (NON_RETRYABLE_ERROR_PATTERNS.some((pattern)=>pattern.test(message))) return false;
38
+ const status = getErrorStatus(error);
39
+ if (void 0 !== status) return RETRYABLE_HTTP_STATUSES.has(status);
40
+ if (error instanceof Error && [
41
+ 'AbortError',
42
+ 'TimeoutError'
43
+ ].includes(error.name)) return true;
44
+ return error instanceof TypeError || /(?:fetch failed|network|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN)/i.test(message);
45
+ };
46
+ const isHttpManifestUrl = (id)=>{
47
+ if (!id) return false;
48
+ try {
49
+ const url = new URL(id);
50
+ return ('http:' === url.protocol || 'https:' === url.protocol) && url.pathname.endsWith('.json');
51
+ } catch {
52
+ return false;
53
+ }
54
+ };
55
+ const defaultWait = (milliseconds)=>new Promise((resolve)=>{
56
+ setTimeout(resolve, milliseconds);
57
+ });
58
+ const fetchWithTimeout = async (fetchImpl, url, timeoutMs)=>{
59
+ const controller = new AbortController();
60
+ const timeout = setTimeout(()=>controller.abort(), timeoutMs);
61
+ try {
62
+ return await fetchImpl(url, {
63
+ signal: controller.signal
64
+ });
65
+ } finally{
66
+ clearTimeout(timeout);
67
+ }
68
+ };
69
+ const createModuleFederationManifestRecoveryPlugin = (options = {})=>{
70
+ const attempts = clampInteger(options.attempts, DEFAULT_ATTEMPTS, 1, MAX_ATTEMPTS);
71
+ const retryDelayMs = clampInteger(options.retryDelayMs, DEFAULT_RETRY_DELAY_MS, 0, MAX_RETRY_DELAY_MS);
72
+ const timeoutMs = clampInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 1, MAX_TIMEOUT_MS);
73
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
74
+ const waitImpl = options.waitImpl ?? defaultWait;
75
+ return {
76
+ name: 'modern-js-manifest-recovery-plugin',
77
+ async errorLoadRemote (args) {
78
+ if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return;
79
+ for(let attempt = 0; attempt < attempts; attempt++){
80
+ if (attempt > 0 && retryDelayMs > 0) await waitImpl(retryDelayMs);
81
+ try {
82
+ const response = await fetchWithTimeout(fetchImpl, args.id, timeoutMs);
83
+ if (!response.ok) {
84
+ if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
85
+ continue;
86
+ }
87
+ try {
88
+ return await response.json();
89
+ } catch {
90
+ break;
91
+ }
92
+ } catch (error) {
93
+ if (!isRetryableError(error) || attempt === attempts - 1) break;
94
+ }
95
+ }
96
+ }
97
+ };
98
+ };
99
+ const manifest_recovery_runtime_plugin = createModuleFederationManifestRecoveryPlugin;
100
+ export default manifest_recovery_runtime_plugin;
101
+ export { createModuleFederationManifestRecoveryPlugin };
@@ -0,0 +1,9 @@
1
+ import "node:module";
2
+ import { createDiscoveryError, formatSurfaceRef, parseSurfaceRef, validateSurfaceRef } from "@modern-js/utils/universal";
3
+ function surfaceResolutionKey(ref, env) {
4
+ return `${env}::${formatSurfaceRef(ref)}`;
5
+ }
6
+ function deliveryUnitResolutionKey(unitId, env) {
7
+ return `${env}::${unitId}`;
8
+ }
9
+ export { createDiscoveryError, deliveryUnitResolutionKey, formatSurfaceRef, parseSurfaceRef, surfaceResolutionKey, validateSurfaceRef };
@@ -7,7 +7,7 @@ import { resolveSSRMode } from "../../../cli/ssr/mode.mjs";
7
7
  import { FILE_SYSTEM_ROUTES_FILE_NAME } from "../constants.mjs";
8
8
  import { walk } from "./nestedRoutes.mjs";
9
9
  import { getServerCombinedModuleFile, getServerLoadersFile } from "./utils.mjs";
10
- import * as __rspack_external__templates_mjs_4da4c6c8 from "./templates.mjs";
10
+ import * as __rspack_external__templates_mjs_ab577925 from "./templates.mjs";
11
11
  async function generateRoutesForEntry(entrypoint, appContext) {
12
12
  const routes = [];
13
13
  if (entrypoint.nestedRoutesEntry) {
@@ -90,7 +90,7 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
90
90
  }
91
91
  const { code } = await hooks.onBeforeGenerateRoutes.call({
92
92
  entrypoint,
93
- code: await __rspack_external__templates_mjs_4da4c6c8.fileSystemRoutes({
93
+ code: await __rspack_external__templates_mjs_ab577925.fileSystemRoutes({
94
94
  metaName,
95
95
  routes: routes,
96
96
  ssrMode: isUseRsc(config) ? 'stream' : ssrMode,
@@ -107,12 +107,12 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
107
107
  const routesServerFile = getServerLoadersFile(internalDirectory, entryName);
108
108
  const filtedRoutesForServer = filterRoutesForServer(routes);
109
109
  const routesForServerLoaderMatches = filterRoutesLoader(routes);
110
- const code = __rspack_external__templates_mjs_4da4c6c8.routesForServer({
110
+ const code = __rspack_external__templates_mjs_ab577925.routesForServer({
111
111
  routesForServerLoaderMatches
112
112
  });
113
113
  await fs.ensureFile(routesServerFile);
114
114
  await fs.writeFile(routesServerFile, code);
115
- const serverRoutesCode = await __rspack_external__templates_mjs_4da4c6c8.fileSystemRoutes({
115
+ const serverRoutesCode = await __rspack_external__templates_mjs_ab577925.fileSystemRoutes({
116
116
  metaName,
117
117
  routes: filtedRoutesForServer,
118
118
  ssrMode,
@@ -126,7 +126,7 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
126
126
  });
127
127
  await fs.outputFile(path.resolve(internalDirectory, `./${entryName}/routes.server.js`), serverRoutesCode, 'utf8');
128
128
  }
129
- const serverLoaderCombined = __rspack_external__templates_mjs_4da4c6c8.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext);
129
+ const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext);
130
130
  if (serverLoaderCombined) {
131
131
  const serverLoaderFile = getServerCombinedModuleFile(internalDirectory, entryName);
132
132
  await fs.outputFile(serverLoaderFile, serverLoaderCombined);
@@ -83,6 +83,7 @@ const walk = async (options)=>{
83
83
  let pageLoaderFile = '';
84
84
  let pageRoute = null;
85
85
  let pageConfigFile = '';
86
+ let pageSearchFile = '';
86
87
  let pageClientData = '';
87
88
  let pageData = '';
88
89
  let pageAction = '';
@@ -129,12 +130,14 @@ const walk = async (options)=>{
129
130
  if (await hasAction(itemPath)) pageAction = itemPathWithAlias;
130
131
  }
131
132
  if (itemWithoutExt === NESTED_ROUTE.PAGE_CONFIG_FILE) pageConfigFile = itemPathWithAlias;
133
+ if (itemWithoutExt === NESTED_ROUTE.PAGE_SEARCH_FILE) pageSearchFile = itemPathWithAlias;
132
134
  if (itemWithoutExt === NESTED_ROUTE.PAGE_FILE) {
133
135
  pageRoute = createIndexRoute({
134
136
  _component: itemPathWithAlias
135
137
  }, rootDir, itemPath, entryName, isMainEntry);
136
138
  if (pageLoaderFile) pageRoute.loader = pageLoaderFile;
137
139
  if (pageConfigFile) pageRoute.config = pageConfigFile;
140
+ if (pageSearchFile) pageRoute.validateSearch = pageSearchFile;
138
141
  if (pageData) pageRoute.data = pageData;
139
142
  if (pageClientData) pageRoute.clientData = pageClientData;
140
143
  if (pageAction) pageRoute.action = pageAction;
@@ -184,7 +184,8 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
184
184
  component = `component_${components.length - 1}`;
185
185
  }
186
186
  const isClientComponent = 'nested' === route.type && Boolean(route._component) && Boolean(srcDirectory) && Boolean(internalSrcAlias) && await hasUseClientDirective(route._component, srcDirectory, internalSrcAlias);
187
- const shouldIncludeClientBundle = !isRscClientBundle || isClientComponent;
187
+ const shouldHydrateRscRoute = isRscClientBundle && !isClientComponent && !route.loader && !route.data;
188
+ const shouldIncludeClientBundle = !isRscClientBundle || isClientComponent || shouldHydrateRscRoute;
188
189
  const finalRoute = {
189
190
  ...route,
190
191
  loading,
@@ -287,7 +288,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
287
288
  ${importLazyCode}
288
289
  ${!isRscClientBundle ? importComponentsCode : ''}
289
290
  ${importRuntimeRouterCode}
290
- ${!isRscClientBundle ? rootLayoutCode : ''}
291
+ ${rootLayoutCode}
291
292
  ${importLoadingCode}
292
293
  ${importErrorComponentsCode}
293
294
  ${importLoadersCode}
@@ -19,6 +19,7 @@ const NESTED_ROUTE = {
19
19
  PAGE_FILE: 'page',
20
20
  PAGE_CONFIG_FILE: 'page.config',
21
21
  PAGE_LOADER_FILE: 'page.loader',
22
+ PAGE_SEARCH_FILE: 'page.search',
22
23
  PAGE_DATA_FILE: 'page.data',
23
24
  PAGE_CLIENT_LOADER: 'page.data.client',
24
25
  SPLATE_FILE: '$',
@@ -4,7 +4,7 @@ import { cloneDeep } from "@modern-js/utils/lodash";
4
4
  import path from "path";
5
5
  import { isPageComponentFile } from "./code/utils.mjs";
6
6
  import { modifyEntrypoints } from "./entry.mjs";
7
- import * as __rspack_external__code_templates_mjs_5e908598 from "./code/templates.mjs";
7
+ import * as __rspack_external__code_templates_mjs_f6c22489 from "./code/templates.mjs";
8
8
  const DEFAULT_ENTRYPOINTS_KEY = '__default_router_entries__';
9
9
  const originEntrypointsByKey = new Map();
10
10
  async function handleModifyEntrypoints(entrypoints, routesDir, options = {}) {
@@ -26,7 +26,7 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
26
26
  if (entrypoint.nestedRoutesEntry || entrypoint.pageRoutesEntry) {
27
27
  const route = appContext.serverRoutes.find((r)=>r.entryName === entrypoint.entryName);
28
28
  const basename = route?.urlPath || '/';
29
- generatorRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_5e908598.runtimeGlobalContext({
29
+ generatorRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_f6c22489.runtimeGlobalContext({
30
30
  entryName: entrypoint.entryName,
31
31
  metaName: appContext.metaName,
32
32
  srcDirectory: appContext.srcDirectory,
@@ -36,7 +36,7 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
36
36
  rscType: enableRsc ? 'client' : void 0,
37
37
  basename
38
38
  }));
39
- if (enableRsc) generatorServerRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_5e908598.runtimeGlobalContext({
39
+ if (enableRsc) generatorServerRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_f6c22489.runtimeGlobalContext({
40
40
  entryName: entrypoint.entryName,
41
41
  metaName: appContext.metaName,
42
42
  srcDirectory: appContext.srcDirectory,
@@ -2,6 +2,7 @@ import "node:module";
2
2
  import node_path from "node:path";
3
3
  import { setTimeout as promises_setTimeout } from "node:timers/promises";
4
4
  import { fs } from "@modern-js/utils";
5
+ import { cloneDeep } from "@modern-js/utils/lodash";
5
6
  const lockPollIntervalMs = 25;
6
7
  const staleLockAgeMs = 120000;
7
8
  const pendingUpdates = new Map();
@@ -44,6 +45,7 @@ async function writeJSONAtomically(filePath, value) {
44
45
  }
45
46
  async function updateNestedRoutesSpec(specPath, nextRoutes) {
46
47
  const resolvedSpecPath = node_path.resolve(specPath);
48
+ const nextRoutesSnapshot = cloneDeep(nextRoutes);
47
49
  const previousUpdate = pendingUpdates.get(resolvedSpecPath) ?? Promise.resolve();
48
50
  const currentUpdate = previousUpdate.catch(()=>void 0).then(async ()=>{
49
51
  const releaseLock = await acquireSpecLock(resolvedSpecPath);
@@ -51,7 +53,7 @@ async function updateNestedRoutesSpec(specPath, nextRoutes) {
51
53
  const existingRoutes = await fs.pathExists(resolvedSpecPath) ? await fs.readJSON(resolvedSpecPath) : {};
52
54
  await writeJSONAtomically(resolvedSpecPath, {
53
55
  ...existingRoutes,
54
- ...nextRoutes
56
+ ...nextRoutesSnapshot
55
57
  });
56
58
  } finally{
57
59
  await releaseLock();
@@ -1,9 +1,10 @@
1
1
  import "node:module";
2
2
  import { createSyncHook } from "@modern-js/plugin";
3
- const modifyRoutes = createSyncHook();
4
- const onBeforeCreateRoutes = createSyncHook();
5
- const onBeforeCreateRouter = createSyncHook();
6
- const onAfterCreateRouter = createSyncHook();
7
- const onBeforeHydrateRouter = createSyncHook();
8
- const onAfterHydrateRouter = createSyncHook();
3
+ const createRouterSyncHook = ()=>createSyncHook();
4
+ const modifyRoutes = createRouterSyncHook();
5
+ const onBeforeCreateRoutes = createRouterSyncHook();
6
+ const onBeforeCreateRouter = createRouterSyncHook();
7
+ const onAfterCreateRouter = createRouterSyncHook();
8
+ const onBeforeHydrateRouter = createRouterSyncHook();
9
+ const onAfterHydrateRouter = createRouterSyncHook();
9
10
  export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter };