every-plugin 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/client/index.d.ts +18 -0
  2. package/dist/client/index.d.ts.map +1 -0
  3. package/dist/client/index.js +33 -0
  4. package/dist/effect.d.ts +2 -0
  5. package/dist/effect.d.ts.map +1 -0
  6. package/dist/effect.js +1 -0
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +1 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -0
  12. package/dist/orpc.d.ts +3 -0
  13. package/dist/orpc.d.ts.map +1 -0
  14. package/dist/orpc.js +2 -0
  15. package/dist/plugin.d.ts +56 -85
  16. package/dist/plugin.d.ts.map +1 -1
  17. package/dist/plugin.js +33 -103
  18. package/dist/runtime/errors.d.ts +0 -14
  19. package/dist/runtime/errors.d.ts.map +1 -1
  20. package/dist/runtime/errors.js +0 -2
  21. package/dist/runtime/index.d.ts +40 -18
  22. package/dist/runtime/index.d.ts.map +1 -1
  23. package/dist/runtime/index.js +127 -24
  24. package/dist/runtime/services/module-federation.service.d.ts +2 -1
  25. package/dist/runtime/services/module-federation.service.d.ts.map +1 -1
  26. package/dist/runtime/services/module-federation.service.js +21 -23
  27. package/dist/runtime/services/normalize.d.ts +18 -0
  28. package/dist/runtime/services/normalize.d.ts.map +1 -0
  29. package/dist/runtime/services/normalize.js +17 -0
  30. package/dist/runtime/services/plugin-lifecycle.service.d.ts +17 -0
  31. package/dist/runtime/services/plugin-lifecycle.service.d.ts.map +1 -0
  32. package/dist/runtime/services/plugin-lifecycle.service.js +35 -0
  33. package/dist/runtime/services/plugin-loader.service.d.ts +21 -0
  34. package/dist/runtime/services/plugin-loader.service.d.ts.map +1 -0
  35. package/dist/runtime/services/plugin-loader.service.js +83 -0
  36. package/dist/runtime/services/plugin.service.d.ts +12 -20
  37. package/dist/runtime/services/plugin.service.d.ts.map +1 -1
  38. package/dist/runtime/services/plugin.service.js +18 -268
  39. package/dist/runtime/services/secrets.service.d.ts +2 -3
  40. package/dist/runtime/services/secrets.service.d.ts.map +1 -1
  41. package/dist/runtime/services/secrets.service.js +7 -5
  42. package/dist/runtime/services.d.ts +1 -1
  43. package/dist/runtime/services.d.ts.map +1 -1
  44. package/dist/runtime/services.js +1 -1
  45. package/dist/testing/index.d.ts +11 -16
  46. package/dist/testing/index.d.ts.map +1 -1
  47. package/dist/testing/index.js +25 -27
  48. package/dist/testing/mocks/module-federation.service.d.ts +1 -1
  49. package/dist/testing/mocks/module-federation.service.d.ts.map +1 -1
  50. package/dist/types.d.ts +177 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/zod.d.ts +2 -0
  53. package/dist/zod.d.ts.map +1 -0
  54. package/dist/zod.js +1 -0
  55. package/package.json +35 -10
  56. package/dist/runtime/streaming/index.d.ts +0 -4
  57. package/dist/runtime/streaming/index.d.ts.map +0 -1
  58. package/dist/runtime/streaming/index.js +0 -2
  59. package/dist/runtime/streaming/state-effects.d.ts +0 -28
  60. package/dist/runtime/streaming/state-effects.d.ts.map +0 -1
  61. package/dist/runtime/streaming/state-effects.js +0 -30
  62. package/dist/runtime/streaming/streaming.d.ts +0 -8
  63. package/dist/runtime/streaming/streaming.d.ts.map +0 -1
  64. package/dist/runtime/streaming/streaming.js +0 -113
  65. package/dist/runtime/streaming/types.d.ts +0 -19
  66. package/dist/runtime/streaming/types.d.ts.map +0 -1
  67. package/dist/runtime/test-utils.d.ts +0 -3
  68. package/dist/runtime/test-utils.d.ts.map +0 -1
  69. package/dist/runtime/test-utils.js +0 -7
  70. package/dist/runtime/types.d.ts +0 -40
  71. package/dist/runtime/types.d.ts.map +0 -1
  72. package/dist/runtime/types.js +0 -1
  73. /package/dist/{runtime/streaming/types.js → types.js} +0 -0
