const require_Action = require('./Action-CzhPMw2i.js'); const require_Broker = require('./Broker-DRFgFvXI.js'); let fs = require("fs"); fs = require_Action.__toESM(fs); let path = require("path"); path = require_Action.__toESM(path); let fs_promises = require("fs/promises"); let _module_federation_managers = require("@module-federation/managers"); let typescript = require("typescript"); typescript = require_Action.__toESM(typescript); let _module_federation_sdk = require("@module-federation/sdk"); let ansi_colors = require("ansi-colors"); ansi_colors = require_Action.__toESM(ansi_colors); let undici = require("undici"); let _module_federation_third_party_dts_extractor = require("@module-federation/third-party-dts-extractor"); let adm_zip = require("adm-zip"); adm_zip = require_Action.__toESM(adm_zip); let crypto = require("crypto"); crypto = require_Action.__toESM(crypto); let _module_federation_error_codes = require("@module-federation/error-codes"); let _module_federation_error_codes_node = require("@module-federation/error-codes/node"); let child_process = require("child_process"); let util = require("util"); util = require_Action.__toESM(util); let isomorphic_ws = require("isomorphic-ws"); isomorphic_ws = require_Action.__toESM(isomorphic_ws); let http = require("http"); http = require_Action.__toESM(http); let process$1 = require("process"); process$1 = require_Action.__toESM(process$1); //#region src/server/message/Action/AddPublisher.ts var AddPublisherAction = class extends require_Action.Action { constructor(payload) { super({ payload }, require_Action.ActionKind.ADD_PUBLISHER); } }; //#endregion //#region src/server/message/Action/AddSubscriber.ts var AddSubscriberAction = class extends require_Action.Action { constructor(payload) { super({ payload }, require_Action.ActionKind.ADD_SUBSCRIBER); } }; //#endregion //#region src/server/message/Action/ExitSubscriber.ts var ExitSubscriberAction = class extends require_Action.Action { constructor(payload) { super({ payload }, require_Action.ActionKind.EXIT_SUBSCRIBER); } }; //#endregion //#region src/server/message/Action/ExitPublisher.ts var ExitPublisherAction = class extends require_Action.Action { constructor(payload) { super({ payload }, require_Action.ActionKind.EXIT_PUBLISHER); } }; //#endregion //#region src/server/message/Action/NotifyWebClient.ts var NotifyWebClientAction = class extends require_Action.Action { constructor(payload) { super({ payload }, require_Action.ActionKind.NOTIFY_WEB_CLIENT); } }; //#endregion //#region src/server/message/Action/UpdatePublisher.ts var UpdatePublisherAction = class extends require_Action.Action { constructor(payload) { super({ payload }, require_Action.ActionKind.UPDATE_PUBLISHER); } }; //#endregion //#region src/server/broker/createBroker.ts function createBroker() { const sub = (0, child_process.fork)(path.default.resolve(__dirname, "./start-broker.js"), [], { detached: true, stdio: "ignore", env: process.env }); sub.send("start"); sub.unref(); return sub; } //#endregion //#region src/server/DevServer.ts var ModuleFederationDevServer = class { constructor(ctx) { this._publishWebSocket = null; this._subscriberWebsocketMap = {}; this._reconnect = true; this._reconnectTimes = 0; this._isConnected = false; this._isReconnecting = false; this._updateCallback = () => Promise.resolve(void 0); const { name, remotes, remoteTypeTarPath, updateCallback } = ctx; this._ip = require_Broker.getIPV4(); this._name = name; this._remotes = remotes; this._remoteTypeTarPath = remoteTypeTarPath; this._updateCallback = updateCallback; this._stopWhenSIGTERMOrSIGINT(); this._handleUnexpectedExit(); this._connectPublishToServer(); } _connectPublishToServer() { if (!this._reconnect) return; require_Broker.fileLog(`Publisher:${this._name} Trying to connect to ws://${this._ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}...`, require_Action.MF_SERVER_IDENTIFIER, "info"); this._publishWebSocket = new isomorphic_ws.default(`ws://${this._ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}?WEB_SOCKET_CONNECT_MAGIC_ID=${require_Broker.Broker.WEB_SOCKET_CONNECT_MAGIC_ID}`); this._publishWebSocket.on("open", () => { require_Broker.fileLog(`Current pid: ${process.pid}, publisher:${this._name} connected to ws://${this._ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}, starting service...`, require_Action.MF_SERVER_IDENTIFIER, "info"); this._isConnected = true; const addPublisherAction = new AddPublisherAction({ name: this._name, ip: this._ip, remoteTypeTarPath: this._remoteTypeTarPath }); this._publishWebSocket?.send(JSON.stringify(addPublisherAction)); this._connectSubscribers(); }); this._publishWebSocket.on("message", async (message) => { try { const parsedMessage = JSON.parse(message.toString()); if (parsedMessage.type === "Log") { if (parsedMessage.kind === require_Broker.LogKind.BrokerExitLog) { require_Broker.fileLog(`Receive broker exit signal, ${this._name} service will exit...`, require_Action.MF_SERVER_IDENTIFIER, "warn"); this._exit(); } } if (parsedMessage.type === "API") { if (parsedMessage.kind === require_Broker.APIKind.FETCH_TYPES) { const { payload: { remoteInfo } } = parsedMessage; require_Broker.fileLog(`${this._name} Receive broker FETCH_TYPES, payload as follows: ${JSON.stringify(remoteInfo, null, 2)}.`, require_Action.MF_SERVER_IDENTIFIER, "info"); await this.fetchDynamicRemoteTypes({ remoteInfo }); } } } catch (err) { console.error(err); const exitPublisher = new ExitPublisherAction({ name: this._name, ip: this._ip }); const exitSubscriber = new ExitSubscriberAction({ name: this._name, ip: this._ip, publishers: this._remotes.map((remote) => ({ name: remote.name, ip: remote.ip })) }); this._publishWebSocket?.send(JSON.stringify(exitPublisher)); this._publishWebSocket?.send(JSON.stringify(exitSubscriber)); require_Broker.fileLog("Parse messages error, ModuleFederationDevServer will exit...", require_Action.MF_SERVER_IDENTIFIER, "fatal"); this._exit(); } }); this._publishWebSocket.on("close", (code) => { require_Broker.fileLog(`Connection closed with code ${code}.`, require_Action.MF_SERVER_IDENTIFIER, "warn"); this._publishWebSocket && this._publishWebSocket.close(); this._publishWebSocket = null; if (!this._reconnect) return; const reconnectTime = require_Broker.fib(++this._reconnectTimes); require_Broker.fileLog(`start reconnecting to server after ${reconnectTime}s.`, require_Action.MF_SERVER_IDENTIFIER, "info"); setTimeout(() => this._connectPublishToServer(), reconnectTime * 1e3); }); this._publishWebSocket.on("error", this._tryCreateBackgroundBroker.bind(this)); } _connectSubscriberToServer(remote) { const { name, ip } = remote; require_Broker.fileLog(`remote module:${name} trying to connect to ws://${ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}...`, require_Action.MF_SERVER_IDENTIFIER, "info"); const identifier = require_Broker.getIdentifier({ name, ip }); this._subscriberWebsocketMap[identifier] = new isomorphic_ws.default(`ws://${ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}?WEB_SOCKET_CONNECT_MAGIC_ID=${require_Broker.Broker.WEB_SOCKET_CONNECT_MAGIC_ID}`); this._subscriberWebsocketMap[identifier].on("open", () => { require_Broker.fileLog(`Current pid: ${process.pid} remote module: ${name} connected to ws://${ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}, starting service...`, require_Action.MF_SERVER_IDENTIFIER, "info"); const addSubscriber = new AddSubscriberAction({ name: this._name, ip: this._ip, publishers: [{ name, ip }] }); this._subscriberWebsocketMap[identifier].send(JSON.stringify(addSubscriber)); }); this._subscriberWebsocketMap[identifier].on("message", async (message) => { try { const parsedMessage = JSON.parse(message.toString()); if (parsedMessage.type === "Log") { if (parsedMessage.kind === require_Broker.LogKind.BrokerExitLog) { require_Broker.fileLog(`${identifier}'s Server exit, thus ${identifier} will no longer has reload ability.`, require_Action.MF_SERVER_IDENTIFIER, "warn"); this._exit(); } } if (parsedMessage.type === "API") { if (parsedMessage.kind === require_Broker.APIKind.UPDATE_SUBSCRIBER) { const { payload: { updateKind, updateSourcePaths, name: subscribeName, remoteTypeTarPath, updateMode } } = parsedMessage; await this._updateSubscriber({ remoteTypeTarPath, name: subscribeName, updateKind, updateMode, updateSourcePaths }); } } } catch (err) { console.error(err); const exitSubscriber = new ExitSubscriberAction({ name: this._name, ip: this._ip, publishers: [{ name, ip }] }); this._subscriberWebsocketMap[identifier].send(JSON.stringify(exitSubscriber)); require_Broker.fileLog(`${identifier} exit, error: ${err instanceof Error ? err.toString() : JSON.stringify(err)} `, require_Action.MF_SERVER_IDENTIFIER, "warn"); } }); this._subscriberWebsocketMap[identifier].on("close", (code) => { require_Broker.fileLog(`Connection closed with code ${code}.`, require_Action.MF_SERVER_IDENTIFIER, "warn"); this._subscriberWebsocketMap[identifier]?.close(); delete this._subscriberWebsocketMap[identifier]; }); this._subscriberWebsocketMap[identifier].on("error", (err) => { if ("code" in err && err.code === "ETIMEDOUT") require_Broker.fileLog(`Can not connect ${JSON.stringify(remote)}, please make sure this remote is started locally.`, require_Action.MF_SERVER_IDENTIFIER, "warn"); else console.error(err); this._subscriberWebsocketMap[identifier]?.close(); delete this._subscriberWebsocketMap[identifier]; }); } _connectSubscribers() { this._remotes.forEach((remote) => { this._connectSubscriberToServer(remote); }); } async _updateSubscriber(options) { const { updateMode, updateKind, updateSourcePaths, name, remoteTypeTarPath, remoteInfo } = options; require_Broker.fileLog(`[_updateSubscriber] run, options: ${JSON.stringify(options, null, 2)}`, require_Action.MF_SERVER_IDENTIFIER, "warn"); if (updateMode === require_Action.UpdateMode.PASSIVE && updateSourcePaths.includes(this._name)) { require_Broker.fileLog(`[_updateSubscriber] run, updateSourcePaths:${updateSourcePaths} includes ${this._name}, update ignore!`, require_Action.MF_SERVER_IDENTIFIER, "warn"); return; } if (updateSourcePaths.slice(-1)[0] === this._name) { require_Broker.fileLog(`[_updateSubscriber] run, updateSourcePaths:${updateSourcePaths} ends is ${this._name}, update ignore!`, require_Action.MF_SERVER_IDENTIFIER, "warn"); return; } require_Broker.fileLog(`[_updateSubscriber] run, updateSourcePaths:${updateSourcePaths}, current module:${this._name}, update start...`, require_Action.MF_SERVER_IDENTIFIER, "info"); await this._updateCallback({ name, updateMode, updateKind, updateSourcePaths, remoteTypeTarPath, remoteInfo }); const newUpdateSourcePaths = updateSourcePaths.concat(this._name); const updatePublisher = new UpdatePublisherAction({ name: this._name, ip: this._ip, updateMode: require_Action.UpdateMode.PASSIVE, updateKind, updateSourcePaths: newUpdateSourcePaths, remoteTypeTarPath: this._remoteTypeTarPath }); require_Broker.fileLog(`[_updateSubscriber] run, updateSourcePaths:${newUpdateSourcePaths}, update publisher ${this._name} start...`, require_Action.MF_SERVER_IDENTIFIER, "info"); this._publishWebSocket?.send(JSON.stringify(updatePublisher)); } _tryCreateBackgroundBroker(err) { if (!((err?.code === "ECONNREFUSED" || err?.code === "ETIMEDOUT") && err.port === require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT)) { require_Broker.fileLog(`websocket error: ${err.stack}`, require_Action.MF_SERVER_IDENTIFIER, "fatal"); return; } require_Broker.fileLog(`Failed to connect to ws://${this._ip}:${require_Broker.Broker.DEFAULT_WEB_SOCKET_PORT}...`, require_Action.MF_SERVER_IDENTIFIER, "fatal"); this._isReconnecting = true; setTimeout(() => { this._isReconnecting = false; if (this._reconnect === false) return; require_Broker.fileLog("Creating new background broker...", require_Action.MF_SERVER_IDENTIFIER, "warn"); createBroker().on("message", (message) => { if (message === "ready") { require_Broker.fileLog("background broker started.", require_Action.MF_SERVER_IDENTIFIER, "info"); this._reconnectTimes = 1; if (process.send) process.send("ready"); } }); }, Math.ceil(100 * Math.random())); } _stopWhenSIGTERMOrSIGINT() { process.on("SIGTERM", () => { require_Broker.fileLog(`Process(${process.pid}) SIGTERM, ModuleFederationDevServer will exit...`, require_Action.MF_SERVER_IDENTIFIER, "warn"); this._exit(); }); process.on("SIGINT", () => { require_Broker.fileLog(`Process(${process.pid}) SIGINT, ModuleFederationDevServer will exit...`, require_Action.MF_SERVER_IDENTIFIER, "warn"); this._exit(); }); } _handleUnexpectedExit() { process.on("unhandledRejection", (error) => { if (this._isReconnecting) return; console.error("Unhandled Rejection Error: ", error); require_Broker.fileLog(`Process(${process.pid}) unhandledRejection, garfishModuleServer will exit...`, require_Action.MF_SERVER_IDENTIFIER, "error"); this._exit(); }); process.on("uncaughtException", (error) => { if (this._isReconnecting) return; console.error("Unhandled Exception Error: ", error); require_Broker.fileLog(`Process(${process.pid}) uncaughtException, garfishModuleServer will exit...`, require_Action.MF_SERVER_IDENTIFIER, "error"); this._exit(); }); } _exit() { this._reconnect = false; if (this._publishWebSocket) { const exitPublisher = new ExitPublisherAction({ name: this._name, ip: this._ip }); this._publishWebSocket.send(JSON.stringify(exitPublisher)); this._publishWebSocket.on("message", (message) => { const parsedMessage = JSON.parse(message.toString()); require_Broker.fileLog(`[${parsedMessage.kind}]: ${JSON.stringify(parsedMessage)}`, require_Action.MF_SERVER_IDENTIFIER, "info"); }); } if (this._publishWebSocket) { this._publishWebSocket.close(); this._publishWebSocket = null; } process.exit(0); } exit() { this._exit(); } update(options) { if (!this._publishWebSocket || !this._isConnected) return; const { updateKind, updateMode, updateSourcePaths, clientName } = options; require_Broker.fileLog(`update run, ${this._name} module update, updateKind: ${updateKind}, updateMode: ${updateMode}, updateSourcePaths: ${updateSourcePaths}`, require_Action.MF_SERVER_IDENTIFIER, "info"); if (updateKind === require_Broker.UpdateKind.RELOAD_PAGE) { const notifyWebClient = new NotifyWebClientAction({ name: clientName || this._name, updateMode }); this._publishWebSocket.send(JSON.stringify(notifyWebClient)); return; } const updatePublisher = new UpdatePublisherAction({ name: this._name, ip: this._ip, updateMode, updateKind, updateSourcePaths: [this._name], remoteTypeTarPath: this._remoteTypeTarPath }); this._publishWebSocket.send(JSON.stringify(updatePublisher)); } async fetchDynamicRemoteTypes(options) { const { remoteInfo, once } = options; const updateMode = require_Action.UpdateMode.PASSIVE; const updateKind = require_Broker.UpdateKind.UPDATE_TYPE; require_Broker.fileLog(`fetchDynamicRemoteTypes: remoteInfo: ${JSON.stringify(remoteInfo)}`, require_Action.MF_SERVER_IDENTIFIER, "info"); await this._updateCallback({ name: this._name, updateMode, updateKind, updateSourcePaths: [], remoteTypeTarPath: "", remoteInfo, once }); const updatePublisher = new UpdatePublisherAction({ name: this._name, ip: this._ip, updateMode, updateKind, updateSourcePaths: [this._name], remoteTypeTarPath: this._remoteTypeTarPath }); this._publishWebSocket.send(JSON.stringify(updatePublisher)); } }; //#endregion //#region src/server/createHttpServer.ts async function createHttpServer(options) { const { typeTarPath } = options; const freeport = await require_Broker.getFreePort(); const server = http.default.createServer((req, res) => { if ((req.url?.split("?")[0] ?? "/") === `/${require_Action.DEFAULT_TAR_NAME}`) { res.statusCode = 200; res.setHeader("Content-Type", "application/x-gzip"); if (req.method === "HEAD") { res.end(); return; } const stream = fs.default.createReadStream(typeTarPath); stream.on("error", () => { if (!res.headersSent) res.statusCode = 500; res.end(); }); res.on("close", () => { stream.destroy(); }); stream.pipe(res); return; } res.statusCode = 404; res.end(); }); server.listen(freeport); return { server, serverAddress: `http://${require_Broker.getIPV4()}:${freeport}` }; } //#endregion //#region src/core/lib/typeScriptCompiler.ts const STARTS_WITH_SLASH = /^\//; const DEFINITION_FILE_EXTENSION = ".d.ts"; const retrieveMfTypesPath = (tsConfig, remoteOptions) => (0, path.normalize)(tsConfig.compilerOptions.outDir.replace(remoteOptions.compiledTypesFolder, "")); const retrieveOriginalOutDir = (tsConfig, remoteOptions) => (0, path.normalize)(tsConfig.compilerOptions.outDir.replace(remoteOptions.compiledTypesFolder, "").replace(remoteOptions.typesFolder, "")); const retrieveMfAPITypesPath = (tsConfig, remoteOptions) => (0, path.join)(retrieveOriginalOutDir(tsConfig, remoteOptions), `${remoteOptions.typesFolder}.d.ts`); function writeTempTsConfig(tsConfig, context, name, cwd) { const createHash = (contents) => { return crypto.default.createHash("md5").update(contents).digest("hex"); }; const hash = createHash(`${JSON.stringify(tsConfig)}${name}${Date.now()}`); const tempTsConfigJsonPath = (0, path.resolve)(cwd ?? context, "node_modules", _module_federation_sdk.TEMP_DIR, `tsconfig.${hash}.json`); (0, fs.mkdirSync)((0, path.dirname)(tempTsConfigJsonPath), { recursive: true }); (0, fs.writeFileSync)(tempTsConfigJsonPath, JSON.stringify(tsConfig, null, 2)); return tempTsConfigJsonPath; } const removeExt = (f) => { const vueExt = ".vue"; const ext = (0, path.extname)(f); if (ext === vueExt) return f; const regexPattern = new RegExp(`\\${ext}$`); return f.replace(regexPattern, ""); }; function getExposeKey(options) { const { filePath, rootDir, outDir, mapExposeToEntry } = options; return mapExposeToEntry[(0, path.relative)(outDir, filePath.replace(new RegExp(`\\.d.ts$`), ""))]; } const processTypesFile = async (options) => { const { outDir, filePath, rootDir, cb, mapExposeToEntry, mfTypePath } = options; if (!(0, fs.existsSync)(filePath)) return; if ((await (0, fs_promises.stat)(filePath)).isDirectory()) { const files = await (0, fs_promises.readdir)(filePath); await Promise.all(files.map((file) => processTypesFile({ ...options, filePath: (0, path.join)(filePath, file) }))); } else if (filePath.endsWith(".d.ts")) { const exposeKey = getExposeKey({ filePath, rootDir, outDir, mapExposeToEntry }); if (exposeKey) { const mfeTypeEntry = (0, path.join)(mfTypePath, `${exposeKey === "." ? "index" : exposeKey}${DEFINITION_FILE_EXTENSION}`); const mfeTypeEntryDirectory = (0, path.dirname)(mfeTypeEntry); const relativePathToOutput = (0, path.relative)(mfeTypeEntryDirectory, filePath).replace(DEFINITION_FILE_EXTENSION, "").replace(STARTS_WITH_SLASH, "").split(path.sep).join("/"); (0, fs.mkdirSync)(mfeTypeEntryDirectory, { recursive: true }); await (0, fs_promises.writeFile)(mfeTypeEntry, `export * from './${relativePathToOutput}';\nexport { default } from './${relativePathToOutput}';`); } cb(await (0, fs_promises.readFile)(filePath, "utf8")); } }; const getPMFromUserAgent = () => { const userAgent = process.env["npm_config_user_agent"]; if (userAgent == null) return "null"; return userAgent.split("/")[0]; }; const resolvePackageManagerExecutable = () => { switch (getPMFromUserAgent()) { case "yarn": return "yarn"; default: return "npx"; } }; const splitCommandArgs = (value) => { const args = []; let current = ""; let quote = null; let escaped = false; for (const char of value) { if (escaped) { current += char; escaped = false; continue; } if (char === "\\") { escaped = true; continue; } if (quote) { if (char === quote) quote = null; else current += char; continue; } if (char === "\"" || char === "'") { quote = char; continue; } if (char.trim() === "") { if (current) { args.push(current); current = ""; } continue; } current += char; } if (current) args.push(current); return args; }; const formatCommandForDisplay = (executable, args) => { const formatArg = (arg) => { if (/[\s'"]/.test(arg)) return JSON.stringify(arg); return arg; }; return [executable, ...args].map(formatArg).join(" "); }; const compileTs = async (mapComponentsToExpose, tsConfig, remoteOptions) => { if (!Object.keys(mapComponentsToExpose).length) return; const { compilerOptions } = tsConfig; const tempTsConfigJsonPath = writeTempTsConfig(tsConfig, remoteOptions.context, remoteOptions.moduleFederationConfig.name || "mf", typeof remoteOptions.moduleFederationConfig.dts !== "boolean" ? remoteOptions.moduleFederationConfig.dts?.cwd ?? void 0 : void 0); require_Broker.logger.debug(`tempTsConfigJsonPath: ${tempTsConfigJsonPath}`); try { const mfTypePath = retrieveMfTypesPath(tsConfig, remoteOptions); const thirdPartyExtractor = new _module_federation_third_party_dts_extractor.ThirdPartyExtractor({ destDir: (0, path.resolve)(mfTypePath, "node_modules"), context: remoteOptions.context, exclude: typeof remoteOptions.extractThirdParty === "object" ? remoteOptions.extractThirdParty.exclude : void 0 }); const execPromise = util.default.promisify(child_process.execFile); const pmExecutable = resolvePackageManagerExecutable(); const compilerArgs = splitCommandArgs(remoteOptions.compilerInstance); const cmdArgs = [ ...compilerArgs.length > 0 ? compilerArgs : [remoteOptions.compilerInstance], "--project", tempTsConfigJsonPath ]; const cmd = formatCommandForDisplay(pmExecutable, cmdArgs); try { await execPromise(pmExecutable, cmdArgs, { cwd: typeof remoteOptions.moduleFederationConfig.dts !== "boolean" ? remoteOptions.moduleFederationConfig.dts?.cwd ?? void 0 : void 0, shell: process.platform === "win32" }); } catch (err) { if (compilerOptions.tsBuildInfoFile) try { await (0, fs_promises.rm)(compilerOptions.tsBuildInfoFile); } catch (e) {} (0, _module_federation_error_codes_node.logAndReport)(_module_federation_error_codes.TYPE_001, _module_federation_error_codes.typeDescMap, { cmd }, (msg) => { throw new Error(msg); }, void 0); } const mapExposeToEntry = Object.fromEntries(Object.entries(mapComponentsToExpose).map(([exposed, filename]) => { const normalizedFileName = (0, path.normalize)(filename); let relativeFileName = ""; if ((0, path.isAbsolute)(normalizedFileName)) relativeFileName = (0, path.relative)(tsConfig.compilerOptions.rootDir, normalizedFileName); else relativeFileName = (0, path.relative)(tsConfig.compilerOptions.rootDir, (0, path.resolve)(remoteOptions.context, normalizedFileName)); return [removeExt(relativeFileName), exposed]; })); const cb = remoteOptions.extractThirdParty ? thirdPartyExtractor.collectPkgs.bind(thirdPartyExtractor) : () => void 0; await processTypesFile({ outDir: compilerOptions.outDir, filePath: compilerOptions.outDir, rootDir: compilerOptions.rootDir, mfTypePath, cb, mapExposeToEntry }); if (remoteOptions.extractThirdParty) await thirdPartyExtractor.copyDts(); if (remoteOptions.deleteTsConfig) await (0, fs_promises.rm)(tempTsConfigJsonPath); } catch (err) { throw err; } }; //#endregion //#region src/core/lib/archiveHandler.ts const retrieveTypesZipPath = (mfTypesPath, remoteOptions) => (0, path.join)(mfTypesPath.replace(remoteOptions.typesFolder, ""), `${remoteOptions.typesFolder}.zip`); const createTypesArchive = async (tsConfig, remoteOptions) => { const mfTypesPath = retrieveMfTypesPath(tsConfig, remoteOptions); const zip = new adm_zip.default(); zip.addLocalFolder(mfTypesPath); return zip.writeZipPromise(retrieveTypesZipPath(mfTypesPath, remoteOptions)); }; const downloadErrorLogger = (destinationFolder, fileToDownload) => (reason) => { throw { ...reason, message: `Network error: Unable to download federated mocks for '${destinationFolder}' from '${fileToDownload}' because '${reason.message}'` }; }; const retrieveTypesArchiveDestinationPath = (hostOptions, destinationFolder) => { return (0, path.resolve)(hostOptions.context, hostOptions.typesFolder, destinationFolder); }; const downloadTypesArchive = (hostOptions) => { let retries = 0; return async ([destinationFolder, fileToDownload]) => { const destinationPath = retrieveTypesArchiveDestinationPath(hostOptions, destinationFolder); while (retries++ < hostOptions.maxRetries) try { const url = new URL(fileToDownload).href; const response = await nativeFetch(url, { responseType: "arraybuffer", timeout: hostOptions.timeout, family: hostOptions.family }).catch(downloadErrorLogger(destinationFolder, url)); if (typeof response.headers?.["content-type"] === "string" && response.headers["content-type"].includes("text/html")) throw new Error(`${url} receives invalid content-type: ${response.headers["content-type"]}`); try { if (hostOptions.deleteTypesFolder) await (0, fs_promises.rm)(destinationPath, { recursive: true, force: true }); } catch (error) { require_Broker.fileLog(`Unable to remove types folder, ${error}`, "downloadTypesArchive", "error"); } new adm_zip.default(Buffer.from(response.data)).extractAllTo(destinationPath, true); require_Broker.fileLog(`zip.extractAllTo success destinationPath: ${destinationPath}; url: ${url}`, "downloadTypesArchive", "info"); return [destinationFolder, destinationPath]; } catch (error) { require_Broker.fileLog(`Error during types archive download: ${error?.message || "unknown error"}`, "downloadTypesArchive", "error"); if (retries >= hostOptions.maxRetries) { require_Broker.logger.error(`Failed to download types archive from "${fileToDownload}". Set FEDERATION_DEBUG=true for details.`); if (hostOptions.abortOnError !== false) throw error; return; } } }; }; //#endregion //#region src/core/configurations/hostPlugin.ts const defaultOptions$1 = { typesFolder: "@mf-types", remoteTypesFolder: "@mf-types", deleteTypesFolder: true, maxRetries: 3, implementation: "", context: process.cwd(), abortOnError: true, consumeAPITypes: false, runtimePkgs: [], remoteTypeUrls: {}, timeout: 6e4, typesOnBuild: false, family: 4 }; const buildZipUrl = (hostOptions, url) => { const remoteUrl = new URL(url, "file:"); remoteUrl.pathname = `${remoteUrl.pathname.split("/").slice(0, -1).join("/")}/${hostOptions.remoteTypesFolder}.zip`; return remoteUrl.protocol === "file:" ? remoteUrl.pathname : remoteUrl.href; }; const buildApiTypeUrl = (zipUrl) => { if (!zipUrl) return; return zipUrl.replace(".zip", ".d.ts"); }; const retrieveRemoteInfo = (options) => { const { hostOptions, remoteAlias, remote } = options; const { remoteTypeUrls } = hostOptions; let decodedRemote = remote; if (decodedRemote.startsWith(_module_federation_sdk.ENCODE_NAME_PREFIX)) decodedRemote = (0, _module_federation_sdk.decodeName)(decodedRemote, _module_federation_sdk.ENCODE_NAME_PREFIX); const parsedInfo = (0, _module_federation_sdk.parseEntry)(decodedRemote, void 0, "@"); const url = "entry" in parsedInfo ? parsedInfo.entry : parsedInfo.name === decodedRemote ? decodedRemote : ""; let zipUrl = ""; let apiTypeUrl = ""; const name = parsedInfo.name || remoteAlias; const remoteTypeUrl = typeof remoteTypeUrls === "object" && remoteTypeUrls[name]; if (remoteTypeUrl) { zipUrl = remoteTypeUrl.zip; apiTypeUrl = remoteTypeUrl.api; } const shouldResolveTypeUrlsByConvention = Boolean(url && !url.includes(_module_federation_sdk.MANIFEST_EXT)); if (!zipUrl && shouldResolveTypeUrlsByConvention) zipUrl = buildZipUrl(hostOptions, url); if (!apiTypeUrl && zipUrl && (remoteTypeUrl || shouldResolveTypeUrlsByConvention)) apiTypeUrl = buildApiTypeUrl(zipUrl); return { name, url, zipUrl, apiTypeUrl, alias: remoteAlias }; }; const resolveRemotes = (hostOptions) => { const parsedOptions = _module_federation_managers.utils.parseOptions(hostOptions.moduleFederationConfig.remotes || {}, (item, key) => ({ remote: Array.isArray(item) ? item[0] : item, key }), (item, key) => ({ remote: Array.isArray(item.external) ? item.external[0] : item.external, key })); const remoteTypeUrls = hostOptions.remoteTypeUrls ?? {}; if (typeof remoteTypeUrls !== "object") throw new Error("remoteTypeUrls must be consumed before resolveRemotes"); const remoteInfos = Object.keys(remoteTypeUrls).reduce((sum, remoteName) => { const { zip, api, alias } = remoteTypeUrls[remoteName]; sum[alias] = { name: remoteName, url: "", zipUrl: zip, apiTypeUrl: api, alias: alias || remoteName }; return sum; }, {}); return parsedOptions.reduce((accumulator, item) => { const { key, remote } = item[1]; const res = retrieveRemoteInfo({ hostOptions, remoteAlias: key, remote }); if (accumulator[key]) { accumulator[key] = { ...accumulator[key], url: res.url, apiTypeUrl: accumulator[key].apiTypeUrl || res.apiTypeUrl }; return accumulator; } accumulator[key] = res; return accumulator; }, remoteInfos); }; const retrieveHostConfig = (options) => { validateOptions(options); const hostOptions = { ...defaultOptions$1, ...options }; return { hostOptions, mapRemotesToDownload: resolveRemotes(hostOptions) }; }; //#endregion //#region src/core/constant.ts const REMOTE_ALIAS_IDENTIFIER = "REMOTE_ALIAS_IDENTIFIER"; const REMOTE_API_TYPES_FILE_NAME = "apis.d.ts"; const HOST_API_TYPES_FILE_NAME = "index.d.ts"; //#endregion //#region src/core/lib/DTSManager.ts var DTSManager = class { constructor(options) { this.options = cloneDeepOptions(options); this.runtimePkgs = [ "@module-federation/runtime", "@module-federation/enhanced/runtime", "@module-federation/runtime-tools" ]; this.loadedRemoteAPIAlias = /* @__PURE__ */ new Set(); this.remoteAliasMap = {}; this.extraOptions = options?.extraOptions || {}; this.updatedRemoteInfos = {}; } generateAPITypes(mapComponentsToExpose) { const exposePaths = /* @__PURE__ */ new Set(); const packageType = Object.keys(mapComponentsToExpose).reduce((sum, exposeKey) => { const exposePath = path.default.join(REMOTE_ALIAS_IDENTIFIER, exposeKey).split(path.default.sep).join("/"); exposePaths.add(`'${exposePath}'`); sum = `T extends '${exposePath}' ? typeof import('${exposePath}') :` + sum; return sum; }, "any;"); return ` export type RemoteKeys = ${[...exposePaths].join(" | ")}; type PackageType = ${packageType}`; } async extractRemoteTypes(options) { const { remoteOptions, tsConfig } = options; if (!remoteOptions.extractRemoteTypes) return; let hasRemotes = false; const remotes = remoteOptions.moduleFederationConfig.remotes; if (remotes) { if (Array.isArray(remotes)) hasRemotes = Boolean(remotes.length); else if (typeof remotes === "object") hasRemotes = Boolean(Object.keys(remotes).length); } const mfTypesPath = retrieveMfTypesPath(tsConfig, remoteOptions); if (hasRemotes && this.options.host) try { const { hostOptions } = retrieveHostConfig(this.options.host); const remoteTypesFolder = path.default.resolve(hostOptions.context, hostOptions.typesFolder); const targetDir = path.default.join(mfTypesPath, "node_modules"); if (fs.default.existsSync(remoteTypesFolder)) { const targetFolder = path.default.resolve(remoteOptions.context, targetDir); await (0, fs_promises.mkdir)(targetFolder, { recursive: true }); await (0, fs_promises.cp)(remoteTypesFolder, targetFolder, { recursive: true, force: true }); } } catch (err) { if (this.options.host?.abortOnError === false) require_Broker.fileLog(`Unable to copy remote types, ${err}`, "extractRemoteTypes", "error"); else throw err; } } async generateTypes() { try { const { options } = this; if (!options.remote) throw new Error("options.remote is required if you want to generateTypes"); const { remoteOptions, tsConfig, mapComponentsToExpose } = retrieveRemoteConfig(options.remote); if (!Object.keys(mapComponentsToExpose).length) return; if (!tsConfig.files?.length) { require_Broker.logger.info("No type files to compile, skip"); return; } if (tsConfig.compilerOptions.tsBuildInfoFile) try { const tsBuildInfoFile = path.default.resolve(remoteOptions.context, tsConfig.compilerOptions.tsBuildInfoFile); const mfTypesPath = retrieveMfTypesPath(tsConfig, remoteOptions); if (!fs.default.existsSync(mfTypesPath)) fs.default.rmSync(tsBuildInfoFile, { force: true }); } catch (e) {} await this.extractRemoteTypes({ remoteOptions, tsConfig, mapComponentsToExpose }); await compileTs(mapComponentsToExpose, tsConfig, remoteOptions); await createTypesArchive(tsConfig, remoteOptions); let apiTypesPath = ""; if (remoteOptions.generateAPITypes) { const apiTypes = this.generateAPITypes(mapComponentsToExpose); apiTypesPath = retrieveMfAPITypesPath(tsConfig, remoteOptions); fs.default.writeFileSync(apiTypesPath, apiTypes); } try { if (remoteOptions.deleteTypesFolder) await (0, fs_promises.rm)(retrieveMfTypesPath(tsConfig, remoteOptions), { recursive: true, force: true }); } catch (err) { if (isDebugMode()) console.error(err); } require_Broker.logger.success("Federated types created correctly"); } catch (error) { if (this.options.remote?.abortOnError === false) { if (this.options.displayErrorInTerminal) require_Broker.logger.error(error); } else throw error; } } async requestRemoteManifest(remoteInfo, hostOptions) { try { if (!remoteInfo.url.includes(_module_federation_sdk.MANIFEST_EXT)) return remoteInfo; if (remoteInfo.zipUrl) return remoteInfo; const url = remoteInfo.url; const manifestJson = (await nativeFetch(url, { timeout: hostOptions.timeout, family: hostOptions.family })).data; if (!manifestJson.metaData.types.zip) throw new Error(`Can not get ${remoteInfo.name}'s types archive url!`); const addProtocol = (u) => { if (u.startsWith("//")) return `https:${u}`; return u; }; let publicPath; if ("publicPath" in manifestJson.metaData) publicPath = manifestJson.metaData.publicPath; else { const getPublicPath = new Function(manifestJson.metaData.getPublicPath); if (manifestJson.metaData.getPublicPath.startsWith("function")) publicPath = getPublicPath()(); else publicPath = getPublicPath(); } if (publicPath === "auto") publicPath = (0, _module_federation_sdk.inferAutoPublicPath)(remoteInfo.url); remoteInfo.zipUrl = new URL(path.default.join(addProtocol(publicPath), manifestJson.metaData.types.zip)).href; if (!manifestJson.metaData.types.api) { console.warn(`Can not get ${remoteInfo.name}'s api types url!`); remoteInfo.apiTypeUrl = ""; return remoteInfo; } remoteInfo.apiTypeUrl = new URL(path.default.join(addProtocol(publicPath), manifestJson.metaData.types.api)).href; return remoteInfo; } catch (_err) { require_Broker.fileLog(`fetch manifest failed, ${_err}, ${remoteInfo.name} will be ignored`, "requestRemoteManifest", "error"); return remoteInfo; } } async consumeTargetRemotes(hostOptions, remoteInfo) { if (!remoteInfo.zipUrl) throw new Error(`Can not get ${remoteInfo.name}'s types archive url!`); return downloadTypesArchive(hostOptions)([remoteInfo.alias, remoteInfo.zipUrl]); } async downloadAPITypes(remoteInfo, destinationPath, hostOptions) { const { apiTypeUrl } = remoteInfo; if (!apiTypeUrl) return; try { let apiTypeFile = (await nativeFetch(apiTypeUrl, { timeout: hostOptions.timeout, family: hostOptions.family })).data; apiTypeFile = apiTypeFile.replaceAll(REMOTE_ALIAS_IDENTIFIER, remoteInfo.alias); const filePath = path.default.join(destinationPath, REMOTE_API_TYPES_FILE_NAME); fs.default.writeFileSync(filePath, apiTypeFile); const existed = this.loadedRemoteAPIAlias.has(remoteInfo.alias); this.loadedRemoteAPIAlias.add(remoteInfo.alias); require_Broker.fileLog(`success`, "downloadAPITypes", "info"); return existed; } catch (err) { require_Broker.fileLog(`Unable to download "${remoteInfo.name}" api types, ${err}`, "downloadAPITypes", "error"); } } consumeAPITypes(hostOptions) { const apiTypeFileName = path.default.join(hostOptions.context, hostOptions.typesFolder, HOST_API_TYPES_FILE_NAME); try { const existedFile = fs.default.readFileSync(apiTypeFileName, "utf-8"); new _module_federation_third_party_dts_extractor.ThirdPartyExtractor({ destDir: "" }).collectTypeImports(existedFile).forEach((existedImport) => { const alias = existedImport.split("./").slice(1).join("./").replace("/apis.d.ts", ""); this.loadedRemoteAPIAlias.add(alias); }); } catch (err) {} if (!this.loadedRemoteAPIAlias.size) return; const packageTypes = []; const remoteKeys = []; const importTypeStr = [...this.loadedRemoteAPIAlias].sort().map((alias, index) => { const remoteKey = `RemoteKeys_${index}`; const packageType = `PackageType_${index}`; packageTypes.push(`T extends ${remoteKey} ? ${packageType}`); remoteKeys.push(remoteKey); return `import type { PackageType as ${packageType},RemoteKeys as ${remoteKey} } from './${alias}/apis.d.ts';`; }).join("\n"); const remoteKeysStr = `type RemoteKeys = ${remoteKeys.join(" | ")};`; const packageTypesStr = `type PackageType = ${[...packageTypes, "Y"].join(" :\n")} ;`; const runtimePkgs = /* @__PURE__ */ new Set(); [...this.runtimePkgs, ...hostOptions.runtimePkgs].forEach((pkg) => { runtimePkgs.add(pkg); }); const fileStr = `${importTypeStr} ${[...runtimePkgs].map((pkg) => { return `declare module "${pkg}" { ${remoteKeysStr} ${packageTypesStr} export function loadRemote(packageName: T): Promise>; export function loadRemote(packageName: T): Promise>; }`; }).join("\n")} `; fs.default.writeFileSync(path.default.join(hostOptions.context, hostOptions.typesFolder, HOST_API_TYPES_FILE_NAME), fileStr); } async consumeArchiveTypes(options) { const { hostOptions, mapRemotesToDownload } = retrieveHostConfig(options); const downloadPromises = Object.entries(mapRemotesToDownload).map(async (item) => { const remoteInfo = item[1]; if (!this.remoteAliasMap[remoteInfo.alias]) { const requiredRemoteInfo = await this.requestRemoteManifest(remoteInfo, hostOptions); this.remoteAliasMap[remoteInfo.alias] = requiredRemoteInfo; } return this.consumeTargetRemotes(hostOptions, this.remoteAliasMap[remoteInfo.alias]); }); return { hostOptions, downloadPromisesResult: await Promise.allSettled(downloadPromises) }; } async consumeTypes() { try { const { options } = this; if (!options.host) throw new Error("options.host is required if you want to consumeTypes"); const { mapRemotesToDownload } = retrieveHostConfig(options.host); if (!Object.keys(mapRemotesToDownload).length) return; const { downloadPromisesResult, hostOptions } = await this.consumeArchiveTypes(options.host); if (hostOptions.consumeAPITypes) { await Promise.all(downloadPromisesResult.map(async (item) => { if (item.status === "rejected" || !item.value) return; const [alias, destinationPath] = item.value; const remoteInfo = this.remoteAliasMap[alias]; if (!remoteInfo) return; await this.downloadAPITypes(remoteInfo, destinationPath, hostOptions); })); this.consumeAPITypes(hostOptions); } require_Broker.logger.success("Federated types extraction completed"); } catch (err) { if (this.options.host?.abortOnError === false) require_Broker.fileLog(`Unable to consume federated types, ${err}`, "consumeTypes", "error"); else throw err; } } async updateTypes(options) { try { const { remoteName, updateMode, remoteTarPath, remoteInfo: updatedRemoteInfo, once } = options; const hostName = this.options?.host?.moduleFederationConfig?.name; require_Broker.fileLog(`options: ${JSON.stringify(options, null, 2)};\nhostName: ${hostName}`, "updateTypes", "info"); if (updateMode === require_Action.UpdateMode.POSITIVE && remoteName === hostName) { if (!this.options.remote) return; await this.generateTypes(); } else { const { remoteAliasMap } = this; if (!this.options.host) return; const { hostOptions, mapRemotesToDownload } = retrieveHostConfig(this.options.host); const loadedRemoteInfo = Object.values(remoteAliasMap).find((i) => i.name === remoteName); const consumeTypes = async (requiredRemoteInfo) => { require_Broker.fileLog(`consumeTypes start`, "updateTypes", "info"); if (!requiredRemoteInfo.zipUrl) throw new Error(`Can not get ${requiredRemoteInfo.name}'s types archive url!`); const [_alias, destinationPath] = await this.consumeTargetRemotes(hostOptions, { ...requiredRemoteInfo, zipUrl: remoteTarPath || requiredRemoteInfo.zipUrl }); if (await this.downloadAPITypes(requiredRemoteInfo, destinationPath, hostOptions)) this.consumeAPITypes(hostOptions); require_Broker.fileLog(`consumeTypes end`, "updateTypes", "info"); }; require_Broker.fileLog(`loadedRemoteInfo: ${JSON.stringify(loadedRemoteInfo, null, 2)}`, "updateTypes", "info"); if (!loadedRemoteInfo) { const remoteInfo = Object.values(mapRemotesToDownload).find((item) => { return item.name === remoteName; }); require_Broker.fileLog(`remoteInfo: ${JSON.stringify(remoteInfo, null, 2)}`, "updateTypes", "info"); if (remoteInfo) { if (!this.remoteAliasMap[remoteInfo.alias]) { const requiredRemoteInfo = await this.requestRemoteManifest(remoteInfo, hostOptions); this.remoteAliasMap[remoteInfo.alias] = requiredRemoteInfo; } await consumeTypes(this.remoteAliasMap[remoteInfo.alias]); } else if (updatedRemoteInfo) { const consumeDynamicRemoteTypes = async () => { await consumeTypes(this.updatedRemoteInfos[updatedRemoteInfo.name]); }; if (!this.updatedRemoteInfos[updatedRemoteInfo.name]) { const parsedRemoteInfo = retrieveRemoteInfo({ hostOptions, remoteAlias: updatedRemoteInfo.alias || updatedRemoteInfo.name, remote: updatedRemoteInfo.url }); require_Broker.fileLog(`start request manifest`, "consumeTypes", "info"); this.updatedRemoteInfos[updatedRemoteInfo.name] = await this.requestRemoteManifest(parsedRemoteInfo, hostOptions); require_Broker.fileLog(`end request manifest, this.updatedRemoteInfos[updatedRemoteInfo.name]: ${JSON.stringify(this.updatedRemoteInfos[updatedRemoteInfo.name], null, 2)}`, "updateTypes", "info"); await consumeDynamicRemoteTypes(); } if (!once && this.updatedRemoteInfos[updatedRemoteInfo.name]) await consumeDynamicRemoteTypes(); } } else await consumeTypes(loadedRemoteInfo); } } catch (err) { require_Broker.fileLog(`updateTypes fail, ${err}`, "updateTypes", "error"); } } }; //#endregion //#region src/core/lib/utils.ts const dispatcherCache = /* @__PURE__ */ new Map(); function getDTSManagerConstructor(implementation) { if (implementation) { const NewConstructor = require(implementation); return NewConstructor.default ? NewConstructor.default : NewConstructor; } return DTSManager; } const validateOptions = (options) => { if (!options.moduleFederationConfig) throw new Error("moduleFederationConfig is required"); }; function retrieveTypesAssetsInfo(options) { let apiTypesPath = ""; let zipTypesPath = ""; try { const { tsConfig, remoteOptions, mapComponentsToExpose } = retrieveRemoteConfig(options); if (!Object.keys(mapComponentsToExpose).length || !tsConfig.files.length) return { apiTypesPath, zipTypesPath, zipName: "", apiFileName: "" }; zipTypesPath = retrieveTypesZipPath(retrieveMfTypesPath(tsConfig, remoteOptions), remoteOptions); if (remoteOptions.generateAPITypes) apiTypesPath = retrieveMfAPITypesPath(tsConfig, remoteOptions); return { apiTypesPath, zipTypesPath, zipName: path.default.basename(zipTypesPath), apiFileName: path.default.basename(apiTypesPath) }; } catch (err) { console.error(ansi_colors.default.red(`Unable to compile federated types, ${err}`)); return { apiTypesPath: "", zipTypesPath: "", zipName: "", apiFileName: "" }; } } function isDebugMode() { return Boolean(process.env["FEDERATION_DEBUG"]) || process.env["NODE_ENV"] === "test"; } const isTSProject = (dtsOptions, context = process.cwd()) => { if (dtsOptions === false) return false; try { let filepath = ""; if (typeof dtsOptions === "object" && dtsOptions.tsConfigPath) filepath = dtsOptions.tsConfigPath; else filepath = path.default.resolve(context, "./tsconfig.json"); if (!path.default.isAbsolute(filepath)) filepath = path.default.resolve(context, filepath); return fs.default.existsSync(filepath); } catch (err) { return false; } }; function cloneDeepOptions(options) { const excludeKeys = new Set(["manifest", "async"]); const cache = /* @__PURE__ */ new WeakMap(); function sanitize(val, key) { if (key !== void 0 && excludeKeys.has(key) || typeof val === "function") return false; if (key === "extractThirdParty" && Array.isArray(val)) return val.map(String); if (Array.isArray(val)) { if (cache.has(val)) return cache.get(val); const out = []; cache.set(val, out); val.forEach((v, i) => out.push(sanitize(v, String(i)))); return out; } if (val !== null && typeof val === "object" && Object.getPrototypeOf(val) === Object.prototype) { const obj = val; if (cache.has(obj)) return cache.get(obj); const out = {}; cache.set(obj, out); for (const [k, v] of Object.entries(obj)) out[k] = sanitize(v, k); return out; } return val; } return structuredClone(sanitize(options)); } const getEnvHeaders = () => { const headersStr = (0, _module_federation_sdk.getProcessEnv)()["MF_ENV_HEADERS"]; if (!headersStr || headersStr === "undefined") return {}; try { return { ...JSON.parse(headersStr) }; } catch { return {}; } }; const createDispatcherFromFamily = (family) => { if (!family) return void 0; if (dispatcherCache.has(family)) return dispatcherCache.get(family); try { const dispatcher = new undici.Agent({ connect: { family } }); dispatcherCache.set(family, dispatcher); return dispatcher; } catch {} }; const toHeaderRecord = (headers) => { const out = {}; headers.forEach((value, key) => { out[key.toLowerCase()] = value; }); return out; }; async function nativeFetch(url, config) { const controller = new AbortController(); const timeoutMs = config?.timeout ?? 6e4; const timeoutId = setTimeout(() => controller.abort(), timeoutMs); const headers = { ...getEnvHeaders(), ...config?.headers ?? {} }; const dispatcher = config?.dispatcher ?? createDispatcherFromFamily(config?.family); try { const resp = await fetch(url, { headers, signal: controller.signal, ...dispatcher ? { dispatcher } : {}, ...config?.agent ? { agent: config.agent } : {} }); const headerRecord = toHeaderRecord(resp.headers); if (!resp.ok) throw new Error(`Request failed with status ${resp.status}`); if (config?.responseType === "arraybuffer") return { data: await resp.arrayBuffer(), headers: headerRecord, status: resp.status }; return { data: (resp.headers.get("content-type") || "").includes("application/json") || url.endsWith(".json") ? await resp.json() : await resp.text(), headers: headerRecord, status: resp.status }; } finally { clearTimeout(timeoutId); } } //#endregion //#region src/core/configurations/remotePlugin.ts const defaultOptions = { tsConfigPath: "./tsconfig.json", typesFolder: "@mf-types", compiledTypesFolder: "compiled-types", hostRemoteTypesFolder: "@mf-types", deleteTypesFolder: true, additionalFilesToCompile: [], compilerInstance: "tsc", compileInChildProcess: false, implementation: "", generateAPITypes: false, context: process.cwd(), abortOnError: true, extractRemoteTypes: false, extractThirdParty: false, outputDir: "", deleteTsConfig: true }; function getEffectiveRootDir(parsedCommandLine) { const compilerOptions = parsedCommandLine.options; if (compilerOptions.rootDir) return compilerOptions.rootDir; const files = parsedCommandLine.fileNames; if (files.length > 0) return files.map((file) => (0, path.dirname)(file)).reduce((commonPath, fileDir) => { while (!fileDir.startsWith(commonPath)) commonPath = (0, path.dirname)(commonPath); return commonPath; }, files[0]); if (parsedCommandLine.projectReferences.length) { const relativeReferences = parsedCommandLine.projectReferences.filter((reference) => !(0, path.isAbsolute)(reference.originalPath ?? reference.path)); const referencesForRoot = relativeReferences.length ? relativeReferences : parsedCommandLine.projectReferences; return referencesForRoot.map((reference) => (0, path.dirname)(reference.path)).reduce((commonPath, filePath) => { while (!filePath.startsWith(commonPath)) commonPath = (0, path.dirname)(commonPath); return commonPath; }, (0, path.dirname)(referencesForRoot[0].path)); } throw new Error("Can not get effective rootDir, please set compilerOptions.rootDir !"); } const getDependentFiles = (rootFiles, configContent, rootDir) => { const dependentFiles = typescript.default.createProgram(rootFiles, configContent.options).getSourceFiles().map((file) => file.fileName).filter((file) => !file.endsWith(".d.ts") && file.startsWith(rootDir)); return dependentFiles.length ? dependentFiles : rootFiles; }; const readTsConfig = ({ tsConfigPath, typesFolder, compiledTypesFolder, context, additionalFilesToCompile, outputDir }, mapComponentsToExpose) => { const resolvedTsConfigPath = (0, path.resolve)(context, tsConfigPath); const readResult = typescript.default.readConfigFile(resolvedTsConfigPath, typescript.default.sys.readFile); if (readResult.error) throw new Error(readResult.error.messageText.toString()); const rawTsConfigJson = readResult.config; const configContent = typescript.default.parseJsonConfigFileContent(rawTsConfigJson, typescript.default.sys, (0, path.dirname)(resolvedTsConfigPath)); const rootDir = getEffectiveRootDir(configContent); const outDir = (0, path.resolve)(context, outputDir || configContent.options.outDir || "dist", typesFolder, compiledTypesFolder); const defaultCompilerOptions = { rootDir, emitDeclarationOnly: true, noEmit: false, declaration: true, outDir }; rawTsConfigJson.compilerOptions = rawTsConfigJson.compilerOptions || {}; rawTsConfigJson.compilerOptions = { incremental: true, tsBuildInfoFile: (0, path.resolve)(context, "node_modules/.cache/mf-types/.tsbuildinfo"), ...rawTsConfigJson.compilerOptions, ...defaultCompilerOptions }; const { paths, baseUrl, ...restCompilerOptions } = rawTsConfigJson.compilerOptions || {}; rawTsConfigJson.compilerOptions = restCompilerOptions; const outDirWithoutTypesFolder = (0, path.resolve)(context, outputDir || configContent.options.outDir || "dist"); const excludeExtensions = [".mdx", ".md"]; const filesToCompile = [...getDependentFiles([...Object.values(mapComponentsToExpose), ...additionalFilesToCompile].filter((filename) => !excludeExtensions.some((ext) => filename.endsWith(ext))), configContent, rootDir), ...configContent.fileNames.filter((filename) => filename.endsWith(".d.ts") && !filename.startsWith(outDirWithoutTypesFolder))]; rawTsConfigJson.include = []; rawTsConfigJson.files = [...new Set(filesToCompile)]; rawTsConfigJson.exclude = []; "references" in rawTsConfigJson && delete rawTsConfigJson.references; rawTsConfigJson.extends = resolvedTsConfigPath; rawTsConfigJson.compilerOptions.declarationDir = outDir; return rawTsConfigJson; }; const TS_EXTENSIONS = [ "ts", "tsx", "vue", "svelte" ]; const resolveWithExtension = (exposedPath, context) => { if ((0, path.extname)(exposedPath)) return (0, path.resolve)(context, exposedPath); for (const extension of TS_EXTENSIONS) { const exposedPathWithExtension = (0, path.resolve)(context, `${exposedPath}.${extension}`); if ((0, fs.existsSync)(exposedPathWithExtension)) return exposedPathWithExtension; } }; const resolveExposes = (remoteOptions) => { return _module_federation_managers.utils.parseOptions(remoteOptions.moduleFederationConfig.exposes || {}, (item, key) => ({ exposePath: Array.isArray(item) ? item[0] : item, key }), (item, key) => ({ exposePath: Array.isArray(item.import) ? item.import[0] : item.import[0], key })).reduce((accumulator, item) => { const { exposePath, key } = item[1]; accumulator[key] = resolveWithExtension(exposePath, remoteOptions.context) || resolveWithExtension((0, path.join)(exposePath, "index"), remoteOptions.context) || exposePath; return accumulator; }, {}); }; const retrieveRemoteConfig = (options) => { validateOptions(options); const remoteOptions = { ...defaultOptions, ...options }; const mapComponentsToExpose = resolveExposes(remoteOptions); const tsConfig = readTsConfig(remoteOptions, mapComponentsToExpose); if (tsConfig.compilerOptions.incremental && tsConfig.compilerOptions.tsBuildInfoFile && options.deleteTypesFolder !== true) remoteOptions.deleteTypesFolder = false; return { tsConfig, mapComponentsToExpose, remoteOptions }; }; //#endregion //#region src/core/lib/generateTypes.ts async function generateTypes(options) { return new (getDTSManagerConstructor(options.remote?.implementation))(options).generateTypes(); } //#endregion //#region src/core/rpc/types.ts let RpcGMCallTypes = /* @__PURE__ */ function(RpcGMCallTypes) { RpcGMCallTypes["CALL"] = "mf_call"; RpcGMCallTypes["RESOLVE"] = "mf_resolve"; RpcGMCallTypes["REJECT"] = "mf_reject"; RpcGMCallTypes["EXIT"] = "mf_exit"; return RpcGMCallTypes; }({}); //#endregion //#region src/core/rpc/expose-rpc.ts function exposeRpc(fn) { const sendMessage = (message) => new Promise((resolve, reject) => { if (!process$1.default.send) reject(/* @__PURE__ */ new Error(`Process ${process$1.default.pid} doesn't have IPC channels`)); else if (!process$1.default.connected) reject(/* @__PURE__ */ new Error(`Process ${process$1.default.pid} doesn't have open IPC channels`)); else process$1.default.send(message, void 0, void 0, (error) => { if (error) reject(error); else resolve(void 0); }); }); const handleMessage = async (message) => { if (message.type === RpcGMCallTypes.CALL) { if (!process$1.default.send) return; let value, error; try { value = await fn(...message.args); } catch (fnError) { error = fnError; } try { if (error) await sendMessage({ type: RpcGMCallTypes.REJECT, id: message.id, error }); else await sendMessage({ type: RpcGMCallTypes.RESOLVE, id: message.id, value }); } catch (sendError) { if (error) { if (error instanceof Error) console.error(error); } console.error(sendError); } } }; process$1.default.on("message", handleMessage); } //#endregion Object.defineProperty(exports, 'DTSManager', { enumerable: true, get: function () { return DTSManager; } }); Object.defineProperty(exports, 'HOST_API_TYPES_FILE_NAME', { enumerable: true, get: function () { return HOST_API_TYPES_FILE_NAME; } }); Object.defineProperty(exports, 'ModuleFederationDevServer', { enumerable: true, get: function () { return ModuleFederationDevServer; } }); Object.defineProperty(exports, 'REMOTE_ALIAS_IDENTIFIER', { enumerable: true, get: function () { return REMOTE_ALIAS_IDENTIFIER; } }); Object.defineProperty(exports, 'REMOTE_API_TYPES_FILE_NAME', { enumerable: true, get: function () { return REMOTE_API_TYPES_FILE_NAME; } }); Object.defineProperty(exports, 'RpcGMCallTypes', { enumerable: true, get: function () { return RpcGMCallTypes; } }); Object.defineProperty(exports, 'cloneDeepOptions', { enumerable: true, get: function () { return cloneDeepOptions; } }); Object.defineProperty(exports, 'createHttpServer', { enumerable: true, get: function () { return createHttpServer; } }); Object.defineProperty(exports, 'exposeRpc', { enumerable: true, get: function () { return exposeRpc; } }); Object.defineProperty(exports, 'generateTypes', { enumerable: true, get: function () { return generateTypes; } }); Object.defineProperty(exports, 'getDTSManagerConstructor', { enumerable: true, get: function () { return getDTSManagerConstructor; } }); Object.defineProperty(exports, 'isDebugMode', { enumerable: true, get: function () { return isDebugMode; } }); Object.defineProperty(exports, 'isTSProject', { enumerable: true, get: function () { return isTSProject; } }); Object.defineProperty(exports, 'retrieveHostConfig', { enumerable: true, get: function () { return retrieveHostConfig; } }); Object.defineProperty(exports, 'retrieveMfTypesPath', { enumerable: true, get: function () { return retrieveMfTypesPath; } }); Object.defineProperty(exports, 'retrieveOriginalOutDir', { enumerable: true, get: function () { return retrieveOriginalOutDir; } }); Object.defineProperty(exports, 'retrieveRemoteConfig', { enumerable: true, get: function () { return retrieveRemoteConfig; } }); Object.defineProperty(exports, 'retrieveTypesAssetsInfo', { enumerable: true, get: function () { return retrieveTypesAssetsInfo; } }); Object.defineProperty(exports, 'retrieveTypesZipPath', { enumerable: true, get: function () { return retrieveTypesZipPath; } }); Object.defineProperty(exports, 'validateOptions', { enumerable: true, get: function () { return validateOptions; } });