every-plugin 0.1.6 → 0.2.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 (36) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/plugin.d.ts +5 -12
  5. package/dist/plugin.d.ts.map +1 -1
  6. package/dist/plugin.js +0 -1
  7. package/dist/runtime/index.d.ts +21 -35
  8. package/dist/runtime/index.d.ts.map +1 -1
  9. package/dist/runtime/index.js +57 -69
  10. package/dist/runtime/services/module-federation.service.d.ts +7 -11
  11. package/dist/runtime/services/module-federation.service.d.ts.map +1 -1
  12. package/dist/runtime/services/module-federation.service.js +7 -9
  13. package/dist/runtime/services/plugin-lifecycle.service.d.ts +9 -12
  14. package/dist/runtime/services/plugin-lifecycle.service.d.ts.map +1 -1
  15. package/dist/runtime/services/plugin-lifecycle.service.js +5 -6
  16. package/dist/runtime/services/plugin-loader.service.d.ts +34 -13
  17. package/dist/runtime/services/plugin-loader.service.d.ts.map +1 -1
  18. package/dist/runtime/services/plugin-loader.service.js +34 -27
  19. package/dist/runtime/services/plugin.service.d.ts +29 -17
  20. package/dist/runtime/services/plugin.service.d.ts.map +1 -1
  21. package/dist/runtime/services/plugin.service.js +13 -7
  22. package/dist/runtime/services/secrets.service.d.ts +8 -9
  23. package/dist/runtime/services/secrets.service.d.ts.map +1 -1
  24. package/dist/runtime/services/secrets.service.js +28 -27
  25. package/dist/runtime/services.d.ts +3 -1
  26. package/dist/runtime/services.d.ts.map +1 -1
  27. package/dist/runtime/services.js +3 -1
  28. package/dist/testing/index.d.ts +45 -12
  29. package/dist/testing/index.d.ts.map +1 -1
  30. package/dist/testing/index.js +34 -27
  31. package/dist/testing/mocks/module-federation.service.d.ts +3 -5
  32. package/dist/testing/mocks/module-federation.service.d.ts.map +1 -1
  33. package/dist/testing/mocks/module-federation.service.js +18 -24
  34. package/dist/types.d.ts +40 -74
  35. package/dist/types.d.ts.map +1 -1
  36. package/package.json +4 -1
@@ -1,21 +1,33 @@
1
- import { Context, Effect, Layer, Scope } from "effect";
1
+ import { Context, Effect, Scope } from "effect";
2
2
  import { PluginRuntimeError, toPluginRuntimeError } from "../errors";
3
3
  import { validate } from "../validation";
4
4
  import { ModuleFederationService } from "./module-federation.service";
