{"version":3,"file":"module-federation.service.mjs","names":[],"sources":["../../../src/runtime/services/module-federation.service.ts"],"sourcesContent":["import { createInstance, getInstance } from \"@module-federation/enhanced/runtime\";\nimport { setGlobalFederationInstance } from \"@module-federation/runtime-core\";\nimport { Effect } from \"effect\";\nimport type { AnyPlugin } from \"../../types\";\nimport { ModuleFederationError } from \"../errors\";\nimport { type CoreSharedDepName, MF_CORE_SHARED_DEPS } from \"../mf-config\";\nimport { getNormalizedRemoteName } from \"./normalize\";\n\ntype RemoteModule = (new () => AnyPlugin) | { default: new () => AnyPlugin };\n\nconst coreModuleLoaders: Record<CoreSharedDepName, () => Promise<unknown>> = {\n  \"every-plugin\": () => import(\"every-plugin\"),\n  effect: () => import(\"effect\"),\n  zod: () => import(\"zod\"),\n  \"@orpc/contract\": () => import(\"@orpc/contract\"),\n  \"@orpc/server\": () => import(\"@orpc/server\"),\n};\n\nfunction buildSharedConfig(): Record<\n  string,\n  {\n    version: string;\n    get: () => Promise<() => unknown>;\n    shareConfig: (typeof MF_CORE_SHARED_DEPS)[CoreSharedDepName][\"shareConfig\"];\n  }\n> {\n  return Object.fromEntries(\n    (\n      Object.entries(MF_CORE_SHARED_DEPS) as [\n        CoreSharedDepName,\n        (typeof MF_CORE_SHARED_DEPS)[CoreSharedDepName],\n      ][]\n    ).map(([name, config]) => {\n      const load = coreModuleLoaders[name];\n\n      if (!load) {\n        throw new Error(`Missing core shared module loader for ${name}`);\n      }\n\n      return [\n        name,\n        {\n          version: config.version,\n          get: () => load().then((mod) => () => mod),\n          shareConfig: config.shareConfig,\n        },\n      ];\n    }),\n  );\n}\n\nconst createModuleFederationInstance = Effect.cached(\n  Effect.sync(() => {\n    try {\n      const shared = buildSharedConfig();\n      let instance = getInstance();\n\n      if (!instance) {\n        instance = createInstance({\n          name: \"host\",\n          remotes: [],\n          shared,\n        });\n\n        setGlobalFederationInstance(instance);\n      } else {\n        instance.registerShared(shared);\n      }\n\n      return instance;\n    } catch (error) {\n      throw new Error(`Failed to initialize Module Federation: ${error}`);\n    }\n  }),\n);\n\nexport class ModuleFederationService extends Effect.Service<ModuleFederationService>()(\n  \"ModuleFederationService\",\n  {\n    effect: Effect.gen(function* () {\n      const mf = yield* Effect.flatten(createModuleFederationInstance);\n\n      return {\n        registerRemote: (pluginId: string, url: string) =>\n          Effect.gen(function* () {\n            console.log(`[MF] Registering ${pluginId}`);\n\n            const remoteName = getNormalizedRemoteName(pluginId);\n            const type = url.endsWith(\"/mf-manifest.json\")\n              ? (\"manifest\" as const)\n              : url.endsWith(\"/remoteEntry.js\")\n                ? (\"script\" as const)\n                : undefined;\n\n            yield* Effect.try({\n              try: () =>\n                mf.registerRemotes([\n                  {\n                    name: remoteName,\n                    entry: url,\n                    ...(type ? { type } : {}),\n                  },\n                ]),\n              catch: (error): ModuleFederationError =>\n                new ModuleFederationError({\n                  pluginId,\n                  remoteUrl: url,\n                  cause: error instanceof Error ? error : new Error(String(error)),\n                }),\n            });\n\n            console.log(`[MF] ✅ Registered ${pluginId}`);\n          }),\n\n        loadRemoteConstructor: (pluginId: string, url: string) =>\n          Effect.gen(function* () {\n            const remoteName = getNormalizedRemoteName(pluginId);\n            console.log(`[MF] Loading remote ${remoteName}`);\n            const modulePath = `${remoteName}/plugin`;\n\n            return yield* Effect.tryPromise({\n              try: async () => {\n                const container = await mf.loadRemote<RemoteModule>(modulePath);\n                if (!container) {\n                  throw new Error(`No container returned for ${modulePath}`);\n                }\n\n                // Support multiple export patterns: direct function, default export, named exports\n                let Constructor: any;\n\n                if (typeof container === \"function\") {\n                  // Direct function export\n                  Constructor = container;\n                } else if (container.default) {\n                  // Default export\n                  Constructor = container.default;\n                } else {\n                  // Named export fallback - prioritize exports with 'binding' property (plugin classes)\n                  Constructor = Object.values(container).find(\n                    (exp) => typeof exp === \"function\" && (exp as any).binding !== undefined,\n                  );\n\n                  // Fallback to any function export if no binding found\n                  if (!Constructor) {\n                    Constructor = Object.values(container).find(\n                      (exp) => typeof exp === \"function\" && exp.prototype?.constructor === exp,\n                    );\n                  }\n                }\n\n                if (!Constructor || typeof Constructor !== \"function\") {\n                  const containerInfo =\n                    typeof container === \"object\"\n                      ? `Available exports: ${Object.keys(container).join(\", \")}`\n                      : `Container type: ${typeof container}`;\n\n                  throw new Error(\n                    `No valid plugin constructor found for '${pluginId}'.\\n` +\n                      `Supported patterns:\\n` +\n                      `  - export const YourPlugin = createPlugin({...})\\n` +\n                      `  - export default createPlugin({...})\\n` +\n                      `${containerInfo}`,\n                  );\n                }\n\n                // Validate it looks like a plugin constructor (has binding property)\n                if (!(Constructor as any).binding) {\n                  const containerInfo =\n                    typeof container === \"object\"\n                      ? `Found exports: ${Object.keys(container).join(\", \")}`\n                      : `Container type: ${typeof container}`;\n\n                  throw new Error(\n                    `Invalid plugin constructor for '${pluginId}'. ` +\n                      `The exported value must be created with createPlugin(). ` +\n                      `Found a function but it's missing the required 'binding' property.\\n` +\n                      `${containerInfo}`,\n                  );\n                }\n\n                console.log(`[MF] ✅ Loaded constructor for ${pluginId}`);\n                return Constructor;\n              },\n              catch: (error): ModuleFederationError =>\n                new ModuleFederationError({\n                  pluginId,\n                  remoteUrl: url,\n                  cause: error instanceof Error ? error : new Error(String(error)),\n                }),\n            });\n          }),\n      };\n    }),\n  },\n) {}\n"],"mappings":";;;;;;;;AAUA,MAAM,oBAAuE;CAC3E,sBAAsB,OAAO;CAC7B,cAAc,OAAO;CACrB,WAAW,OAAO;CAClB,wBAAwB,OAAO;CAC/B,sBAAsB,OAAO;CAC9B;AAED,SAAS,oBAOP;AACA,QAAO,OAAO,YAEV,OAAO,QAAQ,oBAAoB,CAInC,KAAK,CAAC,MAAM,YAAY;EACxB,MAAM,OAAO,kBAAkB;AAE/B,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,yCAAyC,OAAO;AAGlE,SAAO,CACL,MACA;GACE,SAAS,OAAO;GAChB,WAAW,MAAM,CAAC,MAAM,cAAc,IAAI;GAC1C,aAAa,OAAO;GACrB,CACF;GACD,CACH;;AAGH,MAAM,iCAAiC,OAAO,OAC5C,OAAO,WAAW;AAChB,KAAI;EACF,MAAM,SAAS,mBAAmB;EAClC,IAAI,WAAW,aAAa;AAE5B,MAAI,CAAC,UAAU;AACb,cAAW,eAAe;IACxB,MAAM;IACN,SAAS,EAAE;IACX;IACD,CAAC;AAEF,+BAA4B,SAAS;QAErC,UAAS,eAAe,OAAO;AAGjC,SAAO;UACA,OAAO;AACd,QAAM,IAAI,MAAM,2CAA2C,QAAQ;;EAErE,CACH;AAED,IAAa,0BAAb,cAA6C,OAAO,SAAkC,CACpF,2BACA,EACE,QAAQ,OAAO,IAAI,aAAa;CAC9B,MAAM,KAAK,OAAO,OAAO,QAAQ,+BAA+B;AAEhE,QAAO;EACL,iBAAiB,UAAkB,QACjC,OAAO,IAAI,aAAa;AACtB,WAAQ,IAAI,oBAAoB,WAAW;GAE3C,MAAM,aAAa,wBAAwB,SAAS;GACpD,MAAM,OAAO,IAAI,SAAS,oBAAoB,GACzC,aACD,IAAI,SAAS,kBAAkB,GAC5B,WACD;AAEN,UAAO,OAAO,IAAI;IAChB,WACE,GAAG,gBAAgB,CACjB;KACE,MAAM;KACN,OAAO;KACP,GAAI,OAAO,EAAE,MAAM,GAAG,EAAE;KACzB,CACF,CAAC;IACJ,QAAQ,UACN,IAAI,sBAAsB;KACxB;KACA,WAAW;KACX,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;KACjE,CAAC;IACL,CAAC;AAEF,WAAQ,IAAI,qBAAqB,WAAW;IAC5C;EAEJ,wBAAwB,UAAkB,QACxC,OAAO,IAAI,aAAa;GACtB,MAAM,aAAa,wBAAwB,SAAS;AACpD,WAAQ,IAAI,uBAAuB,aAAa;GAChD,MAAM,aAAa,GAAG,WAAW;AAEjC,UAAO,OAAO,OAAO,WAAW;IAC9B,KAAK,YAAY;KACf,MAAM,YAAY,MAAM,GAAG,WAAyB,WAAW;AAC/D,SAAI,CAAC,UACH,OAAM,IAAI,MAAM,6BAA6B,aAAa;KAI5D,IAAI;AAEJ,SAAI,OAAO,cAAc,WAEvB,eAAc;cACL,UAAU,QAEnB,eAAc,UAAU;UACnB;AAEL,oBAAc,OAAO,OAAO,UAAU,CAAC,MACpC,QAAQ,OAAO,QAAQ,cAAe,IAAY,YAAY,OAChE;AAGD,UAAI,CAAC,YACH,eAAc,OAAO,OAAO,UAAU,CAAC,MACpC,QAAQ,OAAO,QAAQ,cAAc,IAAI,WAAW,gBAAgB,IACtE;;AAIL,SAAI,CAAC,eAAe,OAAO,gBAAgB,YAAY;MACrD,MAAM,gBACJ,OAAO,cAAc,WACjB,sBAAsB,OAAO,KAAK,UAAU,CAAC,KAAK,KAAK,KACvD,mBAAmB,OAAO;AAEhC,YAAM,IAAI,MACR,0CAA0C,SAAS,sHAI9C,gBACN;;AAIH,SAAI,CAAE,YAAoB,SAAS;MACjC,MAAM,gBACJ,OAAO,cAAc,WACjB,kBAAkB,OAAO,KAAK,UAAU,CAAC,KAAK,KAAK,KACnD,mBAAmB,OAAO;AAEhC,YAAM,IAAI,MACR,mCAAmC,SAAS,iIAGvC,gBACN;;AAGH,aAAQ,IAAI,iCAAiC,WAAW;AACxD,YAAO;;IAET,QAAQ,UACN,IAAI,sBAAsB;KACxB;KACA,WAAW;KACX,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;KACjE,CAAC;IACL,CAAC;IACF;EACL;EACD,EACH,CACF,CAAC"}