@bleedingdev/modern-js-federation-runtime 3.9.0-ultramodern.11 → 3.9.0-ultramodern.13

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.
@@ -3,113 +3,5 @@ export * from "./distributed-ssr.mjs";
3
3
  export * from "./last-known-good.mjs";
4
4
  export * from "./manifest-recovery-runtime-plugin.mjs";
5
5
  export * from "./surface-resolution-types.mjs";
6
- const MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT = 'modernjs:mf-runtime-fallback';
7
- const MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT = 'modernjs:mf-runtime-recovery';
8
- const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = '/_modern/contract-gates/runtime-fallback';
9
- const DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER = 'x-modernjs-runtime-signal-token';
10
- class ModuleFederationRemoteLoadTimeoutError extends Error {
11
- constructor(remote, timeoutMs){
12
- super(`Loading remote "${remote}" timed out after ${timeoutMs}ms`);
13
- this.name = 'ModuleFederationRemoteLoadTimeoutError';
14
- }
15
- }
16
- class ModuleFederationRemoteLoadError extends Error {
17
- constructor(remote, attempts, causeError){
18
- super(`Unable to load remote "${remote}" after ${attempts} attempt${attempts > 1 ? 's' : ''}: ${causeError.message}`);
19
- this.name = 'ModuleFederationRemoteLoadError';
20
- this.remote = remote;
21
- this.attempts = attempts;
22
- this.causeError = causeError;
23
- }
24
- }
25
- class ModuleFederationRemoteComponentContractError extends Error {
26
- constructor(remote, exportName){
27
- super(`Remote "${remote}" export "${exportName}" is not a valid React component`);
28
- this.name = 'ModuleFederationRemoteComponentContractError';
29
- }
30
- }
31
- function toError(error) {
32
- if (error instanceof Error) return error;
33
- return new Error('string' == typeof error ? error : 'Unknown remote load error');
34
- }
35
- function classifyModuleFederationFallback(error) {
36
- const normalizedError = toError(error);
37
- if (normalizedError instanceof ModuleFederationRemoteLoadError) return classifyModuleFederationFallback(normalizedError.causeError);
38
- if (normalizedError instanceof ModuleFederationRemoteLoadTimeoutError) return 'timeout';
39
- if (normalizedError instanceof ModuleFederationRemoteComponentContractError) return 'contract';
40
- const message = normalizedError.message;
41
- if (/version|requiredVersion|singleton|share scope|shared module/i.test(message)) return 'version-skew';
42
- if (/network|fetch|script|timeout|chunk|loading/i.test(message)) return 'network';
43
- return 'remote-unavailable';
44
- }
45
- function createModuleFederationFallbackTelemetry(input) {
46
- const error = void 0 !== input.error ? toError(input.error) : void 0;
47
- const status = input.status ?? 'degraded';
48
- const eventName = input.eventName ?? ('recovered' === status ? MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT : MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT);
49
- const metadata = {
50
- ...input.metadata ?? {},
51
- classification: input.classification,
52
- remote: input.remote,
53
- status
54
- };
55
- if (void 0 !== input.exportName) metadata.exportName = input.exportName;
56
- if (void 0 !== input.runtimeDigest) metadata.runtimeDigest = input.runtimeDigest;
57
- if (void 0 !== error) {
58
- metadata.errorName = error.name;
59
- metadata.errorMessage = error.message;
60
- }
61
- const payload = {
62
- appName: input.appName,
63
- eventName,
64
- metadata,
65
- phase: input.phase,
66
- reason: input.classification,
67
- schemaVersion: 1
68
- };
69
- if (void 0 !== input.entry) payload.entry = input.entry;
70
- if (void 0 !== input.runtimeDigest) payload.runtimeDigest = input.runtimeDigest;
71
- return payload;
72
- }
73
- function toModuleFederationFallbackAttributes(payload) {
74
- return {
75
- 'data-mf-fallback-app': payload.appName,
76
- 'data-mf-fallback-classification': payload.reason,
77
- 'data-mf-fallback-phase': payload.phase,
78
- 'data-mf-fallback-remote': String(payload.metadata.remote),
79
- 'data-mf-fallback-status': String(payload.metadata.status),
80
- 'data-mf-telemetry-event': payload.eventName
81
- };
82
- }
83
- async function emitModuleFederationFallbackTelemetry(input, options = {}) {
84
- const payload = createModuleFederationFallbackTelemetry(input);
85
- if ("u" > typeof window && 'function' == typeof window.dispatchEvent && "u" > typeof CustomEvent) window.dispatchEvent(new CustomEvent(payload.eventName, {
86
- detail: payload
87
- }));
88
- const shouldPost = true === options.postSignal || Boolean(options.endpoint);
89
- if (!shouldPost) return {
90
- dispatched: true,
91
- posted: false
92
- };
93
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
94
- if ('function' != typeof fetchImpl) return {
95
- dispatched: true,
96
- posted: false
97
- };
98
- const headers = new Headers({
99
- 'content-type': 'application/json'
100
- });
101
- if (void 0 !== options.authToken && options.authToken.length > 0) headers.set(options.authHeaderName ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER, options.authToken);
102
- const response = await fetchImpl(options.endpoint ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, {
103
- body: JSON.stringify(payload),
104
- headers,
105
- method: 'POST',
106
- keepalive: true
107
- });
108
- return {
109
- dispatched: true,
110
- posted: true,
111
- postStatus: response.status
112
- };
113
- }
6
+ export * from "./telemetry.mjs";
114
7
  export { DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY, useDistributedSsrFragmentProps } from "./distributed-ssr.mjs";