5
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* () {
6
+ export class PluginRegistryTag extends Context.Tag("PluginRegistry")() {
7
+ }
8
+ export class RegistryService extends Effect.Service()("RegistryService", {
9
+ effect: Effect.gen(function* () {
10
+ const registry = yield* PluginRegistryTag;
11
+ return {
12
+ get: (pluginId) => Effect.fromNullable(registry[pluginId]).pipe(Effect.mapError(() => new PluginRuntimeError({
13
+ pluginId,
14
+ operation: "load-plugin",
15
+ cause: new Error(`Plugin ${pluginId} not found in registry`),
16
+ retryable: false,
17
+ }))),
18
+ };
19
+ }),
20
+ }) {
21
+ }
22
+ export class PluginLoaderService extends Effect.Service()("PluginLoaderService", {
23
+ effect: Effect.gen(function* () {
8
24
  const moduleFederationService = yield* ModuleFederationService;
9
25
  const secretsService = yield* SecretsService;
26
+ const registryService = yield* RegistryService;
10
27
  const resolveUrl = (baseUrl, version) => version && version !== "latest"
11
28
  ? baseUrl.replace("@latest", `@${version}`)
12
29
  : 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
- })));
30
+ const getMetadata = (pluginId) => registryService.get(pluginId);
19
31
  return {
20
32
  loadPlugin: (pluginId) => Effect.gen(function* () {
21
33
  const metadata = yield* getMetadata(pluginId);
@@ -25,27 +37,23 @@ export class PluginLoaderService extends Context.Tag("PluginLoaderService")() {
25
37
  const ctor = yield* moduleFederationService.loadRemoteConstructor(pluginId, url).pipe(Effect.mapError((error) => toPluginRuntimeError(error.cause, pluginId, undefined, "load-remote", false)));
26
38
  return {
27
39
  ctor,
28
- metadata: {
29
- pluginId,
30
- version: metadata.version,
31
- type: metadata.type,
32
- },
40
+ metadata: metadata,
33
41
  };
34
42
  }),
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)));
43
+ instantiatePlugin: (pluginId, loadedPlugin) => Effect.gen(function* () {
44
+ const instance = yield* Effect.try(() => new loadedPlugin.ctor()).pipe(Effect.mapError((error) => toPluginRuntimeError(error, pluginId, undefined, "instantiate-plugin", false)));
37
45
  // Validate plugin ID matches
38
- if (instance.id !== pluginConstructor.metadata.pluginId) {
46
+ if (instance.id !== pluginId) {
39
47
  return yield* Effect.fail(new PluginRuntimeError({
40
- pluginId: pluginConstructor.metadata.pluginId,
48
+ pluginId,
41
49
  operation: "validate-plugin-id",
42
- cause: new Error(`Plugin ID mismatch: expected ${pluginConstructor.metadata.pluginId}, got ${instance.id}`),
50
+ cause: new Error(`Plugin ID mismatch: expected ${pluginId}, got ${instance.id}`),
43
51
  retryable: false,
44
52
  }));
45
53
  }
46
54
  return {
47
55
  plugin: instance,
48
- metadata: pluginConstructor.metadata,
56
+ metadata: loadedPlugin.metadata,
49
57
  };
50
58
  }),
51
59
  initializePlugin: (pluginInstance, config) => Effect.gen(function* () {
@@ -57,8 +65,8 @@ export class PluginLoaderService extends Context.Tag("PluginLoaderService")() {
57
65
  cause: validationError.zodError,
58
66
  retryable: false,
59
67
  })));
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({
68
+ const hydratedConfig = yield* secretsService.hydrateSecrets(validatedConfig);
69
+ const _config = yield* validate(plugin.configSchema, hydratedConfig, plugin.id, "config").pipe(Effect.mapError((validationError) => new PluginRuntimeError({
62
70
  pluginId: plugin.id,
63
71
  operation: "validate-hydrated-config",
64
72
  cause: validationError.zodError,
@@ -67,17 +75,16 @@ export class PluginLoaderService extends Context.Tag("PluginLoaderService")() {
67
75
  // Create a long-lived scope for this plugin instance
68
76
  const scope = yield* Scope.make();
69
77
  // 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)));
78
+ const context = yield* plugin.initialize(_config).pipe(Effect.provideService(Scope.Scope, scope), Effect.mapError((error) => toPluginRuntimeError(error, plugin.id, undefined, "initialize-plugin", false)));
71
79
  return {
72
80
  plugin,
73
81
  metadata: pluginInstance.metadata,
74
- config: finalConfig,
82
+ config: _config,
75
83
  context,
76
84
  scope,
77
85
  };
78
86
  }),
79
87
  };
80
- }));
88
+ }),
89
+ }) {
81
90
  }
