{"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/client\": () => import(\"@orpc/client\"),\n  \"@orpc/server\": () => import(\"@orpc/server\"),\n};\n\nfunction buildSharedConfig(): Record<\n  string,\n  {\n    version: string;\n    shareScope: 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          shareScope: config.shareScope,\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            yield* Effect.logDebug(`[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            yield* Effect.logInfo(`[MF] ✅ Registered ${pluginId}`);\n          }),\n\n        loadRemoteConstructor: (pluginId: string, url: string) =>\n          Effect.gen(function* () {\n            const remoteName = getNormalizedRemoteName(pluginId);\n            yield* Effect.logDebug(`[MF] Loading remote ${remoteName}`);\n            const modulePath = `${remoteName}/plugin`;\n\n            const pluginConstructor = 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                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            yield* Effect.logInfo(`[MF] ✅ Loaded constructor for ${pluginId}`);\n            return pluginConstructor;\n          }),\n      };\n    }),\n  },\n) {}\n"],"mappings":"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"}