115
- 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,142 @@
1
+ const MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT = 'modernjs:mf-runtime-fallback';
2
+ const MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT = 'modernjs:mf-runtime-recovery';
3
+ const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = '/_modern/contract-gates/runtime-fallback';
4
+ const DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER = 'x-modernjs-runtime-signal-token';
5
+ class ModuleFederationRemoteLoadTimeoutError extends Error {
6
+ constructor(remote, timeoutMs){
7
+ super(`Loading remote "${remote}" timed out after ${timeoutMs}ms`);
8
+ this.name = 'ModuleFederationRemoteLoadTimeoutError';
9
+ }
10
+ }
11
+ class ModuleFederationRemoteLoadError extends Error {
12
+ constructor(remote, attempts, causeError){
13
+ super(`Unable to load remote "${remote}" after ${attempts} attempt${attempts > 1 ? 's' : ''}: ${causeError.message}`);
14
+ this.name = 'ModuleFederationRemoteLoadError';
15
+ this.remote = remote;
16
+ this.attempts = attempts;
17
+ this.causeError = causeError;
18
+ }
19
+ }
20
+ class ModuleFederationRemoteComponentContractError extends Error {
21
+ constructor(remote, exportName){
22
+ super(`Remote "${remote}" export "${exportName}" is not a valid React component`);
23
+ this.name = 'ModuleFederationRemoteComponentContractError';
24
+ }
25
+ }
26
+ function toError(error) {
27
+ if (error instanceof Error) return error;
28
+ return new Error('string' == typeof error ? error : 'Unknown remote load error');
29
+ }
30
+ function classifyModuleFederationFallback(error) {
31
+ const normalizedError = toError(error);
32
+ if (normalizedError instanceof ModuleFederationRemoteLoadError) return classifyModuleFederationFallback(normalizedError.causeError);
33
+ if (normalizedError instanceof ModuleFederationRemoteLoadTimeoutError) return 'timeout';
34
+ if (normalizedError instanceof ModuleFederationRemoteComponentContractError) return 'contract';
35
+ const message = normalizedError.message;
36
+ if (/version|requiredVersion|singleton|share scope|shared module/i.test(message)) return 'version-skew';
37
+ if (/network|fetch|script|timeout|chunk|loading/i.test(message)) return 'network';
38
+ return 'remote-unavailable';
39
+ }
40
+ function createModuleFederationFallbackTelemetry(input) {
41
+ const error = void 0 !== input.error ? toError(input.error) : void 0;
42
+ const status = input.status ?? 'degraded';
43
+ const eventName = input.eventName ?? ('recovered' === status ? MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT : MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT);
44
+ const metadata = {
45
+ ...input.metadata ?? {},
46
+ classification: input.classification,
47
+ remote: input.remote,
48
+ status
49
+ };
50
+ if (void 0 !== input.exportName) metadata.exportName = input.exportName;
51
+ if (void 0 !== input.runtimeDigest) metadata.runtimeDigest = input.runtimeDigest;
52
+ if (void 0 !== error) {
53
+ metadata.errorName = error.name;
54
+ metadata.errorMessage = error.message;
55
+ }
56
+ const payload = {
57
+ appName: input.appName,
58
+ eventName,
59
+ metadata,
60
+ phase: input.phase,
61
+ reason: input.classification,
62
+ schemaVersion: 1
63
+ };
64
+ if (void 0 !== input.entry) payload.entry = input.entry;
65
+ if (void 0 !== input.runtimeDigest) payload.runtimeDigest = input.runtimeDigest;
66
+ return payload;
67
+ }
68
+ function toModuleFederationFallbackAttributes(payload) {
69
+ return {
70
+ 'data-mf-fallback-app': payload.appName,
71
+ 'data-mf-fallback-classification': payload.reason,
72
+ 'data-mf-fallback-phase': payload.phase,
73
+ 'data-mf-fallback-remote': String(payload.metadata.remote),
74
+ 'data-mf-fallback-status': String(payload.metadata.status),
75
+ 'data-mf-telemetry-event': payload.eventName
76
+ };
77
+ }
78
+ function emitModuleFederationFallbackTelemetry(input, options = {}) {
79
+ return emitModuleFederationFallbackPayload(createModuleFederationFallbackTelemetry(input), options);
80
+ }
81
+ function emitModuleFederationFallbackPayload(payload, options = {}) {
82
+ const delivery = deliver(payload, options);
83
+ try {
84
+ options.observe?.(payload, delivery);
85
+ } catch {}
86
+ return delivery;
87
+ }
88
+ async function deliver(payload, options) {
89
+ let dispatched = false;
90
+ let timer;
91
+ const controller = new AbortController();
92
+ try {
93
+ if ("u" > typeof window && 'function' == typeof window.dispatchEvent && "u" > typeof CustomEvent) {
94
+ window.dispatchEvent(new CustomEvent(payload.eventName, {
95
+ detail: payload
96
+ }));
97
+ dispatched = true;
98
+ }
99
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
100
+ if (!(true === options.postSignal || options.endpoint) || 'function' != typeof fetchImpl) return {
101
+ dispatched,
102
+ posted: false
103
+ };
104
+ const headers = new Headers({
105
+ 'content-type': 'application/json'
106
+ });
107
+ if (options.authToken) headers.set(options.authHeaderName ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER, options.authToken);
108
+ const timeoutMs = Number.isSafeInteger(options.timeoutMs) && (options.timeoutMs ?? 0) > 0 ? options.timeoutMs : 1000;
109
+ const expired = new Promise((resolve)=>{
110
+ timer = setTimeout(()=>{
111
+ controller.abort();
112
+ resolve(void 0);
113
+ }, timeoutMs);
114
+ });
115
+ const response = await Promise.race([
116
+ fetchImpl(options.endpoint ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, {
117
+ body: JSON.stringify(payload),
118
+ headers,
119
+ method: 'POST',
120
+ keepalive: true,
121
+ signal: controller.signal
122
+ }),
123
+ expired
124
+ ]);
125
+ return response ? {
126
+ dispatched,
127
+ posted: true,
128
+ postStatus: response.status
129
+ } : {
130
+ dispatched,
131
+ posted: false
132
+ };
133
+ } catch {
134
+ return {
135
+ dispatched,
136
+ posted: false
137
+ };
138
+ } finally{
139
+ if (void 0 !== timer) clearTimeout(timer);
140
+ }
141
+ }
142
+ 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, emitModuleFederationFallbackPayload, emitModuleFederationFallbackTelemetry, toModuleFederationFallbackAttributes };
@@ -1,6 +1,6 @@
1
1
  import "node:module";
