@bleedingdev/modern-js-federation-runtime 0.0.0 → 3.9.0-ultramodern.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.
- package/LICENSE +21 -0
- package/dist/cjs/module-federation/consume-surface.js +199 -0
- package/dist/cjs/module-federation/distributed-ssr.js +135 -0
- package/dist/cjs/module-federation/index.js +316 -0
- package/dist/cjs/module-federation/last-known-good.js +157 -0
- package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +130 -0
- package/dist/cjs/module-federation/surface-resolution-types.js +61 -0
- package/dist/esm/module-federation/consume-surface.mjs +158 -0
- package/dist/esm/module-federation/distributed-ssr.mjs +82 -0
- package/dist/esm/module-federation/index.mjs +115 -0
- package/dist/esm/module-federation/last-known-good.mjs +113 -0
- package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +90 -0
- package/dist/esm/module-federation/surface-resolution-types.mjs +8 -0
- package/dist/esm-node/module-federation/consume-surface.mjs +159 -0
- package/dist/esm-node/module-federation/distributed-ssr.mjs +83 -0
- package/dist/esm-node/module-federation/index.mjs +116 -0
- package/dist/esm-node/module-federation/last-known-good.mjs +114 -0
- package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +91 -0
- package/dist/esm-node/module-federation/surface-resolution-types.mjs +9 -0
- package/dist/types/module-federation/consume-surface.d.ts +104 -0
- package/dist/types/module-federation/distributed-ssr.d.ts +61 -0
- package/dist/types/module-federation/index.d.ts +71 -0
- package/dist/types/module-federation/last-known-good.d.ts +52 -0
- package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +25 -0
- package/dist/types/module-federation/surface-resolution-types.d.ts +23 -0
- package/package.json +86 -4
- package/src/module-federation/consume-surface.ts +369 -0
- package/src/module-federation/distributed-ssr.tsx +240 -0
- package/src/module-federation/index.ts +274 -0
- package/src/module-federation/last-known-good.ts +292 -0
- package/src/module-federation/manifest-recovery-runtime-plugin.ts +215 -0
- package/src/module-federation/surface-resolution-types.ts +60 -0
- package/README.md +0 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
+
LAST_KNOWN_GOOD_PROVIDER_NAME: ()=>LAST_KNOWN_GOOD_PROVIDER_NAME,
|
|
32
|
+
createInMemoryLkgStorage: ()=>createInMemoryLkgStorage,
|
|
33
|
+
createLastKnownGoodProvider: ()=>createLastKnownGoodProvider
|
|
34
|
+
});
|
|
35
|
+
const surface_resolution_namespaceObject = require("@modern-js/surface-resolution");
|
|
36
|
+
const external_surface_resolution_types_js_namespaceObject = require("./surface-resolution-types.js");
|
|
37
|
+
const LAST_KNOWN_GOOD_PROVIDER_NAME = 'last-known-good';
|
|
38
|
+
function createInMemoryLkgStorage() {
|
|
39
|
+
const map = new Map();
|
|
40
|
+
return {
|
|
41
|
+
read (key) {
|
|
42
|
+
return map.get(key);
|
|
43
|
+
},
|
|
44
|
+
write (key, record) {
|
|
45
|
+
map.set(key, record);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function markDegraded(resolved, reason) {
|
|
50
|
+
return {
|
|
51
|
+
...resolved,
|
|
52
|
+
compatibility: {
|
|
53
|
+
...resolved.compatibility,
|
|
54
|
+
status: 'degraded',
|
|
55
|
+
reason
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function staleRecordResult(ref, env, ageMs, maxStaleMs) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
error: (0, external_surface_resolution_types_js_namespaceObject.createDiscoveryError)('stale-record', ref, `Last-known-good record for surface is stale: age ${ageMs}ms exceeds maxStaleMs ${maxStaleMs}ms`, {
|
|
63
|
+
env,
|
|
64
|
+
ageMs,
|
|
65
|
+
maxStaleMs
|
|
66
|
+
})
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function resolutionAnswersRef(resolved, ref) {
|
|
70
|
+
const selected = (0, surface_resolution_namespaceObject.selectResolvedSurface)(resolved, ref);
|
|
71
|
+
return selected.ok && selected.surface.servedMajor === ref.major;
|
|
72
|
+
}
|
|
73
|
+
function createLastKnownGoodProvider(options) {
|
|
74
|
+
const storage = options.storage ?? createInMemoryLkgStorage();
|
|
75
|
+
const now = options.now ?? (()=>Math.floor(performance.timeOrigin + performance.now()));
|
|
76
|
+
const maxStaleMs = options.freshness?.maxStaleMs;
|
|
77
|
+
let nextResolutionGeneration = 0;
|
|
78
|
+
const latestCacheableGenerationByKey = new Map();
|
|
79
|
+
const writeTailByKey = new Map();
|
|
80
|
+
async function cacheCompatibleResolution(key, generation, record) {
|
|
81
|
+
latestCacheableGenerationByKey.set(key, Math.max(latestCacheableGenerationByKey.get(key) ?? 0, generation));
|
|
82
|
+
const previous = writeTailByKey.get(key) ?? Promise.resolve();
|
|
83
|
+
const write = previous.catch(()=>void 0).then(async ()=>{
|
|
84
|
+
if (latestCacheableGenerationByKey.get(key) !== generation) return;
|
|
85
|
+
await storage.write(key, record);
|
|
86
|
+
});
|
|
87
|
+
writeTailByKey.set(key, write);
|
|
88
|
+
try {
|
|
89
|
+
await write;
|
|
90
|
+
} finally{
|
|
91
|
+
if (writeTailByKey.get(key) === write) writeTailByKey.delete(key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function serveFromCache(ref, env, fallback) {
|
|
95
|
+
const key = (0, external_surface_resolution_types_js_namespaceObject.deliveryUnitResolutionKey)(ref.unitId, env);
|
|
96
|
+
const cached = await storage.read(key);
|
|
97
|
+
if (!cached) return fallback();
|
|
98
|
+
if (cached.major !== ref.major) return fallback();
|
|
99
|
+
if (!resolutionAnswersRef(cached.resolved, ref)) return fallback();
|
|
100
|
+
if ('compatible' !== cached.resolved.compatibility.status) return fallback();
|
|
101
|
+
const ageMs = now() - cached.storedAt;
|
|
102
|
+
if (void 0 !== maxStaleMs && ageMs > maxStaleMs) return staleRecordResult(ref, env, ageMs, maxStaleMs);
|
|
103
|
+
return {
|
|
104
|
+
ok: true,
|
|
105
|
+
unit: markDegraded(cached.resolved, `served last-known-good record (age ${ageMs}ms) after provider failure`)
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
name: LAST_KNOWN_GOOD_PROVIDER_NAME,
|
|
110
|
+
async resolve (ref, env) {
|
|
111
|
+
const key = (0, external_surface_resolution_types_js_namespaceObject.deliveryUnitResolutionKey)(ref.unitId, env);
|
|
112
|
+
const generation = ++nextResolutionGeneration;
|
|
113
|
+
let resolution;
|
|
114
|
+
try {
|
|
115
|
+
resolution = await options.provider.resolve(ref, env);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return serveFromCache(ref, env, ()=>({
|
|
118
|
+
ok: false,
|
|
119
|
+
error: (0, external_surface_resolution_types_js_namespaceObject.createDiscoveryError)('provider-unavailable', ref, error instanceof Error ? error.message : 'provider threw a non-error value', {
|
|
120
|
+
env,
|
|
121
|
+
provider: options.provider.name
|
|
122
|
+
})
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
if (!resolution.ok) {
|
|
126
|
+
const failure = resolution;
|
|
127
|
+
return serveFromCache(ref, env, ()=>failure);
|
|
128
|
+
}
|
|
129
|
+
if (!resolutionAnswersRef(resolution.unit, ref)) return serveFromCache(ref, env, ()=>({
|
|
130
|
+
ok: false,
|
|
131
|
+
error: (0, external_surface_resolution_types_js_namespaceObject.createDiscoveryError)('identity-mismatch', ref, `Provider ${options.provider.name} returned a delivery unit that does not answer the requested surface.`, {
|
|
132
|
+
env,
|
|
133
|
+
provider: options.provider.name,
|
|
134
|
+
recordUnitId: resolution.unit.unitId,
|
|
135
|
+
availableSurfaces: resolution.unit.surfaces.map((surface)=>surface.surfaceId)
|
|
136
|
+
})
|
|
137
|
+
}));
|
|
138
|
+
if ('compatible' === resolution.unit.compatibility.status) await cacheCompatibleResolution(key, generation, {
|
|
139
|
+
resolved: resolution.unit,
|
|
140
|
+
storedAt: now(),
|
|
141
|
+
major: ref.major
|
|
142
|
+
});
|
|
143
|
+
return resolution;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
exports.LAST_KNOWN_GOOD_PROVIDER_NAME = __webpack_exports__.LAST_KNOWN_GOOD_PROVIDER_NAME;
|
|
148
|
+
exports.createInMemoryLkgStorage = __webpack_exports__.createInMemoryLkgStorage;
|
|
149
|
+
exports.createLastKnownGoodProvider = __webpack_exports__.createLastKnownGoodProvider;
|
|
150
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
151
|
+
"LAST_KNOWN_GOOD_PROVIDER_NAME",
|
|
152
|
+
"createInMemoryLkgStorage",
|
|
153
|
+
"createLastKnownGoodProvider"
|
|
154
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
155
|
+
Object.defineProperty(exports, '__esModule', {
|
|
156
|
+
value: true
|
|
157
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
const DEFAULT_ATTEMPTS = 3;
|
|
31
|
+
const DEFAULT_RETRY_DELAY_MS = 100;
|
|
32
|
+
const DEFAULT_TIMEOUT_MS = 1000;
|
|
33
|
+
const MAX_ATTEMPTS = 5;
|
|
34
|
+
const MAX_RETRY_DELAY_MS = 1000;
|
|
35
|
+
const MAX_TIMEOUT_MS = 5000;
|
|
36
|
+
const RETRYABLE_HTTP_STATUSES = new Set([
|
|
37
|
+
408,
|
|
38
|
+
425,
|
|
39
|
+
429,
|
|
40
|
+
500,
|
|
41
|
+
502,
|
|
42
|
+
503,
|
|
43
|
+
504
|
|
44
|
+
]);
|
|
45
|
+
const NON_RETRYABLE_ERROR_PATTERNS = [
|
|
46
|
+
/RUNTIME-013/i,
|
|
47
|
+
/invalid manifest/i,
|
|
48
|
+
/manifest (?:schema|contract|version|identity)/i,
|
|
49
|
+
/(?:incompatible|mismatch).*(?:manifest|remote)/i
|
|
50
|
+
];
|
|
51
|
+
const clampInteger = (value, fallback, minimum, maximum)=>{
|
|
52
|
+
if (void 0 === value || !Number.isFinite(value)) return fallback;
|
|
53
|
+
return Math.min(maximum, Math.max(minimum, Math.floor(value)));
|
|
54
|
+
};
|
|
55
|
+
const getErrorMessage = (error)=>{
|
|
56
|
+
if (error instanceof Error) return error.message;
|
|
57
|
+
return 'string' == typeof error ? error : '';
|
|
58
|
+
};
|
|
59
|
+
const getErrorStatus = (error)=>{
|
|
60
|
+
if ('object' == typeof error && null !== error && 'status' in error && 'number' == typeof error.status) return error.status;
|
|
61
|
+
};
|
|
62
|
+
const isRetryableError = (error)=>{
|
|
63
|
+
if (error instanceof SyntaxError) return false;
|
|
64
|
+
const message = getErrorMessage(error);
|
|
65
|
+
if (NON_RETRYABLE_ERROR_PATTERNS.some((pattern)=>pattern.test(message))) return false;
|
|
66
|
+
const status = getErrorStatus(error);
|
|
67
|
+
if (void 0 !== status) return RETRYABLE_HTTP_STATUSES.has(status);
|
|
68
|
+
if (error instanceof Error && [
|
|
69
|
+
'AbortError',
|
|
70
|
+
'TimeoutError'
|
|
71
|
+
].includes(error.name)) return true;
|
|
72
|
+
return error instanceof TypeError || /(?:fetch failed|network|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN)/i.test(message);
|
|
73
|
+
};
|
|
74
|
+
const isHttpManifestUrl = (id)=>{
|
|
75
|
+
if (void 0 === id || 0 === id.length) return false;
|
|
76
|
+
try {
|
|
77
|
+
const url = new URL(id);
|
|
78
|
+
return ('http:' === url.protocol || 'https:' === url.protocol) && url.pathname.endsWith('.json');
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const defaultWait = (milliseconds)=>new Promise((resolve)=>{
|
|
84
|
+
setTimeout(resolve, milliseconds);
|
|
85
|
+
});
|
|
86
|
+
const fetchWithTimeout = (fetchImpl, url, timeoutMs)=>fetchImpl(url, {
|
|
87
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
88
|
+
});
|
|
89
|
+
const createModuleFederationManifestRecoveryPlugin = (options = {})=>{
|
|
90
|
+
const attempts = clampInteger(options.attempts, DEFAULT_ATTEMPTS, 1, MAX_ATTEMPTS);
|
|
91
|
+
const retryDelayMs = clampInteger(options.retryDelayMs, DEFAULT_RETRY_DELAY_MS, 0, MAX_RETRY_DELAY_MS);
|
|
92
|
+
const timeoutMs = clampInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 1, MAX_TIMEOUT_MS);
|
|
93
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
94
|
+
const waitImpl = options.waitImpl ?? defaultWait;
|
|
95
|
+
const recoverManifest = (url, attempt)=>{
|
|
96
|
+
const fetchManifest = ()=>Promise.resolve().then(()=>fetchWithTimeout(fetchImpl, url, timeoutMs)).then((response)=>{
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
|
|
99
|
+
return recoverManifest(url, attempt + 1);
|
|
100
|
+
}
|
|
101
|
+
return Promise.resolve().then(()=>response.json()).then((manifest)=>manifest, ()=>void 0);
|
|
102
|
+
}, (error)=>{
|
|
103
|
+
if (!isRetryableError(error) || attempt === attempts - 1) return;
|
|
104
|
+
return recoverManifest(url, attempt + 1);
|
|
105
|
+
});
|
|
106
|
+
if (attempt > 0 && retryDelayMs > 0) return waitImpl(retryDelayMs).then(fetchManifest);
|
|
107
|
+
return fetchManifest();
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
name: 'modern-js-manifest-recovery-plugin',
|
|
111
|
+
errorLoadRemote (args) {
|
|
112
|
+
if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return Promise.resolve(void 0);
|
|
113
|
+
return recoverManifest(args.id, 0);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
const __rspack_default_export = createModuleFederationManifestRecoveryPlugin;
|
|
118
|
+
__webpack_require__.d(__webpack_exports__, {}, {
|
|
119
|
+
createModuleFederationManifestRecoveryPlugin: createModuleFederationManifestRecoveryPlugin,
|
|
120
|
+
default: __rspack_default_export
|
|
121
|
+
});
|
|
122
|
+
exports.createModuleFederationManifestRecoveryPlugin = __webpack_exports__.createModuleFederationManifestRecoveryPlugin;
|
|
123
|
+
exports["default"] = __webpack_exports__["default"];
|
|
124
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
125
|
+
"createModuleFederationManifestRecoveryPlugin",
|
|
126
|
+
"default"
|
|
127
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
128
|
+
Object.defineProperty(exports, '__esModule', {
|
|
129
|
+
value: true
|
|
130
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
+
createDiscoveryError: ()=>surface_resolution_namespaceObject.createDiscoveryError,
|
|
32
|
+
deliveryUnitResolutionKey: ()=>deliveryUnitResolutionKey,
|
|
33
|
+
formatSurfaceRef: ()=>surface_resolution_namespaceObject.formatSurfaceRef,
|
|
34
|
+
parseSurfaceRef: ()=>surface_resolution_namespaceObject.parseSurfaceRef,
|
|
35
|
+
surfaceResolutionKey: ()=>surfaceResolutionKey,
|
|
36
|
+
validateSurfaceRef: ()=>surface_resolution_namespaceObject.validateSurfaceRef
|
|
37
|
+
});
|
|
38
|
+
const surface_resolution_namespaceObject = require("@modern-js/surface-resolution");
|
|
39
|
+
function surfaceResolutionKey(ref, env) {
|
|
40
|
+
return `${env}::${(0, surface_resolution_namespaceObject.formatSurfaceRef)(ref)}`;
|
|
41
|
+
}
|
|
42
|
+
function deliveryUnitResolutionKey(unitId, env) {
|
|
43
|
+
return `${env}::${unitId}`;
|
|
44
|
+
}
|
|
45
|
+
exports.createDiscoveryError = __webpack_exports__.createDiscoveryError;
|
|
46
|
+
exports.deliveryUnitResolutionKey = __webpack_exports__.deliveryUnitResolutionKey;
|
|
47
|
+
exports.formatSurfaceRef = __webpack_exports__.formatSurfaceRef;
|
|
48
|
+
exports.parseSurfaceRef = __webpack_exports__.parseSurfaceRef;
|
|
49
|
+
exports.surfaceResolutionKey = __webpack_exports__.surfaceResolutionKey;
|
|
50
|
+
exports.validateSurfaceRef = __webpack_exports__.validateSurfaceRef;
|
|
51
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
52
|
+
"createDiscoveryError",
|
|
53
|
+
"deliveryUnitResolutionKey",
|
|
54
|
+
"formatSurfaceRef",
|
|
55
|
+
"parseSurfaceRef",
|
|
56
|
+
"surfaceResolutionKey",
|
|
57
|
+
"validateSurfaceRef"
|
|
58
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
59
|
+
Object.defineProperty(exports, '__esModule', {
|
|
60
|
+
value: true
|
|
61
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { classifyModuleFederationFallback, createModuleFederationFallbackTelemetry, emitModuleFederationFallbackTelemetry } from "./index.mjs";
|
|
2
|
+
import { createDiscoveryError, formatSurfaceRef, parseSurfaceRef, validateSurfaceRef } from "./surface-resolution-types.mjs";
|
|
3
|
+
function classifyDiscoveryError(code) {
|
|
4
|
+
switch(code){
|
|
5
|
+
case 'major-not-published':
|
|
6
|
+
case 'stale-record':
|
|
7
|
+
return 'version-skew';
|
|
8
|
+
case 'identity-mismatch':
|
|
9
|
+
return 'contract';
|
|
10
|
+
case 'unknown-unit':
|
|
11
|
+
case 'unknown-surface':
|
|
12
|
+
case 'provider-unavailable':
|
|
13
|
+
return 'remote-unavailable';
|
|
14
|
+
default:
|
|
15
|
+
return 'remote-unavailable';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function toRemoteString(ref) {
|
|
19
|
+
return void 0 === validateSurfaceRef(ref) ? formatSurfaceRef(ref) : `${ref.unitId}#${ref.surfaceId}`;
|
|
20
|
+
}
|
|
21
|
+
async function reportFailure(options, ref, base) {
|
|
22
|
+
const remote = toRemoteString(ref);
|
|
23
|
+
const telemetry = createModuleFederationFallbackTelemetry({
|
|
24
|
+
appName: options.appName,
|
|
25
|
+
classification: base.classification,
|
|
26
|
+
error: base.error ?? base.discoveryError,
|
|
27
|
+
metadata: {
|
|
28
|
+
env: options.env,
|
|
29
|
+
surfaceRef: remote,
|
|
30
|
+
...base.discoveryError ? {
|
|
31
|
+
discoveryErrorCode: base.discoveryError.code
|
|
32
|
+
} : {},
|
|
33
|
+
...base.resolved ? {
|
|
34
|
+
buildMarker: base.resolved.buildMarker
|
|
35
|
+
} : {}
|
|
36
|
+
},
|
|
37
|
+
phase: base.phase,
|
|
38
|
+
remote,
|
|
39
|
+
status: 'degraded'
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
await emitModuleFederationFallbackTelemetry({
|
|
43
|
+
appName: options.appName,
|
|
44
|
+
classification: base.classification,
|
|
45
|
+
error: base.error ?? base.discoveryError,
|
|
46
|
+
metadata: telemetry.metadata,
|
|
47
|
+
phase: base.phase,
|
|
48
|
+
remote,
|
|
49
|
+
status: 'degraded'
|
|
50
|
+
}, options.telemetry ?? {});
|
|
51
|
+
} catch {}
|
|
52
|
+
const failure = {
|
|
53
|
+
ref,
|
|
54
|
+
env: options.env,
|
|
55
|
+
phase: base.phase,
|
|
56
|
+
classification: base.classification,
|
|
57
|
+
telemetry
|
|
58
|
+
};
|
|
59
|
+
if (base.discoveryError) failure.discoveryError = base.discoveryError;
|
|
60
|
+
if (void 0 !== base.error) failure.error = base.error;
|
|
61
|
+
if (base.resolved) failure.resolved = base.resolved;
|
|
62
|
+
const critical = (options.classification ?? 'critical') === 'critical';
|
|
63
|
+
const reason = base.discoveryError ?? (void 0 !== base.error ? base.error : createDiscoveryError('identity-mismatch', remote, `resolved record for "${remote}" is incompatible`, {
|
|
64
|
+
env: options.env
|
|
65
|
+
}));
|
|
66
|
+
let degradedValue;
|
|
67
|
+
try {
|
|
68
|
+
degradedValue = await options.degraded(failure);
|
|
69
|
+
} catch (handlerError) {
|
|
70
|
+
try {
|
|
71
|
+
await emitModuleFederationFallbackTelemetry({
|
|
72
|
+
appName: options.appName,
|
|
73
|
+
classification: base.classification,
|
|
74
|
+
error: handlerError,
|
|
75
|
+
metadata: {
|
|
76
|
+
...telemetry.metadata,
|
|
77
|
+
degradedHandlerFailed: true
|
|
78
|
+
},
|
|
79
|
+
phase: base.phase,
|
|
80
|
+
remote,
|
|
81
|
+
status: 'failed'
|
|
82
|
+
}, options.telemetry ?? {});
|
|
83
|
+
} catch {}
|
|
84
|
+
if (critical) throw reason;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (critical) throw reason;
|
|
88
|
+
return degradedValue;
|
|
89
|
+
}
|
|
90
|
+
async function consumeSurface(options) {
|
|
91
|
+
let ref;
|
|
92
|
+
if ('string' == typeof options.ref) {
|
|
93
|
+
const parsed = parseSurfaceRef(options.ref);
|
|
94
|
+
if (!parsed.ok) {
|
|
95
|
+
const hashIndex = options.ref.indexOf('#');
|
|
96
|
+
const echoed = -1 === hashIndex ? {
|
|
97
|
+
unitId: options.ref,
|
|
98
|
+
surfaceId: ''
|
|
99
|
+
} : {
|
|
100
|
+
unitId: options.ref.slice(0, hashIndex),
|
|
101
|
+
surfaceId: options.ref.slice(hashIndex + 1)
|
|
102
|
+
};
|
|
103
|
+
return reportFailure(options, echoed, {
|
|
104
|
+
phase: 'discovery',
|
|
105
|
+
classification: 'remote-unavailable',
|
|
106
|
+
discoveryError: createDiscoveryError('unknown-surface', options.ref, `SurfaceRef "${options.ref}" is not a valid canonical reference (${parsed.error.code}).`, {
|
|
107
|
+
parseError: parsed.error,
|
|
108
|
+
env: options.env
|
|
109
|
+
})
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
ref = parsed.ref;
|
|
113
|
+
} else ref = options.ref;
|
|
114
|
+
let resolution;
|
|
115
|
+
try {
|
|
116
|
+
resolution = await options.provider.resolve(ref, options.env);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
return reportFailure(options, ref, {
|
|
119
|
+
phase: 'discovery',
|
|
120
|
+
classification: classifyModuleFederationFallback(error),
|
|
121
|
+
error
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (!resolution.ok) return reportFailure(options, ref, {
|
|
125
|
+
phase: 'discovery',
|
|
126
|
+
classification: classifyDiscoveryError(resolution.error.code),
|
|
127
|
+
discoveryError: resolution.error
|
|
128
|
+
});
|
|
129
|
+
const resolved = resolution.unit;
|
|
130
|
+
if ('incompatible' === resolved.compatibility.status) return reportFailure(options, ref, {
|
|
131
|
+
phase: 'discovery',
|
|
132
|
+
classification: 'contract',
|
|
133
|
+
resolved
|
|
134
|
+
});
|
|
135
|
+
try {
|
|
136
|
+
return await options.load({
|
|
137
|
+
resolved,
|
|
138
|
+
ref,
|
|
139
|
+
env: options.env
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return reportFailure(options, ref, {
|
|
143
|
+
phase: 'load',
|
|
144
|
+
classification: classifyModuleFederationFallback(error),
|
|
145
|
+
error,
|
|
146
|
+
resolved
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function createSurfaceConsumer(base) {
|
|
151
|
+
return function(options) {
|
|
152
|
+
return consumeSurface({
|
|
153
|
+
...base,
|
|
154
|
+
...options
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export { consumeSurface, createSurfaceConsumer };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRuntimeContext } from "@modern-js/runtime";
|
|
3
|
+
const DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY = '__modernDistributedSsrFragments';
|
|
4
|
+
const DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY = '__modernDistributedSsrFragmentRequest';
|
|
5
|
+
function distributedSsrFragmentKey(remote, expose) {
|
|
6
|
+
return `${remote}::${expose}`;
|
|
7
|
+
}
|
|
8
|
+
function getDistributedSsrFragmentContext(response) {
|
|
9
|
+
const locals = response?.locals;
|
|
10
|
+
if ('object' != typeof locals || null === locals) return;
|
|
11
|
+
const context = DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY in locals ? locals[DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY] : void 0;
|
|
12
|
+
if ('object' != typeof context || null === context) return;
|
|
13
|
+
return context;
|
|
14
|
+
}
|
|
15
|
+
function useDistributedSsrFragmentProps({ boundaryId, expose }) {
|
|
16
|
+
const runtimeContext = useRuntimeContext();
|
|
17
|
+
const locals = runtimeContext.requestContext?.response?.locals;
|
|
18
|
+
const request = 'object' == typeof locals && null !== locals && DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY in locals ? locals[DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY] : void 0;
|
|
19
|
+
if ('object' != typeof request || null === request || !('boundaryId' in request) || request.boundaryId !== boundaryId || !('expose' in request) || request.expose !== expose) throw new Error(`Distributed SSR fragment request contract mismatch for ${boundaryId} ${expose}.`);
|
|
20
|
+
const props = 'props' in request ? request.props : void 0;
|
|
21
|
+
if ('object' != typeof props || null === props || Array.isArray(props)) throw new Error(`Distributed SSR fragment request props must be an object for ${boundaryId} ${expose}.`);
|
|
22
|
+
return props;
|
|
23
|
+
}
|
|
24
|
+
function isThenable(value) {
|
|
25
|
+
return void 0 !== value && 'then' in value && 'function' == typeof value.then;
|
|
26
|
+
}
|
|
27
|
+
function DistributedSsrBoundary({ children, expose, fallback, fragmentProps, remote }) {
|
|
28
|
+
const runtimeContext = useRuntimeContext();
|
|
29
|
+
const key = distributedSsrFragmentKey(remote, expose);
|
|
30
|
+
const attributes = {
|
|
31
|
+
'data-modern-distributed-ssr-boundary': key
|
|
32
|
+
};
|
|
33
|
+
if (runtimeContext.isBrowser) return /*#__PURE__*/ jsx("div", {
|
|
34
|
+
...attributes,
|
|
35
|
+
children: children
|
|
36
|
+
});
|
|
37
|
+
const fragmentContext = getDistributedSsrFragmentContext(runtimeContext.requestContext?.response);
|
|
38
|
+
if (void 0 === fragmentContext) return /*#__PURE__*/ jsx("div", {
|
|
39
|
+
...attributes,
|
|
40
|
+
children: children
|
|
41
|
+
});
|
|
42
|
+
const resolverFragmentProps = void 0 === fragmentProps ? {} : Object.fromEntries(Object.entries(fragmentProps));
|
|
43
|
+
const fragmentOrPromise = fragmentContext.resolve?.(remote, expose, resolverFragmentProps) ?? fragmentContext.fragments?.[key];
|
|
44
|
+
if (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 };
|