every-plugin 2.4.0 → 2.4.1

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.
Files changed (33) hide show
  1. package/dist/build/rspack/plugin.cjs +1 -1
  2. package/dist/build/rspack/plugin.cjs.map +1 -1
  3. package/dist/build/rspack/plugin.mjs +1 -1
  4. package/dist/build/rspack/plugin.mjs.map +1 -1
  5. package/dist/build/shared-deps.cjs +16 -0
  6. package/dist/build/shared-deps.cjs.map +1 -1
  7. package/dist/build/shared-deps.d.cts +28 -0
  8. package/dist/build/shared-deps.d.cts.map +1 -1
  9. package/dist/build/shared-deps.d.mts +28 -0
  10. package/dist/build/shared-deps.d.mts.map +1 -1
  11. package/dist/build/shared-deps.mjs +16 -0
  12. package/dist/build/shared-deps.mjs.map +1 -1
  13. package/dist/runtime/mf-config.cjs +17 -1
  14. package/dist/runtime/mf-config.cjs.map +1 -1
  15. package/dist/runtime/mf-config.d.cts +36 -0
  16. package/dist/runtime/mf-config.d.cts.map +1 -1
  17. package/dist/runtime/mf-config.d.mts +36 -0
  18. package/dist/runtime/mf-config.d.mts.map +1 -1
  19. package/dist/runtime/mf-config.mjs +17 -1
  20. package/dist/runtime/mf-config.mjs.map +1 -1
  21. package/dist/runtime/services/module-federation.service.cjs +19 -11
  22. package/dist/runtime/services/module-federation.service.cjs.map +1 -1
  23. package/dist/runtime/services/module-federation.service.d.cts.map +1 -1
  24. package/dist/runtime/services/module-federation.service.d.mts.map +1 -1
  25. package/dist/runtime/services/module-federation.service.mjs +19 -11
  26. package/dist/runtime/services/module-federation.service.mjs.map +1 -1
  27. package/package.json +7 -3
  28. package/skills/plugin-development/SKILL.md +208 -0
  29. package/skills/plugin-testing/SKILL.md +152 -0
  30. package/src/build/rspack/plugin.ts +1 -1
  31. package/src/build/shared-deps.ts +16 -0
  32. package/src/runtime/mf-config.ts +16 -0
  33. package/src/runtime/services/module-federation.service.ts +37 -24