82
- export const PluginLoaderServiceTag = PluginLoaderService;
83
- export const PluginLoaderServiceLive = PluginLoaderService.Live;
@@ -1,21 +1,33 @@
1
- import { Context, Effect, Layer } from "effect";
2
- import type { AnyPlugin, InitializedPlugin, PluginConstructor, PluginInstance, PluginRegistry, SecretsConfig } from "../../types";
3
- import type { PluginRuntimeError } from "../errors";
4
- export interface IPluginService {
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>;
11
- readonly shutdownPlugin: (plugin: InitializedPlugin<AnyPlugin>) => Effect.Effect<void, PluginRuntimeError>;
12
- readonly cleanup: () => Effect.Effect<void, never>;
13
- }
14
- declare const PluginService_base: Context.TagClass<PluginService, "PluginService", IPluginService>;
1
+ import { Effect, Layer, Scope } from "effect";
2
+ import type { AnyPlugin, InitializedPlugin, PluginRegistry, SecretsConfig } from "../../types";
3
+ import { PluginLifecycleService } from "./plugin-lifecycle.service";
4
+ import { PluginLoaderService } from "./plugin-loader.service";
5
+ declare const PluginService_base: Effect.Service.Class<PluginService, "PluginService", {
6
+ readonly scoped: Effect.Effect<{
7
+ loadPlugin: (pluginId: string) => Effect.Effect<{
8
+ ctor: new () => AnyPlugin;
9
+ metadata: import("../../types").PluginMetadata;
10
+ }, import("../errors").PluginRuntimeError, never>;
11
+ instantiatePlugin: <T extends AnyPlugin>(pluginId: string, loadedPlugin: import("../..").LoadedPlugin<T>) => Effect.Effect<{
12
+ plugin: T;
13
+ metadata: import("../../types").PluginMetadata;
14
+ }, import("../errors").PluginRuntimeError, never>;
15
+ initializePlugin: <T extends AnyPlugin>(pluginInstance: import("../..").PluginInstance<T>, config: {
16
+ variables: unknown;
17
+ secrets: unknown;
18
+ }) => Effect.Effect<{
19
+ plugin: T;
20
+ metadata: import("../../types").PluginMetadata;
21
+ config: import("zod").infer<T["configSchema"]>;
22
+ context: any;
23
+ scope: Scope.CloseableScope;
24
+ }, import("../errors").PluginRuntimeError, never>;
25
+ shutdownPlugin: (plugin: InitializedPlugin<AnyPlugin>) => Effect.Effect<void, never, never>;
26
+ cleanup: () => Effect.Effect<void, never, never>;
27
+ }, never, PluginLoaderService | PluginLifecycleService>;
28
+ }>;
15
29
  export declare class PluginService extends PluginService_base {
16
- static Live: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, import("./module-federation.service").ModuleFederationService | import("./secrets.service").SecretsService>;
30
+ static Live: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, never>;
17
31
  }
18
- export declare const PluginServiceTag: typeof PluginService;
19
- export declare const PluginServiceLive: (registry: PluginRegistry, secrets: SecretsConfig) => Layer.Layer<PluginService, never, import("./module-federation.service").ModuleFederationService | import("./secrets.service").SecretsService>;
20
32
  export {};
21
33
  //# 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":"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"}
1
+ {"version":3,"file":"plugin.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/plugin.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EACX,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAsC,MAAM,yBAAyB,CAAC;;;;;;;;;;;;;;;;;;;;;iCAYtE,iBAAiB,CAAC,SAAS,CAAC;;;;AATxD,qBAAa,aAAc,SAAQ,kBAyBjC;IACD,MAAM,CAAC,IAAI,GAAI,UAAU,cAAc,EAAE,SAAS,aAAa,8CAmB9D;CACD"}
@@ -1,8 +1,10 @@
1
- import { Context, Effect, Exit, Layer, Scope } from "effect";
1
+ import { Effect, Exit, Layer, Scope } from "effect";
2
+ import { ModuleFederationService } from "./module-federation.service";
2
3
  import { PluginLifecycleService } from "./plugin-lifecycle.service";
3
- import { PluginLoaderService } from "./plugin-loader.service";
4
- export class PluginService extends Context.Tag("PluginService")() {
5
- static Live = (registry, secrets) => Layer.scoped(PluginService, Effect.gen(function* () {
4
+ import { PluginLoaderService, PluginRegistryTag, RegistryService } from "./plugin-loader.service";
5
+ import { SecretsConfigTag, SecretsService } from "./secrets.service";
6
+ export class PluginService extends Effect.Service()("PluginService", {
7
+ scoped: Effect.gen(function* () {
6
8
  const loader = yield* PluginLoaderService;
7
9
  const lifecycle = yield* PluginLifecycleService;
8
10
  return {
@@ -19,7 +21,11 @@ export class PluginService extends Context.Tag("PluginService")() {
19
21
  }),
20
22
  cleanup: lifecycle.cleanup,
21
23
  };
22
- })).pipe(Layer.provide(Layer.mergeAll(PluginLoaderService.Live(registry, secrets), PluginLifecycleService.Live)));
24
+ }),
25
+ }) {
26
+ static Live = (registry, secrets) => {
27
+ const contextLayer = Layer.mergeAll(Layer.succeed(PluginRegistryTag, registry), Layer.succeed(SecretsConfigTag, secrets));
28
+ const servicesLayer = Layer.mergeAll(ModuleFederationService.Default, SecretsService.Default, RegistryService.Default, PluginLifecycleService.Default).pipe(Layer.provide(contextLayer));
29
+ return PluginService.Default.pipe(Layer.provide(PluginLoaderService.Default), Layer.provide(servicesLayer));
30
+ };
23
31
  }