2
- import { classifyModuleFederationFallback, createModuleFederationFallbackTelemetry, emitModuleFederationFallbackTelemetry } from "./index.mjs";
3
2
  import { createDiscoveryError, formatSurfaceRef, parseSurfaceRef, validateSurfaceRef } from "./surface-resolution-types.mjs";
3
+ import { classifyModuleFederationFallback, createModuleFederationFallbackTelemetry, emitModuleFederationFallbackPayload, emitModuleFederationFallbackTelemetry } from "./telemetry.mjs";
4
4
  function classifyDiscoveryError(code) {
5
5
  switch(code){
6
6
  case 'major-not-published':
@@ -39,17 +39,7 @@ async function reportFailure(options, ref, base) {
39
39
  remote,
40
40
  status: 'degraded'
41
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 {}
42
+ emitModuleFederationFallbackPayload(telemetry, options.telemetry);
53
43
  const failure = {
54
44
  ref,
55
45
  env: options.env,
@@ -69,7 +59,7 @@ async function reportFailure(options, ref, base) {
69
59
  degradedValue = await options.degraded(failure);
70
60
  } catch (handlerError) {
71
61
  try {
72
- await emitModuleFederationFallbackTelemetry({
62
+ emitModuleFederationFallbackTelemetry({
73
63
  appName: options.appName,
74
64
  classification: base.classification,
75
65
  error: handlerError,
@@ -4,113 +4,5 @@ export * from "./distributed-ssr.mjs";
4
4
  export * from "./last-known-good.mjs";
5
5
  export * from "./manifest-recovery-runtime-plugin.mjs";
6
6
  export * from "./surface-resolution-types.mjs";
7
- const MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT = 'modernjs:mf-runtime-fallback';
8
- const MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT = 'modernjs:mf-runtime-recovery';
9
- const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = '/_modern/contract-gates/runtime-fallback';
10
- const DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER = 'x-modernjs-runtime-signal-token';
11
- class ModuleFederationRemoteLoadTimeoutError extends Error {
12
- constructor(remote, timeoutMs){
13
- super(`Loading remote "${remote}" timed out after ${timeoutMs}ms`);
14
- this.name = 'ModuleFederationRemoteLoadTimeoutError';
15
- }
16
- }
17
- class ModuleFederationRemoteLoadError extends Error {
18
- constructor(remote, attempts, causeError){
19
- super(`Unable to load remote "${remote}" after ${attempts} attempt${attempts > 1 ? 's' : ''}: ${causeError.message}`);
20
- this.name = 'ModuleFederationRemoteLoadError';
21
- this.remote = remote;
22
- this.attempts = attempts;
23
- this.causeError = causeError;
24
- }
25
- }
26
- class ModuleFederationRemoteComponentContractError extends Error {
27
- constructor(remote, exportName){
28
- super(`Remote "${remote}" export "${exportName}" is not a valid React component`);
29
- this.name = 'ModuleFederationRemoteComponentContractError';
30
- }
31
- }
32
- function toError(error) {
33
- if (error instanceof Error) return error;
34
- return new Error('string' == typeof error ? error : 'Unknown remote load error');
35
- }
36
- function classifyModuleFederationFallback(error) {
37
- const normalizedError = toError(error);
38
- if (normalizedError instanceof ModuleFederationRemoteLoadError) return classifyModuleFederationFallback(normalizedError.causeError);
39
- if (normalizedError instanceof ModuleFederationRemoteLoadTimeoutError) return 'timeout';
40
- if (normalizedError instanceof ModuleFederationRemoteComponentContractError) return 'contract';
41
- const message = normalizedError.message;
42
- if (/version|requiredVersion|singleton|share scope|shared module/i.test(message)) return 'version-skew';
43
- if (/network|fetch|script|timeout|chunk|loading/i.test(message)) return 'network';
44
- return 'remote-unavailable';
45
- }
46
- function createModuleFederationFallbackTelemetry(input) {
47
- const error = void 0 !== input.error ? toError(input.error) : void 0;
48
- const status = input.status ?? 'degraded';
49
- const eventName = input.eventName ?? ('recovered' === status ? MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT : MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT);
50
- const metadata = {
51
- ...input.metadata ?? {},
52
- classification: input.classification,
53
- remote: input.remote,
54
- status
55
- };
56
- if (void 0 !== input.exportName) metadata.exportName = input.exportName;
57
- if (void 0 !== input.runtimeDigest) metadata.runtimeDigest = input.runtimeDigest;
58
- if (void 0 !== error) {
59
- metadata.errorName = error.name;
60
- metadata.errorMessage = error.message;
61
- }
62
- const payload = {
63
- appName: input.appName,
64
- eventName,
65
- metadata,
66
- phase: input.phase,
67
- reason: input.classification,
68
- schemaVersion: 1
69
- };
70
- if (void 0 !== input.entry) payload.entry = input.entry;
71
- if (void 0 !== input.runtimeDigest) payload.runtimeDigest = input.runtimeDigest;
72
- return payload;
73
- }
74
- function toModuleFederationFallbackAttributes(payload) {
75
- return {
76
- 'data-mf-fallback-app': payload.appName,
77
- 'data-mf-fallback-classification': payload.reason,
78
- 'data-mf-fallback-phase': payload.phase,
79
- 'data-mf-fallback-remote': String(payload.metadata.remote),
80
- 'data-mf-fallback-status': String(payload.metadata.status),
81
- 'data-mf-telemetry-event': payload.eventName
82
- };
83
- }
84
- async function emitModuleFederationFallbackTelemetry(input, options = {}) {
85
- const payload = createModuleFederationFallbackTelemetry(input);
86
- if ("u" > typeof window && 'function' == typeof window.dispatchEvent && "u" > typeof CustomEvent) window.dispatchEvent(new CustomEvent(payload.eventName, {
87
- detail: payload
88
- }));
89
- const shouldPost = true === options.postSignal || Boolean(options.endpoint);
90
- if (!shouldPost) return {
91
- dispatched: true,
92
- posted: false
93
- };
94
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
95
- if ('function' != typeof fetchImpl) return {
96
- dispatched: true,
97
- posted: false
98
- };
99
- const headers = new Headers({
100
- 'content-type': 'application/json'
101
- });
102
- if (void 0 !== options.authToken && options.authToken.length > 0) headers.set(options.authHeaderName ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER, options.authToken);
103
- const response = await fetchImpl(options.endpoint ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, {
104
- body: JSON.stringify(payload),
105
- headers,
106
- method: 'POST',
107
- keepalive: true
108
- });
109
- return {
110
- dispatched: true,
111
- posted: true,
112
- postStatus: response.status
113
- };
114
- }
7
+ export * from "./telemetry.mjs";
115
8
  export { DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY, useDistributedSsrFragmentProps } from "./distributed-ssr.mjs";
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,143 @@
1
+ import "node:module";
2
+ const MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT = 'modernjs:mf-runtime-fallback';
3
+ const MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT = 'modernjs:mf-runtime-recovery';
4
+ const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = '/_modern/contract-gates/runtime-fallback';
5
+ const DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER = 'x-modernjs-runtime-signal-token';
6
+ class ModuleFederationRemoteLoadTimeoutError extends Error {
7
+ constructor(remote, timeoutMs){
8
+ super(`Loading remote "${remote}" timed out after ${timeoutMs}ms`);
9
+ this.name = 'ModuleFederationRemoteLoadTimeoutError';
10
+ }
11
+ }
12
+ class ModuleFederationRemoteLoadError extends Error {
13
+ constructor(remote, attempts, causeError){
14
+ super(`Unable to load remote "${remote}" after ${attempts} attempt${attempts > 1 ? 's' : ''}: ${causeError.message}`);
15
+ this.name = 'ModuleFederationRemoteLoadError';
16
+ this.remote = remote;
17
+ this.attempts = attempts;
18
+ this.causeError = causeError;
19
+ }
20
+ }
21
+ class ModuleFederationRemoteComponentContractError extends Error {
22
+ constructor(remote, exportName){
23
+ super(`Remote "${remote}" export "${exportName}" is not a valid React component`);
24
+ this.name = 'ModuleFederationRemoteComponentContractError';
25
+ }
26
+ }
27
+ function toError(error) {
28
+ if (error instanceof Error) return error;
29
+ return new Error('string' == typeof error ? error : 'Unknown remote load error');
30
+ }
31
+ function classifyModuleFederationFallback(error) {
32
+ const normalizedError = toError(error);
33
+ if (normalizedError instanceof ModuleFederationRemoteLoadError) return classifyModuleFederationFallback(normalizedError.causeError);
34
+ if (normalizedError instanceof ModuleFederationRemoteLoadTimeoutError) return 'timeout';
35
+ if (normalizedError instanceof ModuleFederationRemoteComponentContractError) return 'contract';
36
+ const message = normalizedError.message;
37
+ if (/version|requiredVersion|singleton|share scope|shared module/i.test(message)) return 'version-skew';
38
+ if (/network|fetch|script|timeout|chunk|loading/i.test(message)) return 'network';
39
+ return 'remote-unavailable';
40
+ }
41
+ function createModuleFederationFallbackTelemetry(input) {
42
+ const error = void 0 !== input.error ? toError(input.error) : void 0;
43
+ const status = input.status ?? 'degraded';
44
+ const eventName = input.eventName ?? ('recovered' === status ? MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT : MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT);
45
+ const metadata = {
46
+ ...input.metadata ?? {},
47
+ classification: input.classification,
48
+ remote: input.remote,
49
+ status
50
+ };
51
+ if (void 0 !== input.exportName) metadata.exportName = input.exportName;
52
+ if (void 0 !== input.runtimeDigest) metadata.runtimeDigest = input.runtimeDigest;
53
+ if (void 0 !== error) {
54
+ metadata.errorName = error.name;
55
+ metadata.errorMessage = error.message;
56
+ }
57
+ const payload = {
58
+ appName: input.appName,
59
+ eventName,
60
+ metadata,
61
+ phase: input.phase,
62
+ reason: input.classification,
63
+ schemaVersion: 1
64
+ };
65
+ if (void 0 !== input.entry) payload.entry = input.entry;
66
+ if (void 0 !== input.runtimeDigest) payload.runtimeDigest = input.runtimeDigest;
67
+ return payload;
68
+ }
69
+ function toModuleFederationFallbackAttributes(payload) {
70
+ return {
71
+ 'data-mf-fallback-app': payload.appName,
72
+ 'data-mf-fallback-classification': payload.reason,
73
+ 'data-mf-fallback-phase': payload.phase,
74
+ 'data-mf-fallback-remote': String(payload.metadata.remote),
75
+ 'data-mf-fallback-status': String(payload.metadata.status),
76
+ 'data-mf-telemetry-event': payload.eventName
77
+ };
78
+ }
79
+ function emitModuleFederationFallbackTelemetry(input, options = {}) {
80
+ return emitModuleFederationFallbackPayload(createModuleFederationFallbackTelemetry(input), options);
81
+ }
82
+ function emitModuleFederationFallbackPayload(payload, options = {}) {
83
+ const delivery = deliver(payload, options);
84
+ try {
85
+ options.observe?.(payload, delivery);
86
+ } catch {}
87
+ return delivery;
88
+ }
89
+ async function deliver(payload, options) {
90
+ let dispatched = false;
91
+ let timer;
92
+ const controller = new AbortController();
93
+ try {
94
+ if ("u" > typeof window && 'function' == typeof window.dispatchEvent && "u" > typeof CustomEvent) {
95
+ window.dispatchEvent(new CustomEvent(payload.eventName, {
96
+ detail: payload
97
+ }));
98
+ dispatched = true;
99
+ }
100
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
101
+ if (!(true === options.postSignal || options.endpoint) || 'function' != typeof fetchImpl) return {
102
+ dispatched,
103
+ posted: false
104
+ };
105
+ const headers = new Headers({
106
+ 'content-type': 'application/json'
107
+ });
108
+ if (options.authToken) headers.set(options.authHeaderName ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER, options.authToken);
109
+ const timeoutMs = Number.isSafeInteger(options.timeoutMs) && (options.timeoutMs ?? 0) > 0 ? options.timeoutMs : 1000;
110
+ const expired = new Promise((resolve)=>{
111
+ timer = setTimeout(()=>{
112
+ controller.abort();
113
+ resolve(void 0);
114
+ }, timeoutMs);
115
+ });
116
+ const response = await Promise.race([
117
+ fetchImpl(options.endpoint ?? DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, {
118
+ body: JSON.stringify(payload),
119
+ headers,
120
+ method: 'POST',
121
+ keepalive: true,
122
+ signal: controller.signal
123
+ }),
124
+ expired
125
+ ]);
126
+ return response ? {
127
+ dispatched,
128
+ posted: true,
129
+ postStatus: response.status
130
+ } : {
131
+ dispatched,
132
+ posted: false
133
+ };
134
+ } catch {
135
+ return {
136
+ dispatched,
137
+ posted: false
138
+ };
139
+ } finally{
140
+ if (void 0 !== timer) clearTimeout(timer);
141
+ }
142
+ }
143
+ 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, emitModuleFederationFallbackPayload, emitModuleFederationFallbackTelemetry, toModuleFederationFallbackAttributes };
@@ -22,8 +22,8 @@
22
22
  * consumption during a rollout window should be driven by expand/contract, not
23
23
  * by silent degrade.
24
24
  */
25
- import { type ModuleFederationFallbackClassification, type ModuleFederationFallbackTelemetryEmitOptions, type ModuleFederationFallbackTelemetryPayload } from './index.js';
26
25
  import { type DiscoveryError, type EnvironmentId, type ParsedSurfaceRef, type ResolvedDeliveryUnit, type SurfaceResolutionProvider } from './surface-resolution-types.js';
26
+ import { type ModuleFederationFallbackClassification, type ModuleFederationFallbackTelemetryEmitOptions, type ModuleFederationFallbackTelemetryPayload } from './telemetry.js';
27
27
  /** Where in the consumption lifecycle a failure was raised. */
28
28
  export type SurfaceConsumptionPhase = 'discovery' | 'load' | 'mount';
29
29
  /**
@@ -76,7 +76,7 @@ export type SurfaceConsumerOptions<T> = {
76
76
  * omitted.
77
77
  *
78
78
  * - `'noncritical'`: the degraded handler's result is returned and the
79
- * failure is swallowed — the promise never rejects.
79
+ * failure is swallowed — a failed degraded handler resolves undefined.
80
80
  * - `'critical'`: the degraded handler still runs (telemetry + fallback-UI
81
81
  * obligations hold), but the returned promise then REJECTS with the typed
82
82
  * failure so callers / rollout machinery observe it. Prefer expand/contract
@@ -91,14 +91,14 @@ export type SurfaceConsumerOptions<T> = {
91
91
  * load failure the required degraded handler runs (telemetry + fallback UI).
92
92
  *
93
93
  * For a `noncritical` consumption (see {@link SurfaceConsumerOptions.classification})
94
- * this resolves to the degraded value and never rejects, so a failing
94
+ * this resolves to the degraded value (or undefined if the handler fails), so a failing
95
95
  * consumption is isolated from any sibling. For a `critical` consumption (the
96
96
  * default) it rejects with the typed failure AFTER the degraded handler has
97
97
  * run, so callers / rollout machinery observe the failure.
98
98
  */
99
- export declare function consumeSurface<T>(options: SurfaceConsumerOptions<T>): Promise<T>;
99
+ export declare function consumeSurface<T>(options: SurfaceConsumerOptions<T>): Promise<T | undefined>;
100
100
  /**
101
101
  * Build a reusable consumer bound to a provider/env/app, still requiring a
102
102
  * degraded handler per call. Per-call options override the bound base.
103
103
  */
104
- export declare function createSurfaceConsumer(base: Pick<SurfaceConsumerOptions<unknown>, 'provider' | 'env' | 'appName' | 'telemetry'>): <T>(options: Omit<SurfaceConsumerOptions<T>, keyof typeof base> & Partial<Pick<SurfaceConsumerOptions<T>, keyof typeof base>>) => Promise<T>;
104
+ export declare function createSurfaceConsumer(base: Pick<SurfaceConsumerOptions<unknown>, 'provider' | 'env' | 'appName' | 'telemetry'>): <T>(options: Omit<SurfaceConsumerOptions<T>, keyof typeof base> & Partial<Pick<SurfaceConsumerOptions<T>, keyof typeof base>>) => Promise<T | undefined>;
@@ -4,68 +4,4 @@ export { DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY, useDistributedSsrFragmentP
4
4
  export * from './last-known-good.js';
5
5
  export * from './manifest-recovery-runtime-plugin.js';
6
6
  export * from './surface-resolution-types.js';
7
- export declare const MODULE_FEDERATION_FALLBACK_SIGNAL_EVENT = "modernjs:mf-runtime-fallback";
8
- export declare const MODULE_FEDERATION_RECOVERY_SIGNAL_EVENT = "modernjs:mf-runtime-recovery";
9
- export declare const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = "/_modern/contract-gates/runtime-fallback";
10
- export declare const DEFAULT_RUNTIME_FALLBACK_SIGNAL_AUTH_HEADER = "x-modernjs-runtime-signal-token";
11
- export type ModuleFederationFallbackClassification = 'timeout' | 'network' | 'contract' | 'version-skew' | 'remote-unavailable';
12
- export type ModuleFederationFallbackStatus = 'degraded' | 'failed' | 'recovered';
13
- export type ModuleFederationFallbackTelemetryInput = {
14
- appName: string;
15
- classification: ModuleFederationFallbackClassification;
16
- entry?: string;
17
- error?: unknown;
18
- eventName?: string;
19
- exportName?: string;
20
- metadata?: Record<string, unknown>;
21
- phase: 'discovery' | 'load' | 'mount' | 'hydrate' | 'recover';
22
- remote: string;
23
- runtimeDigest?: string;
24
- status?: ModuleFederationFallbackStatus;
25
- };
26
- export type ModuleFederationFallbackTelemetryPayload = {
27
- appName: string;
28
- entry?: string;
29
- eventName: string;
30
- phase: ModuleFederationFallbackTelemetryInput['phase'];
31
- reason: ModuleFederationFallbackClassification;
32
- runtimeDigest?: string;
33
- schemaVersion: 1;
34
- metadata: {
35
- classification: ModuleFederationFallbackClassification;
36
- errorMessage?: string;
37
- errorName?: string;
38
- exportName?: string;
39
- remote: string;
40
- runtimeDigest?: string;
41
- status: ModuleFederationFallbackStatus;
42
- } & Record<string, unknown>;
43
- };
44
- export type ModuleFederationFallbackTelemetryEmitOptions = {
45
- authHeaderName?: string;
46
- authToken?: string;
47
- endpoint?: string;
48
- fetchImpl?: typeof fetch;
49
- postSignal?: boolean;
50
- };
51
- export type ModuleFederationFallbackTelemetryEmitResult = {
52
- dispatched: boolean;
53
- posted: boolean;
54
- postStatus?: number;
55
- };
56
- export declare class ModuleFederationRemoteLoadTimeoutError extends Error {
57
- constructor(remote: string, timeoutMs: number);
58
- }
59
- export declare class ModuleFederationRemoteLoadError extends Error {
60
- readonly remote: string;
61
- readonly attempts: number;
62
- readonly causeError: Error;
63
- constructor(remote: string, attempts: number, causeError: Error);
64
- }
65
- export declare class ModuleFederationRemoteComponentContractError extends Error {
66
- constructor(remote: string, exportName: string);
67
- }
68
- export declare function classifyModuleFederationFallback(error: unknown): ModuleFederationFallbackClassification;
69
- export declare function createModuleFederationFallbackTelemetry(input: ModuleFederationFallbackTelemetryInput): ModuleFederationFallbackTelemetryPayload;
70
- export declare function toModuleFederationFallbackAttributes(payload: ModuleFederationFallbackTelemetryPayload): Record<string, string>;
71
- export declare function emitModuleFederationFallbackTelemetry(input: ModuleFederationFallbackTelemetryInput, options?: ModuleFederationFallbackTelemetryEmitOptions): Promise<ModuleFederationFallbackTelemetryEmitResult>;
7
+ export * from './telemetry.js';