@@ -1 +1 @@
1
- {"version":3,"file":"module-federation.service.cjs","names":["Effect","MF_SHARED_DEPS","getNormalizedRemoteName","ModuleFederationError"],"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 { MF_SHARED_DEPS, type SharedDepName } from \"../mf-config\";\nimport { getNormalizedRemoteName } from \"./normalize\";\n\ntype RemoteModule = (new () => AnyPlugin) | { default: new () => AnyPlugin };\n\nconst sharedModuleLoaders = {\n \"every-plugin\": () => import(\"every-plugin\"),\n effect: () => import(\"effect\"),\n zod: () => import(\"zod\"),\n} satisfies Record<SharedDepName, () => Promise<unknown>>;\n\nconst createModuleFederationInstance = Effect.cached(\n Effect.sync(() => {\n try {\n let instance = getInstance();\n\n if (!instance) {\n const shared = Object.fromEntries(\n (\n Object.entries(MF_SHARED_DEPS) as [\n SharedDepName,\n (typeof MF_SHARED_DEPS)[SharedDepName],\n ][]\n ).map(([name, config]) => {\n const load = sharedModuleLoaders[name];\n\n if (!load) {\n throw new Error(`Missing 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 instance = createInstance({\n name: \"host\",\n remotes: [],\n shared,\n });\n\n setGlobalFederationInstance(instance);\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":"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"}
1
+ {"version":3,"file":"module-federation.service.cjs","names":["MF_SHARED_DEPS","Effect","getNormalizedRemoteName","ModuleFederationError"],"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 { MF_SHARED_DEPS, type SharedDepName } from \"../mf-config\";\nimport { getNormalizedRemoteName } from \"./normalize\";\n\ntype RemoteModule = (new () => AnyPlugin) | { default: new () => AnyPlugin };\n\nconst sharedModuleLoaders = {\n \"every-plugin\": () => import(\"every-plugin\"),\n effect: () => import(\"effect\"),\n zod: () => import(\"zod\"),\n \"better-auth\": () => import(\"better-auth\"),\n \"drizzle-orm\": () => import(\"drizzle-orm\"),\n \"@orpc/contract\": () => import(\"@orpc/contract\"),\n \"@orpc/server\": () => import(\"@orpc/server\"),\n} satisfies Record<SharedDepName, () => Promise<unknown>>;\n\nfunction buildSharedConfig(): Record<\n string,\n {\n version: string;\n get: () => Promise<() => unknown>;\n shareConfig: (typeof MF_SHARED_DEPS)[SharedDepName][\"shareConfig\"];\n }\n> {\n return Object.fromEntries(\n (\n Object.entries(MF_SHARED_DEPS) as [SharedDepName, (typeof MF_SHARED_DEPS)[SharedDepName]][]\n ).map(([name, config]) => {\n const load = sharedModuleLoaders[name];\n\n if (!load) {\n throw new Error(`Missing 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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"module-federation.service.d.cts","names":[],"sources":["../../../src/runtime/services/module-federation.service.ts"],"mappings":";;;;cAIkD,4BAAA;;uCAiET,GAAA,aAAa,MAAA,CAAA,MAAA,OAAA,qBAAA;8CA+BN,GAAA,aAAa,MAAA,CAAA,MAAA,MAAA,qBAAA;EAAA;AAAA;AAAA,cAtChD,uBAAA,SAAgC,4BAAA"}
1
+ {"version":3,"file":"module-federation.service.d.cts","names":[],"sources":["../../../src/runtime/services/module-federation.service.ts"],"mappings":";;;;cAIkD,4BAAA;;uCA8ET,GAAA,aAAa,MAAA,CAAA,MAAA,OAAA,qBAAA;8CA+BN,GAAA,aAAa,MAAA,CAAA,MAAA,MAAA,qBAAA;EAAA;AAAA;AAAA,cAtChD,uBAAA,SAAgC,4BAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"module-federation.service.d.mts","names":[],"sources":["../../../src/runtime/services/module-federation.service.ts"],"mappings":";;;;cAIkD,4BAAA;;uCAiET,GAAA,aAAa,MAAA,CAAA,MAAA,OAAA,qBAAA;8CA+BN,GAAA,aAAa,MAAA,CAAA,MAAA,MAAA,qBAAA;EAAA;AAAA;AAAA,cAtChD,uBAAA,SAAgC,4BAAA"}
1
+ {"version":3,"file":"module-federation.service.d.mts","names":[],"sources":["../../../src/runtime/services/module-federation.service.ts"],"mappings":";;;;cAIkD,4BAAA;;uCA8ET,GAAA,aAAa,MAAA,CAAA,MAAA,OAAA,qBAAA;8CA+BN,GAAA,aAAa,MAAA,CAAA,MAAA,MAAA,qBAAA;EAAA;AAAA;AAAA,cAtChD,uBAAA,SAAgC,4BAAA"}
@@ -9,27 +9,35 @@ import { setGlobalFederationInstance } from "@module-federation/runtime-core";
9
9
  const sharedModuleLoaders = {
10
10
  "every-plugin": () => import("../../index.mjs"),
11
11
  effect: () => import("effect"),
12
- zod: () => import("zod")
12
+ zod: () => import("zod"),
13
+ "better-auth": () => import("../../node_modules/.bun/better-auth@1.6.9_a51fe808ef526527/node_modules/better-auth/dist/index.mjs"),
14
+ "drizzle-orm": () => import("../../node_modules/.bun/drizzle-orm@0.45.2_5d168cad3842e387/node_modules/drizzle-orm/index.mjs"),
15
+ "@orpc/contract": () => import("@orpc/contract"),
16
+ "@orpc/server": () => import("@orpc/server")
13
17
  };
18
+ function buildSharedConfig() {
19
+ return Object.fromEntries(Object.entries(MF_SHARED_DEPS).map(([name, config]) => {
20
+ const load = sharedModuleLoaders[name];
21
+ if (!load) throw new Error(`Missing shared module loader for ${name}`);
22
+ return [name, {
23
+ version: config.version,
24
+ get: () => load().then((mod) => () => mod),
25
+ shareConfig: config.shareConfig
26
+ }];
27
+ }));
28
+ }
14
29
  const createModuleFederationInstance = Effect.cached(Effect.sync(() => {
15
30
  try {
31
+ const shared = buildSharedConfig();
16
32
  let instance = getInstance();
17
33
  if (!instance) {
18
34
  instance = createInstance({
19
35
  name: "host",
20
36
  remotes: [],
21
- shared: Object.fromEntries(Object.entries(MF_SHARED_DEPS).map(([name, config]) => {
22
- const load = sharedModuleLoaders[name];
23
- if (!load) throw new Error(`Missing shared module loader for ${name}`);
24
- return [name, {
25
- version: config.version,
26
- get: () => load().then((mod) => () => mod),
27
- shareConfig: config.shareConfig
28
- }];
29
- }))
37
+ shared
30
38
  });
31
39
  setGlobalFederationInstance(instance);
32
- }
40
+ } else instance.registerShared(shared);
33
41
  return instance;
34
42
  } catch (error) {
35
43
  throw new Error(`Failed to initialize Module Federation: ${error}`);
@@ -1 +1 @@
1
- {"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 { MF_SHARED_DEPS, type SharedDepName } from \"../mf-config\";\nimport { getNormalizedRemoteName } from \"./normalize\";\n\ntype RemoteModule = (new () => AnyPlugin) | { default: new () => AnyPlugin };\n\nconst sharedModuleLoaders = {\n \"every-plugin\": () => import(\"every-plugin\"),\n effect: () => import(\"effect\"),\n zod: () => import(\"zod\"),\n} satisfies Record<SharedDepName, () => Promise<unknown>>;\n\nconst createModuleFederationInstance = Effect.cached(\n Effect.sync(() => {\n try {\n let instance = getInstance();\n\n if (!instance) {\n const shared = Object.fromEntries(\n (\n Object.entries(MF_SHARED_DEPS) as [\n SharedDepName,\n (typeof MF_SHARED_DEPS)[SharedDepName],\n ][]\n ).map(([name, config]) => {\n const load = sharedModuleLoaders[name];\n\n if (!load) {\n throw new Error(`Missing 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 instance = createInstance({\n name: \"host\",\n remotes: [],\n shared,\n });\n\n setGlobalFederationInstance(instance);\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":"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"}
1
+ {"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 { MF_SHARED_DEPS, type SharedDepName } from \"../mf-config\";\nimport { getNormalizedRemoteName } from \"./normalize\";\n\ntype RemoteModule = (new () => AnyPlugin) | { default: new () => AnyPlugin };\n\nconst sharedModuleLoaders = {\n \"every-plugin\": () => import(\"every-plugin\"),\n effect: () => import(\"effect\"),\n zod: () => import(\"zod\"),\n \"better-auth\": () => import(\"better-auth\"),\n \"drizzle-orm\": () => import(\"drizzle-orm\"),\n \"@orpc/contract\": () => import(\"@orpc/contract\"),\n \"@orpc/server\": () => import(\"@orpc/server\"),\n} satisfies Record<SharedDepName, () => Promise<unknown>>;\n\nfunction buildSharedConfig(): Record<\n string,\n {\n version: string;\n get: () => Promise<() => unknown>;\n shareConfig: (typeof MF_SHARED_DEPS)[SharedDepName][\"shareConfig\"];\n }\n> {\n return Object.fromEntries(\n (\n Object.entries(MF_SHARED_DEPS) as [SharedDepName, (typeof MF_SHARED_DEPS)[SharedDepName]][]\n ).map(([name, config]) => {\n const load = sharedModuleLoaders[name];\n\n if (!load) {\n throw new Error(`Missing 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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "every-plugin",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -81,7 +81,9 @@
81
81
  },
82
82
  "files": [
83
83
  "dist",
84
- "src"
84
+ "src",
85
+ "skills",
86
+ "!skills/_artifacts"
85
87
  ],
86
88
  "scripts": {
87
89
  "build": "tsdown",
@@ -111,6 +113,7 @@
111
113
  "@orpc/client": "^1.13.4",
112
114
  "@orpc/openapi": "^1.13.4",
113
115
  "@rspack/cli": "^1.7.4",
116
+ "@tanstack/intent": "^0.0.40",
114
117
  "@types/bun": "^1.3.7",
115
118
  "@types/node": "^25.1.0",
116
119
  "@vitest/ui": "4.1.2",
@@ -134,7 +137,8 @@
134
137
  "module-federation",
135
138
  "orpc",
136
139
  "zod",
137
- "typescript"
140
+ "typescript",
141
+ "tanstack-intent"
138
142
  ],
139
143
  "author": "plugin.every.near",
140
144
  "license": "MIT",
@@ -0,0 +1,208 @@
1
+ ---
2
+ name: plugin-development
3
+ description: Build every-plugin modules with oRPC contracts, Effect services, and Module Federation. Use when creating or modifying plugins under plugins/ or the _template scaffold.
4
+ metadata:
5
+ sources: "src/plugin.ts,src/orpc.ts,src/errors.ts,src/zod.ts,src/types.ts"
6
+ ---
7
+
8
+ # every-plugin Development
9
+
10
+ ## Plugin Structure
11
+
12
+ Every plugin has three core files:
13
+
14
+ ```
15
+ plugins/your-plugin/
16
+ ├── src/
17
+ │ ├── contract.ts # oRPC route definitions + Zod schemas
18
+ │ ├── service.ts # Business logic (plain class, Effect error handling)
19
+ │ ├── index.ts # createPlugin() wiring
20
+ │ └── __tests__/ # Integration & unit tests
21
+ ├── package.json
22
+ ├── rspack.config.js # Build config (every-plugin provides defaults)
23
+ ├── plugin.dev.ts # Dev server config (port, variables, secrets)
24
+ └── tsconfig.json
25
+ ```
26
+
27
+ ## Step 1: Define the Contract
28
+
29
+ Import from `every-plugin` subpath exports — not from `@orpc/*` or `zod` directly:
30
+
31
+ ```typescript
32
+ import { eventIterator, oc } from "every-plugin/orpc";
33
+ import { z } from "every-plugin/zod";
34
+
35
+ const Errors = {
36
+ UNAUTHORIZED: { status: 401, message: "Auth required" },
37
+ NOT_FOUND: { status: 404, message: "Not found" },
38
+ };
39
+
40
+ export const contract = oc.router({
41
+ getById: oc
42
+ .route({ method: "GET", path: "/items/{id}" })
43
+ .input(z.object({ id: z.string() }))
44
+ .output(z.object({ item: ItemSchema }))
45
+ .errors(Errors),
46
+
47
+ search: oc
48
+ .route({ method: "GET", path: "/search" })
49
+ .input(z.object({ query: z.string(), limit: z.number().default(10) }))
50
+ .output(eventIterator(SearchResultSchema)),
51
+
52
+ ping: oc
53
+ .route({ method: "GET", path: "/ping" })
54
+ .output(z.object({ status: z.literal("ok"), timestamp: z.string().datetime() })),
55
+ });
56
+
57
+ export type ContractType = typeof contract;
58
+ ```
59
+
60
+ Key points:
61
+ - Always import `oc` from `every-plugin/orpc`, `z` from `every-plugin/zod`, `Effect` from `every-plugin/effect`
62
+ - Use `eventIterator(schema)` for streaming responses
63
+ - Define error objects with `status` + `message` and pass via `.errors()`
64
+ - Use `CommonPluginErrors` from `every-plugin/errors` for standard UNAUTHORIZED/FORBIDDEN/NOT_FOUND/BAD_REQUEST
65
+
66
+ ## Step 2: Create the Service
67
+
68
+ Plain TypeScript class with Effect error handling:
69
+
70
+ ```typescript
71
+ import { Effect } from "every-plugin/effect";
72
+
73
+ export class MyService {
74
+ constructor(private baseUrl: string, private apiKey: string) {}
75
+
76
+ getById(id: string) {
77
+ return Effect.tryPromise({
78
+ try: async () => {
79
+ const res = await fetch(`${this.baseUrl}/items/${id}`);
80
+ if (!res.ok) throw new Error(`Fetch failed: ${res.status}`);
81
+ return res.json();
82
+ },
83
+ catch: (error: unknown) => new Error(`Failed to fetch item: ${error}`),
84
+ });
85
+ }
86
+
87
+ ping() {
88
+ return Effect.succeed({ status: "ok" as const, timestamp: new Date().toISOString() });
89
+ }
90
+ }
91
+ ```
92
+
93
+ ## Step 3: Wire with createPlugin
94
+
95
+ ```typescript
96
+ import { createPlugin } from "every-plugin";
97
+ import { Effect } from "every-plugin/effect";
98
+ import { z } from "every-plugin/zod";
99
+ import { contract } from "./contract";
100
+ import { MyService } from "./service";
101
+
102
+ export default createPlugin({
103
+ variables: z.object({
104
+ baseUrl: z.url().default("https://api.example.com"),
105
+ }),
106
+ secrets: z.object({
107
+ apiKey: z.string().min(1),
108
+ }),
109
+ contract,
110
+
111
+ initialize: (config) =>
112
+ Effect.gen(function* () {
113
+ const service = new MyService(config.variables.baseUrl, config.secrets.apiKey);
114
+ yield* service.ping();
115
+ return { service };
116
+ }),
117
+
118
+ shutdown: () => Effect.void,
119
+
120
+ createRouter: (context, builder) => {
121
+ const { service } = context;
122
+
123
+ const requireAuth = builder.middleware(async ({ context, next }) => {
124
+ if (!context.userId) throw new ORPCError("UNAUTHORIZED", { message: "Auth required" });
125
+ return next({ context: { ...context, userId: context.userId } });
126
+ });
127
+
128
+ return {
129
+ getById: builder.getById.use(requireAuth).handler(async ({ input, context }) => {
130
+ return await Effect.runPromise(service.getById(input.id));
131
+ }),
132
+ ping: builder.ping.handler(async () => {
133
+ return await Effect.runPromise(service.ping());
134
+ }),
135
+ };
136
+ },
137
+ });
138
+ ```
139
+
140
+ ## Plugin Composition (withPlugins)
141
+
142
+ When an API plugin needs to call other plugins in-process:
143
+
144
+ ```typescript
145
+ import type { PluginsClient } from "./plugins-client.gen";
146
+
147
+ export default createPlugin.withPlugins<PluginsClient>()({
148
+ variables: z.object({ demoMessage: z.string().optional() }),
149
+ contract,
150
+ initialize: (config, plugins) =>
151
+ Effect.sync(() => ({ plugins, demoMessage: config.variables.demoMessage ?? "not configured" })),
152
+ createRouter: (services, builder) => ({
153
+ pluginDemo: builder.pluginDemo.handler(async () => {
154
+ const status = await services.plugins.registry().getRegistryStatus();
155
+ return { apiVariable: services.demoMessage, registryStatus: status };
156
+ }),
157
+ }),
158
+ });
159
+ ```
160
+
161
+ - `pluginsClient` is a map of `createClient` factories, typed by the generated `PluginsClient`
162
+ - Call `services.plugins.{key}()` to execute plugin routers in-process — no HTTP roundtrip
163
+ - The host loads non-API plugins first (Phase 1), then loads the API with `pluginsClient` injected (Phase 2)
164
+
165
+ ## Dev Server Config (plugin.dev.ts)
166
+
167
+ ```typescript
168
+ import type { PluginConfigInput } from "every-plugin";
169
+ import Plugin from "./src/index";
170
+
171
+ export default {
172
+ pluginId: "my-plugin",
173
+ port: 3010,
174
+ config: {
175
+ variables: {
176
+ baseUrl: "https://api.example.com",
177
+ },
178
+ secrets: {
179
+ apiKey: "dev-only-key",
180
+ },
181
+ } satisfies PluginConfigInput<typeof Plugin>,
182
+ };
183
+ ```
184
+
185
+ Port assignments: host=3000, api=3001, auth=3002, ui=3003, ui-ssr=3004, plugins=3010+.
186
+
187
+ ## Build Config (rspack.config.js)
188
+
189
+ every-plugin provides rspack defaults via `EveryPluginDevServer`:
190
+
191
+ ```javascript
192
+ const { EveryPluginDevServer } = require("every-plugin/build/rspack");
193
+
194
+ module.exports = EveryPluginDevServer.configure(__dirname, {
195
+ pluginId: "my-plugin",
196
+ port: 3010,
197
+ });
198
+ ```
199
+
200
+ No manual rspack configuration needed — the helper handles Module Federation, shared deps, and dev server setup.
201
+
202
+ ## Common Mistakes
203
+
204
+ - Importing `oc` from `@orpc/contract` instead of `every-plugin/orpc` — will cause version mismatches in Module Federation
205
+ - Importing `z` from `zod` instead of `every-plugin/zod` — same singleton issue
206
+ - Forgetting `.errors(Errors)` on routes that can throw ORPCError — untyped errors
207
+ - Using `Effect.runPromise` inside `Effect.gen` — use `yield*` instead for proper error channel
208
+ - Putting business logic in `createRouter` — keep it in the service class, router is just glue
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: plugin-testing
3
+ description: Test every-plugin modules with vitest and the plugin runtime. Use when writing or modifying plugin tests under plugins/*/src/__tests__/ or plugins/*/tests/.
4
+ metadata:
5
+ sources: "src/testing/index.ts,src/runtime/index.ts"
6
+ ---
7
+
8
+ # every-plugin Testing
9
+
10
+ ## Test Structure
11
+
12
+ ```
13
+ plugins/your-plugin/
14
+ ├── src/__tests__/
15
+ │ ├── integration.test.ts # Full plugin lifecycle via runtime
16
+ │ └── unit.test.ts # Service class in isolation
17
+ └── vitest.config.ts
18
+ ```
19
+
20
+ ## Unit Tests (Service Only)
21
+
22
+ Test the service class directly without the plugin runtime:
23
+
24
+ ```typescript
25
+ import { describe, expect, it } from "vitest";
26
+ import { Effect } from "effect";
27
+ import { MyService } from "../service";
28
+
29
+ describe("MyService", () => {
30
+ const service = new MyService("https://api.example.com", "test-key");
31
+
32
+ it("ping returns ok", async () => {
33
+ const result = await Effect.runPromise(service.ping());
34
+ expect(result.status).toBe("ok");
35
+ });
36
+
37
+ it("getById returns item", async () => {
38
+ const result = await Effect.runPromise(service.getById("item-1"));
39
+ expect(result.item.id).toBe("item-1");
40
+ });
41
+
42
+ it("getById throws on missing item", async () => {
43
+ await expect(Effect.runPromise(service.getById("missing"))).rejects.toThrow();
44
+ });
45
+ });
46
+ ```
47
+
48
+ ## Integration Tests (Plugin Runtime)
49
+
50
+ Test the full plugin lifecycle — initialization, router execution, shutdown:
51
+
52
+ ```typescript
53
+ import { describe, expect, it, beforeAll, afterAll } from "vitest";
54
+ import { createPluginRuntime } from "every-plugin/runtime";
55
+ import Plugin from "../index";
56
+
57
+ describe("MyPlugin integration", () => {
58
+ let runtime: Awaited<ReturnType<typeof createPluginRuntime>>;
59
+ let client: any;
60
+
61
+ beforeAll(async () => {
62
+ runtime = createPluginRuntime();
63
+ const result = await runtime.usePlugin("my-plugin", {
64
+ variables: { baseUrl: "https://api.example.com" },
65
+ secrets: { apiKey: "test-key" },
66
+ });
67
+ client = result.createClient();
68
+ });
69
+
70
+ afterAll(async () => {
71
+ await runtime.dispose();
72
+ });
73
+
74
+ it("ping responds", async () => {
75
+ const result = await client.ping();
76
+ expect(result.status).toBe("ok");
77
+ });
78
+
79
+ it("getById returns item", async () => {
80
+ const result = await client.getById({ id: "item-1" });
81
+ expect(result.item.id).toBe("item-1");
82
+ });
83
+
84
+ it("getById without auth throws UNAUTHORIZED", async () => {
85
+ await expect(client.getById({ id: "item-1" })).rejects.toThrow();
86
+ });
87
+ });
88
+ ```
89
+
90
+ ## Testing Plugin Composition
91
+
92
+ When testing an API plugin that uses `withPlugins`, mock the `pluginsClient`:
93
+
94
+ ```typescript
95
+ import { createPluginRuntime } from "every-plugin/runtime";
96
+
97
+ const mockRegistryClient = {
98
+ getRegistryStatus: vi.fn().mockResolvedValue({ status: "ok" }),
99
+ listRegistryApps: vi.fn().mockResolvedValue({ apps: [] }),
100
+ };
101
+
102
+ describe("API with mock registry", () => {
103
+ it("pluginDemo returns composed data", async () => {
104
+ const runtime = createPluginRuntime();
105
+ const result = await runtime.usePlugin(
106
+ "api",
107
+ { variables: {}, secrets: {} },
108
+ { registry: () => mockRegistryClient },
109
+ );
110
+ const client = result.createClient();
111
+ const data = await client.pluginDemo();
112
+ expect(data.registryStatus.status).toBe("ok");
113
+ await runtime.dispose();
114
+ });
115
+ });
116
+ ```
117
+
118
+ ## Testing Streaming (eventIterator)
119
+
120
+ Use `for await` to collect streaming results:
121
+
122
+ ```typescript
123
+ it("search streams results", async () => {
124
+ const chunks: any[] = [];
125
+ const stream = await client.search({ query: "test", limit: 5 });
126
+ for await (const chunk of stream) {
127
+ chunks.push(chunk);
128
+ }
129
+ expect(chunks.length).toBeGreaterThan(0);
130
+ });
131
+ ```
132
+
133
+ ## Vitest Config
134
+
135
+ ```typescript
136
+ import { defineConfig } from "vitest/config";
137
+ import tsconfigPaths from "vite-tsconfig-paths";
138
+
139
+ export default defineConfig({
140
+ plugins: [tsconfigPaths()],
141
+ test: {
142
+ include: ["src/__tests__/**/*.test.ts"],
143
+ },
144
+ });
145
+ ```
146
+
147
+ ## Common Mistakes
148
+
149
+ - Not calling `runtime.dispose()` in `afterAll` — leaves processes/resources running
150
+ - Using `vi.fn()` without `.mockResolvedValue()` — unhandled promise rejections
151
+ - Forgetting `vite-tsconfig-paths` plugin — path aliases like `every-plugin/orpc` won't resolve
152
+ - Testing only happy paths — always test error channels (Effect failures, ORPCError throws)
@@ -205,7 +205,7 @@ export class EveryPluginDevServer implements RspackPluginInstance {
205
205
  compiler.options.mode = process.env.NODE_ENV === "development" ? "development" : "production";
206
206
  }
207
207
 
208
- if (!compiler.options.devtool) {
208
+ if (compiler.options.devtool === undefined) {
209
209
  compiler.options.devtool = "source-map";
210
210
  }
211
211
 
@@ -54,6 +54,22 @@ export const pluginSharedDependencies = {
54
54
  version: getInstalledPackageVersion("zod", pkg.peerDependencies.zod),
55
55
  ...DEFAULT_SHARE_CONFIG,
56
56
  },
57
+ "better-auth": {
58
+ version: getInstalledPackageVersion("better-auth", "^1.6.9"),
59
+ ...DEFAULT_SHARE_CONFIG,
60
+ },
61
+ "drizzle-orm": {
62
+ version: getInstalledPackageVersion("drizzle-orm", "^0.45.1"),
63
+ ...DEFAULT_SHARE_CONFIG,
64
+ },
65
+ "@orpc/contract": {
66
+ version: getInstalledPackageVersion("@orpc/contract", pkg.peerDependencies["@orpc/contract"]),
67
+ ...DEFAULT_SHARE_CONFIG,
68
+ },
69
+ "@orpc/server": {
70
+ version: getInstalledPackageVersion("@orpc/server", pkg.peerDependencies["@orpc/server"]),
71
+ ...DEFAULT_SHARE_CONFIG,
72
+ },
57
73
  } satisfies SharedDependencies;
58
74
 
59
75
  export type PluginSharedDependencyName = keyof typeof pluginSharedDependencies;
@@ -43,6 +43,22 @@ export const MF_SHARED_DEPS = {
43
43
  version: getInstalledPackageVersion("zod", "^4.3.6"),
44
44
  shareConfig: SHARE_CONFIG,
45
45
  },
46
+ "better-auth": {
47
+ version: getInstalledPackageVersion("better-auth", "^1.6.9"),
48
+ shareConfig: SHARE_CONFIG,
49
+ },
50
+ "drizzle-orm": {
51
+ version: getInstalledPackageVersion("drizzle-orm", "^0.45.1"),
52
+ shareConfig: SHARE_CONFIG,
53
+ },
54
+ "@orpc/contract": {
55
+ version: getInstalledPackageVersion("@orpc/contract", "^1.13.4"),
56
+ shareConfig: SHARE_CONFIG,
57
+ },
58
+ "@orpc/server": {
59
+ version: getInstalledPackageVersion("@orpc/server", "^1.13.4"),
60
+ shareConfig: SHARE_CONFIG,
61
+ },
46
62
  } as const;
47
63
 
48
64
  export type SharedDepName = keyof typeof MF_SHARED_DEPS;