24
- export const PluginServiceTag = PluginService;
25
- export const PluginServiceLive = PluginService.Live;
@@ -1,16 +1,15 @@
1
- import { Effect, Layer } from "effect";
1
+ import { Context, Effect } from "effect";
2
2
  import type { SecretsConfig } from "../../types";
3
3
  import { PluginRuntimeError } from "../errors";
4
- export interface ISecretsService {
5
- readonly hydrateSecrets: <T>(config: T, secretsConfig: SecretsConfig) => Effect.Effect<T, PluginRuntimeError>;
4
+ declare const SecretsConfigTag_base: Context.TagClass<SecretsConfigTag, "SecretsConfig", SecretsConfig>;
5
+ export declare class SecretsConfigTag extends SecretsConfigTag_base {
6
6
  }
7
- declare const SecretsService_base: import("effect/Context").TagClass<SecretsService, "SecretsService", ISecretsService> & Effect.Tag.Proxy<SecretsService, ISecretsService> & {
8
- use: <X>(body: (_: ISecretsService) => X) => [X] extends [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, R | SecretsService> : [X] extends [PromiseLike<infer A_1>] ? Effect.Effect<A_1, import("effect/Cause").UnknownException, SecretsService> : Effect.Effect<X, never, SecretsService>;
9
- };
7
+ declare const SecretsService_base: Effect.Service.Class<SecretsService, "SecretsService", {
8
+ readonly effect: Effect.Effect<{
9
+ hydrateSecrets: <T>(config: T) => Effect.Effect<T, PluginRuntimeError, never>;
10
+ }, never, SecretsConfigTag>;
11
+ }>;
10
12
  export declare class SecretsService extends SecretsService_base {
11
- static Live: (secrets: SecretsConfig) => Layer.Layer<SecretsService, never, never>;
12
13
  }
13
- export declare const SecretsServiceTag: typeof SecretsService;
14
- export declare const SecretsServiceLive: (secrets: SecretsConfig) => Layer.Layer<SecretsService, never, never>;
15
14
  export {};
16
15
  //# sourceMappingURL=secrets.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"secrets.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/secrets.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,EAC1B,MAAM,EAAE,CAAC,EACT,aAAa,EAAE,aAAa,KACxB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;CAC1C;;;;AAMD,qBAAa,cAAe,SAAQ,mBAGjC;IACF,MAAM,CAAC,IAAI,GAAI,SAAS,aAAa,+CA8BjC;CACJ;AAED,eAAO,MAAM,iBAAiB,uBAAiB,CAAC;AAChD,eAAO,MAAM,kBAAkB,YAlCN,aAAa,8CAkCe,CAAC"}
1
+ {"version":3,"file":"secrets.service.d.ts","sourceRoot":"","sources":["../../../src/runtime/services/secrets.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;;AAM/C,qBAAa,gBAAiB,SAAQ,qBAGnC;CAAI;;;yBAOa,CAAC,UAAU,CAAC;;;AALhC,qBAAa,cAAe,SAAQ,mBA+BlC;CAAI"}
@@ -1,34 +1,35 @@
1
- import { Effect, Layer } from "effect";
1
+ import { Context, Effect } from "effect";
2
2
  import { z } from "zod";
3
3
  import { PluginRuntimeError } from "../errors";
4
4
  const configSchema = z.object({
5
5
  secrets: z.record(z.string(), z.unknown())
6
6
  }).loose();
7
- export class SecretsService extends Effect.Tag("SecretsService")() {
8
- static Live = (secrets) => Layer.succeed(SecretsService, {
9
- hydrateSecrets: (config, secretsConfig) => Effect.gen(function* () {
10
- const parseResult = configSchema.parse(config);
11
- try {
12
- const configString = JSON.stringify(parseResult);
13
- let hydratedString = configString;
14
- // Use provided secrets or fallback to secretsConfig
15
- const effectiveSecrets = { ...secretsConfig, ...secrets };
16
- // Simple template replacement for {{SECRET_NAME}} patterns
17
- for (const [key, value] of Object.entries(effectiveSecrets)) {
18
- const pattern = new RegExp(`{{${key}}}`, "g");
19
- hydratedString = hydratedString.replace(pattern, String(value));
7
+ export class SecretsConfigTag extends Context.Tag("SecretsConfig")() {
8
+ }
9
+ export class SecretsService extends Effect.Service()("SecretsService", {
10
+ effect: Effect.gen(function* () {
11
+ const secrets = yield* SecretsConfigTag;
12
+ return {
13
+ hydrateSecrets: (config) => Effect.gen(function* () {
14
+ const parseResult = configSchema.parse(config);
15
+ try {
16
+ const configString = JSON.stringify(parseResult);
17
+ let hydratedString = configString;
18
+ for (const [key, value] of Object.entries(secrets)) {
19
+ const pattern = new RegExp(`{{${key}}}`, "g");
20
+ hydratedString = hydratedString.replace(pattern, String(value));
21
+ }
22
+ return JSON.parse(hydratedString);
23
+ }
24
+ catch (error) {
25
+ return yield* Effect.fail(new PluginRuntimeError({
26
+ operation: "hydrate-secrets",
27
+ cause: error instanceof Error ? error : new Error(String(error)),
28
+ retryable: false,
29
+ }));
20
30
  }
21
- return JSON.parse(hydratedString);
22
- }
23
- catch (error) {
24
- return yield* Effect.fail(new PluginRuntimeError({
25
- operation: "hydrate-secrets",
26
- cause: error instanceof Error ? error : new Error(String(error)),
27
- retryable: false,
28
- }));
29
- }
30
- }),
31
- });
31
+ }),
32
+ };
33
+ }),
34
+ }) {
32
35
  }
33
- export const SecretsServiceTag = SecretsService;
34
- export const SecretsServiceLive = SecretsService.Live;
@@ -1,4 +1,6 @@
1
+ export * from "./services/module-federation.service";
1
2
  export * from "./services/plugin.service";
3
+ export * from "./services/plugin-lifecycle.service";
4
+ export * from "./services/plugin-loader.service";
2
5
  export * from "./services/secrets.service";
3
- export * from "./services/module-federation.service";
4
6
  //# sourceMappingURL=services.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/runtime/services.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sCAAsC,CAAA"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/runtime/services.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAA;AACpD,cAAc,2BAA2B,CAAA;AACzC,cAAc,qCAAqC,CAAA;AACnD,cAAc,kCAAkC,CAAA;AAChD,cAAc,4BAA4B,CAAA"}
@@ -1,3 +1,5 @@
1
+ export * from "./services/module-federation.service";
1
2
  export * from "./services/plugin.service";
3
+ export * from "./services/plugin-lifecycle.service";
4
+ export * from "./services/plugin-loader.service";
2
5
  export * from "./services/secrets.service";
3
- export * from "./services/module-federation.service";
@@ -1,20 +1,53 @@
1
- import { Effect, Layer, ManagedRuntime } from "effect";
2
- import { PluginRuntimeImpl, PluginRuntimeService } from "../runtime";
1
+ import { Layer } from "effect";
2
+ import type { PluginBinding } from "../plugin";
3
+ import { PluginRuntime } from "../runtime";
4
+ import { PluginService } from "../runtime/services";
3
5
  import type { PluginRuntimeConfig, RegistryBindings } from "../types";
4
- import { type TestPluginMap } from "./mocks/module-federation.service";
6
+ import { type PluginMap } from "./mocks/module-federation.service";
7
+ /**
8
+ * Automatically infer RegistryBindings from a map of locally available plugins.
9
+ * Eliminates the need for manual binding definitions when using createLocalPluginRuntime.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const pluginMap = { "my-plugin": MyPlugin } as const;
14
+ * type MyBindings = InferBindingsFromMap<typeof pluginMap>;
15
+ * ```
16
+ */
17
+ export type InferBindingsFromMap<T extends PluginMap> = {
18
+ [K in keyof T]: PluginBinding<T[K]>;
19
+ } & RegistryBindings;
5
20
  /**
6
21
  * Creates a test layer with mock ModuleFederationService for unit testing.
7
- * This mirrors PluginRuntimeService.Live but uses mock ModuleFederationService.
22
+ * This mirrors PluginService.Live() but uses mock ModuleFederationService.
23
+ */
24
+ export declare const createTestLayer: <R extends RegistryBindings = RegistryBindings>(config: PluginRuntimeConfig<R>, pluginMap: PluginMap) => Layer.Layer<PluginService, never, never>;
25
+ /**
26
+ * Creates a plugin runtime for locally available plugins (non-remote).
27
+ * Automatically infers type bindings from the plugin map, eliminating
28
+ * the need for manual RegistryBindings definitions.
29
+ *
30
+ * Ideal for:
31
+ * - Unit and integration tests
32
+ * - Local development and debugging
33
+ * - Monorepo setups where all plugins are in the same workspace
34
+ *
35
+ * For production with remote Module Federation plugins, use createPluginRuntime().
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const pluginMap = { "my-plugin": MyPlugin } as const;
40
+ * const runtime = createLocalPluginRuntime({ registry, secrets }, pluginMap);
41
+ *
42
+ * // Types are automatically inferred - no manual bindings needed!
43
+ * const plugin = await runtime.usePlugin("my-plugin", config);
44
+ * ```
8
45
  */
9
- export declare const createTestLayer: <R extends RegistryBindings = RegistryBindings>(config: PluginRuntimeConfig<R>, pluginMap: TestPluginMap) => Layer.Layer<PluginRuntimeService, never, never>;
46
+ export declare function createLocalPluginRuntime<T extends PluginMap>(config: PluginRuntimeConfig, pluginMap: T): PluginRuntime<InferBindingsFromMap<T>>;
10
47
  /**
11
- * Creates a test plugin runtime using mock services.
12
- * This mirrors createPluginRuntime exactly but uses test layer.
48
+ * @deprecated Use `createLocalPluginRuntime` instead. This alias is kept for backward compatibility.
13
49
  */
14
- export declare const createTestPluginRuntime: <R extends RegistryBindings = RegistryBindings>(config: PluginRuntimeConfig<R>, pluginMap: TestPluginMap) => {
15
- runtime: ManagedRuntime.ManagedRuntime<PluginRuntimeService, never>;
16
- PluginRuntime: Effect.Effect<PluginRuntimeImpl<R>, never, never>;
17
- };
50
+ export declare const createTestPluginRuntime: typeof createLocalPluginRuntime;
18
51
  export type { PluginRegistry, RegistryBindings } from "../types";
19
- export type { PluginRuntimeConfig, TestPluginMap };
52
+ export type { PluginMap, PluginRuntimeConfig };
20
53
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAG/G;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAC3E,QAAQ,mBAAmB,CAAC,CAAC,CAAC,EAC9B,WAAW,aAAa,oDA+BzB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAI,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EACnF,QAAQ,mBAAmB,CAAC,CAAC,CAAC,EAC9B,WAAW,aAAa;;;CAezB,CAAC;AAGF,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAkB,MAAM,QAAQ,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAIN,aAAa,EAIb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAE3G;;;;;;;;;GASG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,SAAS,IAAI;KACtD,CAAC,IAAI,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,GAAG,gBAAgB,CAAC;AAErB;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,EAC5E,QAAQ,mBAAmB,CAAC,CAAC,CAAC,EAC9B,WAAW,SAAS,6CAwBpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,SAAS,EAC3D,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,CAAC,GACV,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAKxC;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,iCAA2B,CAAC;AAGhE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC"}
@@ -1,38 +1,45 @@
1
- import { Effect, Layer, ManagedRuntime } from "effect";
2
- import { PluginRuntimeImpl, PluginRuntimeService } from "../runtime";
3
- // Import the mock service factory and types
4
- import { PluginService, SecretsService } from "../runtime/services";
1
+ import { Layer, ManagedRuntime } from "effect";
2
+ import { PluginRuntime } from "../runtime";
3
+ import { PluginLifecycleService, PluginLoaderService, PluginRegistryTag, PluginService, RegistryService, SecretsConfigTag, SecretsService } from "../runtime/services";
5
4
  import { createMockModuleFederationServiceLayer } from "./mocks/module-federation.service";
6
5
  /**
7
6
  * Creates a test layer with mock ModuleFederationService for unit testing.
8
- * This mirrors PluginRuntimeService.Live but uses mock ModuleFederationService.
7
+ * This mirrors PluginService.Live() but uses mock ModuleFederationService.
9
8
  */
10
9
  export const createTestLayer = (config, pluginMap) => {
11
10
  const secrets = config.secrets || {};
12
- // Same structure as PluginRuntimeService.Live but with mock ModuleFederationService
13
- return Layer.scoped(PluginRuntimeService, Effect.gen(function* () {
14
- const pluginService = yield* PluginService;
15
- // Register cleanup finalizer for automatic resource management
16
- yield* Effect.addFinalizer(() => pluginService.cleanup().pipe(Effect.catchAll(() => Effect.void) // Ensure cleanup never fails
17
- ));
18
- return pluginService;
19
- })).pipe(Layer.provide(PluginService.Live(config.registry, secrets).pipe(Layer.provide(Layer.mergeAll(createMockModuleFederationServiceLayer(pluginMap), // Mock instead of real
20
- SecretsService.Live(secrets))))));
11
+ const contextLayer = Layer.mergeAll(Layer.succeed(PluginRegistryTag, config.registry), Layer.succeed(SecretsConfigTag, secrets));
12
+ const mockModuleFederationLayer = createMockModuleFederationServiceLayer(pluginMap);
13
+ const servicesLayer = Layer.mergeAll(mockModuleFederationLayer, SecretsService.Default, RegistryService.Default, PluginLifecycleService.Default).pipe(Layer.provide(contextLayer));
14
+ return PluginService.Default.pipe(Layer.provide(PluginLoaderService.Default), Layer.provide(servicesLayer));
21
15
  };
22
16
  /**
23
- * Creates a test plugin runtime using mock services.
24
- * This mirrors createPluginRuntime exactly but uses test layer.
17
+ * Creates a plugin runtime for locally available plugins (non-remote).
18
+ * Automatically infers type bindings from the plugin map, eliminating
19
+ * the need for manual RegistryBindings definitions.
20
+ *
21
+ * Ideal for:
22
+ * - Unit and integration tests
23
+ * - Local development and debugging
24
+ * - Monorepo setups where all plugins are in the same workspace
25
+ *
26
+ * For production with remote Module Federation plugins, use createPluginRuntime().
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const pluginMap = { "my-plugin": MyPlugin } as const;
31
+ * const runtime = createLocalPluginRuntime({ registry, secrets }, pluginMap);
32
+ *
33
+ * // Types are automatically inferred - no manual bindings needed!
34
+ * const plugin = await runtime.usePlugin("my-plugin", config);
35
+ * ```
25
36
  */
26
- export const createTestPluginRuntime = (config, pluginMap) => {
37
+ export function createLocalPluginRuntime(config, pluginMap) {
27
38
  const layer = createTestLayer(config, pluginMap);
28
39
  const runtime = ManagedRuntime.make(layer);
29
- // Same exact pattern as createPluginRuntime
30
- const createTypedRuntime = Effect.gen(function* () {
31
- const pluginService = yield* PluginRuntimeService;
32
- return new PluginRuntimeImpl(pluginService, config.registry);
33
- });
34
- return {
35
- runtime,
36
- PluginRuntime: createTypedRuntime.pipe(Effect.provide(runtime))
37
- };
38
- };
40
+ return new PluginRuntime(runtime, config.registry);
41
+ }
42
+ /**
43
+ * @deprecated Use `createLocalPluginRuntime` instead. This alias is kept for backward compatibility.
44
+ */
45
+ export const createTestPluginRuntime = createLocalPluginRuntime;
@@ -1,8 +1,6 @@
1
1
  import { Layer } from "effect";
2
+ import type { LoadedPluginWithBinding } from "../../plugin";
2
3
  import { ModuleFederationService } from "../../runtime/services/module-federation.service";
3
- import type { AnyPlugin } from "../../types";
4
- export interface TestPluginMap {
5
- [pluginId: string]: new () => AnyPlugin;
6
- }
7
- export declare const createMockModuleFederationServiceLayer: (pluginMap: TestPluginMap) => Layer.Layer<ModuleFederationService, never, never>;
4
+ export type PluginMap = Record<string, LoadedPluginWithBinding<any, any, any, any>>;
5
+ export declare const createMockModuleFederationServiceLayer: (pluginMap: PluginMap) => Layer.Layer<ModuleFederationService, never, never>;
8
6
  //# sourceMappingURL=module-federation.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module-federation.service.d.ts","sourceRoot":"","sources":["../../../src/testing/mocks/module-federation.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAGvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,SAAS,CAAC;CACzC;AA6CD,eAAO,MAAM,sCAAsC,GAAI,WAAW,aAAa,uDACT,CAAC"}
1
+ {"version":3,"file":"module-federation.service.d.ts","sourceRoot":"","sources":["../../../src/testing/mocks/module-federation.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAE3F,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAEpF,eAAO,MAAM,sCAAsC,GAAI,WAAW,SAAS,uDAoCxE,CAAC"}
@@ -1,35 +1,29 @@
1
1
  import { Effect, Layer } from "effect";
2
2
  import { ModuleFederationError } from "../../runtime/errors";
3
3
  import { ModuleFederationService } from "../../runtime/services/module-federation.service";
4
- // Create the mock service implementation
5
- const createMockService = (pluginMap) => ({
4
+ export const createMockModuleFederationServiceLayer = (pluginMap) => Layer.succeed(ModuleFederationService, {
6
5
  registerRemote: (pluginId, url) => Effect.gen(function* () {
7
- // Mock registration - succeeds if plugin is in the map
8
- // Use original pluginId as key since TestPluginMap uses original plugin IDs
9
- if (pluginId in pluginMap) {
10
- return;
6
+ console.log(`[MOCK] registerRemote called for ${pluginId}`);
7
+ if (!(pluginId in pluginMap)) {
8
+ return yield* Effect.fail(new ModuleFederationError({
9
+ pluginId,
10
+ remoteUrl: url,
11
+ cause: new Error(`Mock: Plugin ${pluginId} not available in test plugin map`),
12
+ }));
11
13
  }
12
- // Fail for plugins not in the map
13
- return yield* Effect.fail(new ModuleFederationError({
14
- pluginId,
15
- remoteUrl: url,
16
- cause: new Error(`Mock: Plugin ${pluginId} not available in test plugin map`),
17
- }));
14
+ console.log(`[MOCK] registerRemote succeeded for ${pluginId}`);
18
15
  }),
19
16
  loadRemoteConstructor: (pluginId, url) => Effect.gen(function* () {
20
- // Return the plugin constructor from the map
21
- // Use original pluginId as key since TestPluginMap uses original plugin IDs
17
+ console.log(`[MOCK] loadRemoteConstructor called for ${pluginId}`);
22
18
  const PluginConstructor = pluginMap[pluginId];
23
- if (PluginConstructor) {
24
- return PluginConstructor;
19
+ if (!PluginConstructor) {
20
+ return yield* Effect.fail(new ModuleFederationError({
21
+ pluginId,
22
+ remoteUrl: url,
23
+ cause: new Error(`Mock: Constructor for ${pluginId} not found in test plugin map`),
24
+ }));
25
25
  }
26
- // Fail for plugins not in the map
27
- return yield* Effect.fail(new ModuleFederationError({
28
- pluginId,
29
- remoteUrl: url,
30
- cause: new Error(`Mock: Constructor for ${pluginId} not found in test plugin map`),
31
- }));
26
+ console.log(`[MOCK] loadRemoteConstructor succeeded for ${pluginId}`);
27
+ return PluginConstructor;
32
28
  }),
33
29
  });
34
- // Create a Layer that provides the mock ModuleFederationService
35
- export const createMockModuleFederationServiceLayer = (pluginMap) => Layer.succeed(ModuleFederationService, createMockService(pluginMap));