@@ -1,29 +1,132 @@
1
- import { Effect, Layer, ManagedRuntime } from "effect";
2
- import { PluginLoggerTag } from "../plugin";
3
- import { ModuleFederationService, PluginService, SecretsService, } from "./services";
4
- // Default logger implementation
5
- const createDefaultLogger = () => ({
6
- logInfo: (message, context) => Effect.logInfo(message).pipe(Effect.annotateLogs({ source: "plugin", context })),
7
- logWarning: (message, context) => Effect.logWarning(message).pipe(Effect.annotateLogs({ source: "plugin", context })),
8
- logError: (message, error, context) => Effect.logError(message, error).pipe(Effect.annotateLogs({ source: "plugin", error, context })),
9
- logDebug: (message, context) => Effect.logDebug(message).pipe(Effect.annotateLogs({ source: "plugin", context })),
10
- });
11
- export class PluginRuntime extends Effect.Tag("PluginRuntime")() {
1
+ import { Context, Effect, Hash, Layer, ManagedRuntime } from "effect";
2
+ import { createPluginClient, getPluginRouter } from "../client/index";
3
+ import { PluginRuntimeError } from "./errors";
4
+ import { SecretsService } from "./services";
5
+ import { ModuleFederationService } from "./services/module-federation.service";
6
+ import { PluginService } from "./services/plugin.service";
7
+ export class PluginRuntimeImpl {
8
+ pluginService;
9
+ registry;
10
+ pluginCache = new Map();
11
+ constructor(pluginService, registry) {
12
+ this.pluginService = pluginService;
13
+ this.registry = registry;
14
+ }
15
+ generateCacheKey(pluginId, config) {
16
+ const configHash = Hash.structure(config).toString();
17
+ return `${pluginId}:${configHash}`;
18
+ }
19
+ validatePluginId(pluginId) {
20
+ const pluginIdStr = pluginId;
21
+ // Runtime validation against registry
22
+ if (!(pluginIdStr in this.registry)) {
23
+ return Effect.fail(new PluginRuntimeError({
24
+ pluginId: pluginIdStr,
25
+ operation: "validate-plugin-id",
26
+ cause: new Error(`Plugin ID '${pluginIdStr}' not found in registry`),
27
+ retryable: false,
28
+ }));
29
+ }
30
+ return Effect.succeed(pluginIdStr);
31
+ }
32
+ loadPlugin(pluginId) {
33
+ const self = this;
34
+ return Effect.gen(function* () {
35
+ const validatedId = yield* self.validatePluginId(pluginId);
36
+ const result = yield* self.pluginService.loadPlugin(validatedId);
37
+ return result;
38
+ });
39
+ }
40
+ instantiatePlugin(ctor) {
41
+ const self = this;
42
+ return Effect.gen(function* () {
43
+ const result = yield* self.pluginService.instantiatePlugin(ctor);
44
+ return result;
45
+ });
46
+ }
47
+ initializePlugin(instance, config) {
48
+ const self = this;
49
+ return Effect.gen(function* () {
50
+ const result = yield* self.pluginService.initializePlugin(instance, config);
51
+ return result;
52
+ });
53
+ }
54
+ usePlugin(pluginId, config) {
55
+ const cacheKey = this.generateCacheKey(String(pluginId), config);
56
+ let cachedPlugin = this.pluginCache.get(cacheKey);
57
+ if (!cachedPlugin) {
58
+ const self = this;
59
+ const operation = Effect.gen(function* () {
60
+ const validatedId = yield* self.validatePluginId(pluginId);
61
+ // Load → Instantiate → Initialize
62
+ const ctor = yield* self.pluginService.loadPlugin(validatedId);
63
+ const instance = yield* self.pluginService.instantiatePlugin(ctor);
64
+ const initialized = yield* self.pluginService.initializePlugin(instance, config);
65
+ const client = createPluginClient(initialized);
66
+ const router = getPluginRouter(initialized);
67
+ return {
68
+ client,
69
+ router,
70
+ metadata: initialized.metadata,
71
+ initialized
72
+ };
73
+ });
74
+ cachedPlugin = Effect.cached(operation).pipe(Effect.flatten);
75
+ this.pluginCache.set(cacheKey, cachedPlugin);
76
+ }
77
+ return cachedPlugin;
78
+ }
79
+ shutdown() {
80
+ return this.pluginService.cleanup();
81
+ }
82
+ /**
83
+ * Evict a plugin from cache and shutdown its instance
84
+ */
85
+ evictPlugin(pluginId, config) {
86
+ const cacheKey = this.generateCacheKey(String(pluginId), config);
87
+ const self = this;
88
+ return Effect.gen(function* () {
89
+ // Get cached plugin if it exists
90
+ const cachedPlugin = self.pluginCache.get(cacheKey);
91
+ if (cachedPlugin) {
92
+ // Remove from cache first
93
+ self.pluginCache.delete(cacheKey);
94
+ // Try to shutdown the plugin gracefully
95
+ const pluginResult = yield* cachedPlugin.pipe(Effect.catchAll(() => Effect.succeed(null)));
96
+ if (pluginResult?.initialized) {
97
+ yield* self.pluginService.shutdownPlugin(pluginResult.initialized).pipe(Effect.catchAll(() => Effect.void) // Ignore shutdown errors during eviction
98
+ );
99
+ }
100
+ }
101
+ }).pipe(Effect.catchAll(() => Effect.void) // Never fail
102
+ );
103
+ }
104
+ }
105
+ export class PluginRuntimeService extends Context.Tag("PluginRuntimeService")() {
12
106
  static Live = (config) => {
13
107
  const secrets = config.secrets || {};
14
- const logger = config.logger || createDefaultLogger();
15
- return Layer.effect(PluginRuntime, Effect.gen(function* () {
108
+ return Layer.scoped(PluginRuntimeService, Effect.gen(function* () {
16
109
  const pluginService = yield* PluginService;
17
- return {
18
- loadPlugin: pluginService.loadPlugin,
19
- instantiatePlugin: pluginService.instantiatePlugin,
20
- initializePlugin: pluginService.initializePlugin,
21
- executePlugin: pluginService.executePlugin,
22
- usePlugin: (pluginId, config) => pluginService.usePlugin(pluginId, config),
23
- streamPlugin: (pluginId, config, input, options) => pluginService.streamPlugin(pluginId, config, input, options),
24
- shutdown: () => pluginService.cleanup(),
25
- };
26
- })).pipe(Layer.provide(PluginService.Live(config.registry, secrets).pipe(Layer.provide(Layer.mergeAll(ModuleFederationService.Live, SecretsService.Live(secrets), Layer.succeed(PluginLoggerTag, logger))))));
110
+ // Register cleanup finalizer for automatic resource management
111
+ yield* Effect.addFinalizer(() => pluginService.cleanup().pipe(Effect.catchAll(() => Effect.void) // Ensure cleanup never fails
112
+ ));
113
+ return pluginService;
114
+ })).pipe(Layer.provide(PluginService.Live(config.registry, secrets).pipe(Layer.provide(Layer.mergeAll(ModuleFederationService.Live, SecretsService.Live(secrets))))));
115
+ };
116
+ }
117
+ /**
118
+ * Creates a typed plugin runtime with compile-time registry key validation.
119
+ */
120
+ export function createPluginRuntime(config) {
121
+ const runtimeConfig = {
122
+ registry: config.registry,
123
+ secrets: config.secrets,
124
+ options: config.options
27
125
  };
126
+ const runtime = ManagedRuntime.make(PluginRuntimeService.Live(runtimeConfig));
127
+ const createTypedRuntime = Effect.gen(function* () {
128
+ const pluginService = yield* PluginRuntimeService;
129
+ return new PluginRuntimeImpl(pluginService, runtimeConfig.registry);
130
+ }).pipe(Effect.provide(runtime));
131
+ return { runtime, PluginRuntime: createTypedRuntime };
28
132
  }
29
- export const createPluginRuntime = (config) => ManagedRuntime.make(PluginRuntime.Live(config));
@@ -1,8 +1,9 @@
1
1
  import { Effect, Layer } from "effect";
2
+ import type { AnyPlugin } from "../../types";
2
3
  import { ModuleFederationError } from "../errors";
3
4
  export interface IModuleFederationService {
4
5
  readonly registerRemote: (pluginId: string, url: string) => Effect.Effect<void, ModuleFederationError>;
5
- readonly loadRemoteConstructor: (pluginId: string, url: string) => Effect.Effect<any, ModuleFederationError>;
6
+ readonly loadRemoteConstructor: (pluginId: string, url: string) => Effect.Effect<new () => AnyPlugin, ModuleFederationError>;
6
7
  }
7
8
  declare const ModuleFederationService_base: import("effect/Context").TagClass<ModuleFederationService, "ModuleFederationService", IModuleFederationService> & Effect.Tag.Proxy<ModuleFederationService, IModuleFederationService> & {
8
9
  use: <X>(body: (_: IModuleFederationService) => X) => [X] extends [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, ModuleFederationService | R> : [X] extends [PromiseLike<infer A_1>] ? Effect.Effect<A_1, import("effect/Cause").UnknownException, ModuleFederationService> : Effect.Effect<X, never, ModuleFederationService>;
@@ -1 +1 @@
1
- {"version":3,"file":"module-federation.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/module-federation.service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AASlD,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,cAAc,EAAE,CACxB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;IAChD,QAAQ,CAAC,qBAAqB,EAAE,CAC/B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;CAC/C;;;;AAiED,qBAAa,uBAAwB,SAAQ,4BAES;IACrD,MAAM,CAAC,IAAI,qDA4FT;CACF;AAED,eAAO,MAAM,0BAA0B,gCAA0B,CAAC;AAClE,eAAO,MAAM,2BAA2B,oDAA+B,CAAC"}
1
+ {"version":3,"file":"module-federation.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/module-federation.service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AASlD,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,cAAc,EAAE,CACxB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;IAChD,QAAQ,CAAC,qBAAqB,EAAE,CAC/B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,UAAU,SAAS,EAAE,qBAAqB,CAAC,CAAC;CAC/D;;;;AAsED,qBAAa,uBAAwB,SAAQ,4BAES;IACrD,MAAM,CAAC,IAAI,qDAyFT;CACF;AAED,eAAO,MAAM,0BAA0B,gCAA0B,CAAC;AAClE,eAAO,MAAM,2BAA2B,oDAA+B,CAAC"}
@@ -3,12 +3,8 @@ import { createInstance, getInstance, } from "@module-federation/enhanced/runtim
3
3
  import { setGlobalFederationInstance } from "@module-federation/runtime-core";
4
4
  import { Effect, Layer } from "effect";
5
5
  import { ModuleFederationError } from "../errors";
6
- const normalizePluginId = (pluginId) => {
7
- return pluginId
8
- .toLowerCase()
9
- .replace(/^@/, "")
10
- .replace(/\//g, "_");
11
- };
6
+ import { getNormalizedRemoteName } from "./normalize";
7
+ const pkg = require("../../../package.json");
12
8
  const createModuleFederationInstance = Effect.cached(Effect.sync(() => {
13
9
  try {
14
10
  let instance = getInstance();
@@ -18,43 +14,48 @@ const createModuleFederationInstance = Effect.cached(Effect.sync(() => {
18
14
  remotes: [],
19
15
  shared: {
20
16
  "every-plugin": {
17
+ version: pkg.version,
21
18
  shareConfig: {
22
19
  singleton: true,
23
- requiredVersion: false,
20
+ requiredVersion: `^${pkg.version}`,
24
21
  eager: true,
25
- strictVersion: false,
22
+ strictVersion: true,
26
23
  },
27
24
  },
28
25
  effect: {
26
+ version: pkg.dependencies.effect,
29
27
  shareConfig: {
30
28
  singleton: true,
31
- requiredVersion: false,
29
+ requiredVersion: "^3.17.0", // Allow any 3.17.x patch version
32
30
  eager: true,
33
- strictVersion: false,
31
+ strictVersion: true, // Enforce major/minor compatibility
34
32
  },
35
33
  },
36
34
  zod: {
35
+ version: pkg.dependencies.zod,
37
36
  shareConfig: {
38
37
  singleton: true,
39
- requiredVersion: false,
38
+ requiredVersion: "^4.1.0", // Allow any 4.1.x patch version
40
39
  eager: true,
41
- strictVersion: false,
40
+ strictVersion: true,
42
41
  },
43
42
  },
44
43
  "@orpc/contract": {
44
+ version: pkg.dependencies["@orpc/contract"],
45
45
  shareConfig: {
46
46
  singleton: true,
47
- requiredVersion: false,
47
+ requiredVersion: "^1.8.0", // Allow any 1.8.x patch version
48
48
  eager: true,
49
- strictVersion: false,
49
+ strictVersion: true,
50
50
  },
51
51
  },
52
52
  "@orpc/server": {
53
+ version: pkg.dependencies["@orpc/server"],
53
54
  shareConfig: {
54
55
  singleton: true,
55
- requiredVersion: false,
56
+ requiredVersion: "^1.8.0", // Allow any 1.8.x patch version
56
57
  eager: true,
57
- strictVersion: false,
58
+ strictVersion: true,
58
59
  },
59
60
  }
60
61
  },
@@ -90,11 +91,8 @@ export class ModuleFederationService extends Effect.Tag("ModuleFederationService
90
91
  cause: new Error(`Remote not available (${url}): ${JSON.stringify(error)}`),
91
92
  }));
92
93
  }
93
- // Register remote
94
- const remoteName = pluginId
95
- .toLowerCase()
96
- .replace(/^@/, "")
97
- .replace(/\//g, "_");
94
+ // Register remote using normalized name
95
+ const remoteName = getNormalizedRemoteName(pluginId);
98
96
  yield* Effect.try({
99
97
  try: () => mf.registerRemotes([{ name: remoteName, entry: url }]),
100
98
  catch: (error) => new ModuleFederationError({
@@ -106,7 +104,7 @@ export class ModuleFederationService extends Effect.Tag("ModuleFederationService
106
104
  console.log(`[MF] ✅ Registered ${pluginId}`);
107
105
  }),
108
106
  loadRemoteConstructor: (pluginId, url) => Effect.gen(function* () {
109
- const remoteName = normalizePluginId(pluginId);
107
+ const remoteName = getNormalizedRemoteName(pluginId);
110
108
  console.log(`[MF] Loading remote ${remoteName}`);
111
109
  const modulePath = `${remoteName}/plugin`;
112
110
  return yield* Effect.tryPromise({
@@ -117,7 +115,7 @@ export class ModuleFederationService extends Effect.Tag("ModuleFederationService
117
115
  }
118
116
  const Constructor = typeof container === "function"
119
117
  ? container
120
- : container?.default;
118
+ : container.default;
121
119
  if (!Constructor || typeof Constructor !== "function") {
122
120
  throw new Error(`No valid constructor found. Container type: ${typeof container}`);
123
121
  }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Normalizes a package name into the module federation remote name.
3
+ * This function must produce identical results in both runtime and build contexts.
4
+ *
5
+ * Normalization rules:
6
+ * - Convert to lowercase
7
+ * - Strip a single leading '@' symbol
8
+ * - Replace '/' with '_'
9
+ * - Preserve hyphens and other characters
10
+ *
11
+ * Examples:
12
+ * - "@scope/my-plugin" → "scope_my-plugin"
13
+ * - "@SCOPE/Foo/Bar" → "scope_foo_bar"
14
+ * - "foo/bar" → "foo_bar"
15
+ * - "simple-plugin" → "simple-plugin"
16
+ */
17
+ export declare const getNormalizedRemoteName: (name: string) => string;
18
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,KAAG,MACG,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Normalizes a package name into the module federation remote name.
3
+ * This function must produce identical results in both runtime and build contexts.
4
+ *
5
+ * Normalization rules:
6
+ * - Convert to lowercase
7
+ * - Strip a single leading '@' symbol
8
+ * - Replace '/' with '_'
9
+ * - Preserve hyphens and other characters
10
+ *
11
+ * Examples:
12
+ * - "@scope/my-plugin" → "scope_my-plugin"
13
+ * - "@SCOPE/Foo/Bar" → "scope_foo_bar"
14
+ * - "foo/bar" → "foo_bar"
15
+ * - "simple-plugin" → "simple-plugin"
16
+ */
17
+ export const getNormalizedRemoteName = (name) => name.toLowerCase().replace(/^@/, "").replace(/\//g, "_");
@@ -0,0 +1,17 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { AnyPlugin, InitializedPlugin } from "../../types";
3
+ import { type PluginRuntimeError } from "../errors";
4
+ export interface IPluginLifecycleService {
5
+ readonly register: <T extends AnyPlugin>(plugin: InitializedPlugin<T>) => Effect.Effect<void, never>;
6
+ readonly unregister: (plugin: InitializedPlugin<AnyPlugin>) => Effect.Effect<void, never>;
7
+ readonly shutdown: (plugin: InitializedPlugin<AnyPlugin>) => Effect.Effect<void, PluginRuntimeError>;
8
+ readonly cleanup: () => Effect.Effect<void, never>;
9
+ }
10
+ declare const PluginLifecycleService_base: Context.TagClass<PluginLifecycleService, "PluginLifecycleService", IPluginLifecycleService>;
11
+ export declare class PluginLifecycleService extends PluginLifecycleService_base {
12
+ static Live: Layer.Layer<PluginLifecycleService, never, never>;
13
+ }
14
+ export declare const PluginLifecycleServiceTag: typeof PluginLifecycleService;
15
+ export declare const PluginLifecycleServiceLive: Layer.Layer<PluginLifecycleService, never, never>;
16
+ export {};
17
+ //# sourceMappingURL=plugin-lifecycle.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-lifecycle.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/plugin-lifecycle.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAO,MAAM,QAAQ,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,KAAK,kBAAkB,EAAwB,MAAM,WAAW,CAAC;AAE1E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,SAAS,EACrC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KACzB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,CACnB,MAAM,EAAE,iBAAiB,CAAC,SAAS,CAAC,KACjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,CACjB,MAAM,EAAE,iBAAiB,CAAC,SAAS,CAAC,KACjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;CACpD;;AAED,qBAAa,sBAAuB,SAAQ,2BAGzC;IACD,MAAM,CAAC,IAAI,oDAiET;CACH;AAED,eAAO,MAAM,yBAAyB,+BAAyB,CAAC;AAChE,eAAO,MAAM,0BAA0B,mDAA8B,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { Context, Effect, Layer, Ref } from "effect";
2
+ import { toPluginRuntimeError } from "../errors";
3
+ export class PluginLifecycleService extends Context.Tag("PluginLifecycleService")() {
4
+ static Live = Layer.effect(PluginLifecycleService, Effect.gen(function* () {
5
+ const activePlugins = yield* Ref.make(new Set());
6
+ return {
7
+ register: (plugin) => Ref.update(activePlugins, plugins => new Set(plugins).add(plugin)),
8
+ unregister: (plugin) => Ref.update(activePlugins, plugins => {
9
+ const newSet = new Set(plugins);
10
+ newSet.delete(plugin);
11
+ return newSet;
12
+ }),
13
+ shutdown: (plugin) => Effect.gen(function* () {
14
+ // Remove from active plugins
15
+ yield* Ref.update(activePlugins, plugins => {
16
+ const newSet = new Set(plugins);
17
+ newSet.delete(plugin);
18
+ return newSet;
19
+ });
20
+ // Shutdown the plugin
21
+ yield* plugin.plugin.shutdown().pipe(Effect.mapError(error => toPluginRuntimeError(error, plugin.plugin.id, undefined, "shutdown-plugin", false)));
22
+ }),
23
+ cleanup: () => Effect.gen(function* () {
24
+ const plugins = yield* Ref.get(activePlugins);
25
+ // Shutdown all active plugins concurrently
26
+ yield* Effect.forEach(plugins, plugin => plugin.plugin.shutdown().pipe(Effect.mapError(error => toPluginRuntimeError(error, plugin.plugin.id, undefined, "cleanup-shutdown", false)), Effect.catchAll(error => Effect.logError(`Failed to shutdown plugin ${plugin.plugin.id} during cleanup`, error, { pluginId: plugin.plugin.id }))), { concurrency: "unbounded" });
27
+ // Clear the active plugins set
28
+ yield* Ref.set(activePlugins, new Set());
29
+ }).pipe(Effect.catchAll(() => Effect.void) // Convert errors to void for cleanup
30
+ ),
31
+ };
32
+ }));
33
+ }
34
+ export const PluginLifecycleServiceTag = PluginLifecycleService;
35
+ export const PluginLifecycleServiceLive = PluginLifecycleService.Live;
@@ -0,0 +1,21 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { AnyPlugin, InitializedPlugin, PluginConstructor, PluginInstance, PluginRegistry, SecretsConfig } from "../../types";
3
+ import { PluginRuntimeError } from "../errors";
4
+ import { ModuleFederationService } from "./module-federation.service";
5
+ import { SecretsService } from "./secrets.service";
6
+ export interface IPluginLoaderService {
7
+ readonly loadPlugin: (pluginId: string) => Effect.Effect<PluginConstructor<AnyPlugin>, PluginRuntimeError>;
8
+ readonly instantiatePlugin: <T extends AnyPlugin>(pluginConstructor: PluginConstructor<T>) => Effect.Effect<PluginInstance<T>, PluginRuntimeError>;
9
+ readonly initializePlugin: <T extends AnyPlugin>(pluginInstance: PluginInstance<T>, config: {
10
+ variables: unknown;
11
+ secrets: unknown;
12
+ }) => Effect.Effect<InitializedPlugin<T>, PluginRuntimeError>;
13
+ }
14
+ declare const PluginLoaderService_base: Context.TagClass<PluginLoaderService, "PluginLoaderService", IPluginLoaderService>;
15
+ export declare class PluginLoaderService extends PluginLoaderService_base {
16
+ static Live: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginLoaderService, never, ModuleFederationService | SecretsService>;
17
+ }
18
+ export declare const PluginLoaderServiceTag: typeof PluginLoaderService;
19
+ export declare const PluginLoaderServiceLive: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginLoaderService, never, ModuleFederationService | SecretsService>;
20
+ export {};
21
+ //# sourceMappingURL=plugin-loader.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-loader.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/plugin-loader.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAS,MAAM,QAAQ,CAAC;AAEvD,OAAO,KAAK,EACX,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,aAAa,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAwB,MAAM,WAAW,CAAC;AAErE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,UAAU,EAAE,CACpB,QAAQ,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACrE,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC,SAAS,SAAS,EAC/C,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,KACnC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;IAC1D,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,SAAS,SAAS,EAC9C,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC,EACjC,MAAM,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAC5C,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;CAC7D;;AAED,qBAAa,mBAAoB,SAAQ,wBAGtC;IACF,MAAM,CAAC,IAAI,GAAI,UAAU,cAAc,EAAE,SAAS,aAAa,uFA4J5D;CACH;AAED,eAAO,MAAM,sBAAsB,4BAAsB,CAAC;AAC1D,eAAO,MAAM,uBAAuB,aAhKV,cAAc,WAAW,aAAa,sFAgKD,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { Context, Effect, Layer, Scope } from "effect";
2
+ import { PluginRuntimeError, toPluginRuntimeError } from "../errors";
3
+ import { validate } from "../validation";
4
+ import { ModuleFederationService } from "./module-federation.service";
5
+ import { SecretsService } from "./secrets.service";
6
+ export class PluginLoaderService extends Context.Tag("PluginLoaderService")() {
7
+ static Live = (registry, secrets) => Layer.effect(PluginLoaderService, Effect.gen(function* () {
8
+ const moduleFederationService = yield* ModuleFederationService;
9
+ const secretsService = yield* SecretsService;
10
+ const resolveUrl = (baseUrl, version) => version && version !== "latest"
11
+ ? baseUrl.replace("@latest", `@${version}`)
12
+ : baseUrl;
13
+ const getMetadata = (pluginId) => Effect.fromNullable(registry[pluginId]).pipe(Effect.mapError(() => new PluginRuntimeError({
14
+ pluginId,
15
+ operation: "load-plugin",
16
+ cause: new Error(`Plugin ${pluginId} not found in registry`),
17
+ retryable: false,
18
+ })));
19
+ return {
20
+ loadPlugin: (pluginId) => Effect.gen(function* () {
21
+ const metadata = yield* getMetadata(pluginId);
22
+ const url = resolveUrl(metadata.remoteUrl);
23
+ yield* moduleFederationService.registerRemote(pluginId, url).pipe(Effect.mapError((error) => toPluginRuntimeError(error.cause, pluginId, undefined, "register-remote", true)));
24
+ yield* Effect.logDebug("Loading plugin", { pluginId, url });
25
+ const ctor = yield* moduleFederationService.loadRemoteConstructor(pluginId, url).pipe(Effect.mapError((error) => toPluginRuntimeError(error.cause, pluginId, undefined, "load-remote", false)));
26
+ return {
27
+ ctor,
28
+ metadata: {
29
+ pluginId,
30
+ version: metadata.version,
31
+ type: metadata.type,
32
+ },
33
+ };
34
+ }),
35
+ instantiatePlugin: (pluginConstructor) => Effect.gen(function* () {
36
+ const instance = yield* Effect.try(() => new pluginConstructor.ctor()).pipe(Effect.mapError((error) => toPluginRuntimeError(error, pluginConstructor.metadata.pluginId, undefined, "instantiate-plugin", false)));
37
+ // Validate plugin ID matches
38
+ if (instance.id !== pluginConstructor.metadata.pluginId) {
39
+ return yield* Effect.fail(new PluginRuntimeError({
40
+ pluginId: pluginConstructor.metadata.pluginId,
41
+ operation: "validate-plugin-id",
42
+ cause: new Error(`Plugin ID mismatch: expected ${pluginConstructor.metadata.pluginId}, got ${instance.id}`),
43
+ retryable: false,
44
+ }));
45
+ }
46
+ return {
47
+ plugin: instance,
48
+ metadata: pluginConstructor.metadata,
49
+ };
50
+ }),
51
+ initializePlugin: (pluginInstance, config) => Effect.gen(function* () {
52
+ const { plugin } = pluginInstance;
53
+ // Validate and hydrate config
54
+ const validatedConfig = yield* validate(plugin.configSchema, config, plugin.id, "config").pipe(Effect.mapError((validationError) => new PluginRuntimeError({
55
+ pluginId: plugin.id,
56
+ operation: "validate-config",
57
+ cause: validationError.zodError,
58
+ retryable: false,
59
+ })));
60
+ const hydratedConfig = yield* secretsService.hydrateSecrets(validatedConfig, secrets);
61
+ const finalConfig = yield* validate(plugin.configSchema, hydratedConfig, plugin.id, "config").pipe(Effect.mapError((validationError) => new PluginRuntimeError({
62
+ pluginId: plugin.id,
63
+ operation: "validate-hydrated-config",
64
+ cause: validationError.zodError,
65
+ retryable: false,
66
+ })));
67
+ // Create a long-lived scope for this plugin instance
68
+ const scope = yield* Scope.make();
69
+ // Initialize plugin within the scope
70
+ const context = yield* plugin.initialize(finalConfig).pipe(Effect.provideService(Scope.Scope, scope), Effect.mapError((error) => toPluginRuntimeError(error, plugin.id, undefined, "initialize-plugin", false)));
71
+ return {
72
+ plugin,
73
+ metadata: pluginInstance.metadata,
74
+ config: finalConfig,
75
+ context,
76
+ scope,
77
+ };
78
+ }),
79
+ };
80
+ }));
81
+ }
82
+ export const PluginLoaderServiceTag = PluginLoaderService;
83
+ export const PluginLoaderServiceLive = PluginLoaderService.Live;
@@ -1,29 +1,21 @@
1
- import { Effect, Layer, type Stream } from "effect";
2
- import type { z } from "zod";
3
- import { type Contract, type Plugin, PluginLoggerTag, type PluginRegistry } from "../../plugin";
4
- import { PluginRuntimeError } from "../errors";
5
- import { type StreamingOptions } from "../streaming";
6
- import type { AnyPlugin, InitializedPlugin, PluginConstructor, PluginInstance, SecretsConfig } from "../types";
7
- import { ModuleFederationService } from "./module-federation.service";
8
- import { SecretsService } from "./secrets.service";
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { AnyPlugin, InitializedPlugin, PluginConstructor, PluginInstance, PluginRegistry, SecretsConfig } from "../../types";
3
+ import type { PluginRuntimeError } from "../errors";
9
4
  export interface IPluginService {
10
- readonly loadPlugin: (pluginId: string) => Effect.Effect<PluginConstructor, PluginRuntimeError>;
11
- readonly instantiatePlugin: <T extends AnyPlugin>(pluginConstructor: PluginConstructor) => Effect.Effect<PluginInstance<T>, PluginRuntimeError>;
12
- readonly initializePlugin: <T extends AnyPlugin>(pluginInstance: PluginInstance<T>, config: unknown) => Effect.Effect<InitializedPlugin<T>, PluginRuntimeError>;
13
- readonly executePlugin: <T extends AnyPlugin>(initializedPlugin: InitializedPlugin<T>, input: z.infer<T["inputSchema"]>) => Effect.Effect<z.infer<T["outputSchema"]>, PluginRuntimeError>;
14
- readonly usePlugin: <T extends AnyPlugin>(pluginId: string, config: unknown) => Effect.Effect<InitializedPlugin<T>, PluginRuntimeError>;
15
- readonly streamPlugin: <T extends Plugin<Contract>, TInput extends z.infer<T["inputSchema"]> = z.infer<T["inputSchema"]>, TItem = unknown, TPluginState extends z.infer<T["stateSchema"]> = z.infer<T["stateSchema"]>>(pluginId: string, config: z.infer<T["configSchema"]>, input: TInput, options?: StreamingOptions<TItem, TPluginState>) => Effect.Effect<Stream.Stream<TItem, PluginRuntimeError>, PluginRuntimeError>;
5
+ readonly loadPlugin: (pluginId: string) => Effect.Effect<PluginConstructor<AnyPlugin>, PluginRuntimeError>;
6
+ readonly instantiatePlugin: <T extends AnyPlugin>(pluginConstructor: PluginConstructor<T>) => Effect.Effect<PluginInstance<T>, PluginRuntimeError>;
7
+ readonly initializePlugin: <T extends AnyPlugin>(pluginInstance: PluginInstance<T>, config: {
8
+ variables: unknown;
9
+ secrets: unknown;
10
+ }) => Effect.Effect<InitializedPlugin<T>, PluginRuntimeError>;
16
11
  readonly shutdownPlugin: (plugin: InitializedPlugin<AnyPlugin>) => Effect.Effect<void, PluginRuntimeError>;
17
- readonly clearCache: () => Effect.Effect<void, never>;
18
12
  readonly cleanup: () => Effect.Effect<void, never>;
19
13
  }
20
- declare const PluginService_base: import("effect/Context").TagClass<PluginService, "PluginService", IPluginService> & Effect.Tag.Proxy<PluginService, IPluginService> & {
21
- use: <X>(body: (_: IPluginService) => X) => [X] extends [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, R | PluginService> : [X] extends [PromiseLike<infer A_1>] ? Effect.Effect<A_1, import("effect/Cause").UnknownException, PluginService> : Effect.Effect<X, never, PluginService>;
22
- };
14
+ declare const PluginService_base: Context.TagClass<PluginService, "PluginService", IPluginService>;
23
15
  export declare class PluginService extends PluginService_base {
24
- static Live: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, PluginLoggerTag | ModuleFederationService | SecretsService>;
16
+ static Live: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, import("./module-federation.service").ModuleFederationService | import("./secrets.service").SecretsService>;
25
17
  }
26
18
  export declare const PluginServiceTag: typeof PluginService;
27
- export declare const PluginServiceLive: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, PluginLoggerTag | ModuleFederationService | SecretsService>;
19
+ export declare const PluginServiceLive: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, import("./module-federation.service").ModuleFederationService | import("./secrets.service").SecretsService>;
28
20
  export {};
29
21
  //# sourceMappingURL=plugin.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/plugin.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/plugin.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAQ,KAAK,EAAS,MAAM,QAAQ,CAAC;AAC7D,OAAO,KAAK,EACX,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,aAAa,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAIpD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,UAAU,EAAE,CACpB,QAAQ,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACrE,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC,SAAS,SAAS,EAC/C,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,KACnC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;IAC1D,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,SAAS,SAAS,EAC9C,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC,EACjC,MAAM,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAC5C,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;IAC7D,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC3G,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;CACnD;;AAED,qBAAa,aAAc,SAAQ,kBAGhC;IACF,MAAM,CAAC,IAAI,GAAI,UAAU,cAAc,EAAE,SAAS,aAAa,mJAkC5D;CACH;AAED,eAAO,MAAM,gBAAgB,sBAAgB,CAAC;AAC9C,eAAO,MAAM,iBAAiB,aAtCJ,cAAc,WAAW,aAAa,kJAsCb,CAAC"}