every-plugin 0.1.0 → 0.1.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 (63) hide show
  1. package/README.md +1 -329
  2. package/dist/errors.d.ts +4 -4
  3. package/dist/errors.js +10 -10
  4. package/dist/index.d.ts +2 -4
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -3
  7. package/dist/plugin.d.ts +89 -103
  8. package/dist/plugin.d.ts.map +1 -1
  9. package/dist/plugin.js +104 -23
  10. package/dist/runtime/errors.d.ts +36 -53
  11. package/dist/runtime/errors.js +8 -8
  12. package/dist/runtime/index.d.ts +17 -66
  13. package/dist/runtime/index.d.ts.map +1 -1
  14. package/dist/runtime/index.js +22 -126
  15. package/dist/runtime/services/module-federation.service.d.ts +10 -38
  16. package/dist/runtime/services/module-federation.service.d.ts.map +1 -1
  17. package/dist/runtime/services/module-federation.service.js +139 -124
  18. package/dist/runtime/services/plugin.service.d.ts +21 -67
  19. package/dist/runtime/services/plugin.service.d.ts.map +1 -1
  20. package/dist/runtime/services/plugin.service.js +263 -328
  21. package/dist/runtime/services/secrets.service.d.ts +9 -29
  22. package/dist/runtime/services/secrets.service.js +26 -30
  23. package/dist/runtime/services.d.ts +1 -1
  24. package/dist/runtime/streaming/index.d.ts +4 -0
  25. package/dist/runtime/streaming/index.d.ts.map +1 -0
  26. package/dist/runtime/streaming/index.js +2 -0
  27. package/dist/runtime/streaming/state-effects.d.ts +28 -0
  28. package/dist/runtime/streaming/state-effects.d.ts.map +1 -0
  29. package/dist/runtime/streaming/state-effects.js +30 -0
  30. package/dist/runtime/streaming/streaming.d.ts +8 -0
  31. package/dist/runtime/streaming/streaming.d.ts.map +1 -0
  32. package/dist/runtime/streaming/streaming.js +107 -0
  33. package/dist/runtime/streaming/types.d.ts +19 -0
  34. package/dist/runtime/streaming/types.d.ts.map +1 -0
  35. package/dist/runtime/streaming/types.js +1 -0
  36. package/dist/runtime/test-utils.d.ts +1 -1
  37. package/dist/runtime/test-utils.js +4 -10
  38. package/dist/runtime/types.d.ts +28 -28
  39. package/dist/runtime/types.d.ts.map +1 -1
  40. package/dist/runtime/validation.d.ts +2 -7
  41. package/dist/runtime/validation.js +11 -14
  42. package/dist/testing/index.d.ts +25 -0
  43. package/dist/testing/index.d.ts.map +1 -0
  44. package/dist/testing/index.js +40 -0
  45. package/dist/testing/mocks/module-federation.service.d.ts +8 -0
  46. package/dist/testing/mocks/module-federation.service.d.ts.map +1 -0
  47. package/dist/testing/mocks/module-federation.service.js +35 -0
  48. package/package.json +21 -4
  49. package/dist/runtime/mf.test.d.ts +0 -2
  50. package/dist/runtime/mf.test.d.ts.map +0 -1
  51. package/dist/runtime/mf.test.js +0 -135
  52. package/dist/runtime/runtime.test.d.ts +0 -2
  53. package/dist/runtime/runtime.test.d.ts.map +0 -1
  54. package/dist/runtime/runtime.test.js +0 -378
  55. package/dist/runtime/streaming.d.ts +0 -29
  56. package/dist/runtime/streaming.d.ts.map +0 -1
  57. package/dist/runtime/streaming.js +0 -59
  58. package/dist/runtime/streaming.test.d.ts +0 -2
  59. package/dist/runtime/streaming.test.d.ts.map +0 -1
  60. package/dist/runtime/streaming.test.js +0 -271
  61. package/dist/source.d.ts +0 -70
  62. package/dist/source.d.ts.map +0 -1
  63. package/dist/source.js +0 -37
@@ -2,36 +2,16 @@ import { Effect, Layer } from "effect";
2
2
  import { PluginRuntimeError } from "../errors";
3
3
  import type { SecretsConfig } from "../types";
4
4
  export interface ISecretsService {
5
- readonly hydrateSecrets: (
6
- config: any, // TODO:
7
- secretsConfig: SecretsConfig,
8
- ) => Effect.Effect<any, PluginRuntimeError>;
5
+ readonly hydrateSecrets: (config: any, // TODO:
6
+ secretsConfig: SecretsConfig) => Effect.Effect<any, PluginRuntimeError>;
9
7
  }
10
- declare const SecretsService_base: import("effect/Context").TagClass<
11
- SecretsService,
12
- "SecretsService",
13
- ISecretsService
14
- > &
15
- Effect.Tag.Proxy<SecretsService, ISecretsService> & {
16
- use: <X>(
17
- body: (_: ISecretsService) => X,
18
- ) => [X] extends [Effect.Effect<infer A, infer E, infer R>]
19
- ? Effect.Effect<A, E, R | SecretsService>
20
- : [X] extends [PromiseLike<infer A_1>]
21
- ? Effect.Effect<
22
- A_1,
23
- import("effect/Cause").UnknownException,
24
- SecretsService
25
- >
26
- : Effect.Effect<X, never, SecretsService>;
27
- };
8
+ declare const SecretsService_base: import("effect/Context").TagClass<SecretsService, "SecretsService", ISecretsService> & Effect.Tag.Proxy<SecretsService, ISecretsService> & {
9
+ 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>;
10
+ };
28
11
  export declare class SecretsService extends SecretsService_base {
29
- static Live: (
30
- secrets: SecretsConfig,
31
- ) => Layer.Layer<SecretsService, never, never>;
12
+ static Live: (secrets: SecretsConfig) => Layer.Layer<SecretsService, never, never>;
32
13
  }
33
14
  export declare const SecretsServiceTag: typeof SecretsService;
34
- export declare const SecretsServiceLive: (
35
- secrets: SecretsConfig,
36
- ) => Layer.Layer<SecretsService, never, never>;
37
- //# sourceMappingURL=secrets.service.d.ts.map
15
+ export declare const SecretsServiceLive: (secrets: SecretsConfig) => Layer.Layer<SecretsService, never, never>;
16
+ export {};
17
+ //# sourceMappingURL=secrets.service.d.ts.map
@@ -1,36 +1,32 @@
1
1
  import { Effect, Layer } from "effect";
2
2
  import { PluginRuntimeError } from "../errors";
3
3
  export class SecretsService extends Effect.Tag("SecretsService")() {
4
- static Live = (secrets) =>
5
- Layer.succeed(SecretsService, {
6
- hydrateSecrets: (config, secretsConfig) =>
7
- Effect.gen(function* () {
8
- if (!config || typeof config !== "object" || !config.secrets) {
9
- return config;
10
- }
11
- try {
12
- const configString = JSON.stringify(config);
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, value);
20
- }
21
- return JSON.parse(hydratedString);
22
- } catch (error) {
23
- return yield* Effect.fail(
24
- new PluginRuntimeError({
25
- operation: "hydrate-secrets",
26
- cause:
27
- error instanceof Error ? error : new Error(String(error)),
28
- retryable: false,
29
- }),
30
- );
31
- }
32
- }),
33
- });
4
+ static Live = (secrets) => Layer.succeed(SecretsService, {
5
+ hydrateSecrets: (config, secretsConfig) => Effect.gen(function* () {
6
+ if (!config || typeof config !== "object" || !config.secrets) {
7
+ return config;
8
+ }
9
+ try {
10
+ const configString = JSON.stringify(config);
11
+ let hydratedString = configString;
12
+ // Use provided secrets or fallback to secretsConfig
13
+ const effectiveSecrets = { ...secretsConfig, ...secrets };
14
+ // Simple template replacement for {{SECRET_NAME}} patterns
15
+ for (const [key, value] of Object.entries(effectiveSecrets)) {
16
+ const pattern = new RegExp(`{{${key}}}`, "g");
17
+ hydratedString = hydratedString.replace(pattern, value);
18
+ }
19
+ return JSON.parse(hydratedString);
20
+ }
21
+ catch (error) {
22
+ return yield* Effect.fail(new PluginRuntimeError({
23
+ operation: "hydrate-secrets",
24
+ cause: error instanceof Error ? error : new Error(String(error)),
25
+ retryable: false,
26
+ }));
27
+ }
28
+ }),
29
+ });
34
30
  }
35
31
  export const SecretsServiceTag = SecretsService;
36
32
  export const SecretsServiceLive = SecretsService.Live;
@@ -1,4 +1,4 @@
1
1
  export * from "./services/module-federation.service";
2
2
  export * from "./services/plugin.service";
3
3
  export * from "./services/secrets.service";
4
- //# sourceMappingURL=services.d.ts.map
4
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +1,4 @@
1
+ export { pipe, StateTransitions } from './state-effects';
2
+ export { createSourceStream } from './streaming';
3
+ export type { StreamingOptions, StreamState } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/streaming/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { pipe, StateTransitions } from './state-effects';
2
+ export { createSourceStream } from './streaming';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * State transition helpers for common patterns
3
+ */
4
+ export declare const StateTransitions: {
5
+ /**
6
+ * Transition to a new phase with optional updates
7
+ */
8
+ to: <T extends {
9
+ phase?: string;
10
+ }>(phase: string, updates?: Partial<T>) => (state: T) => T;
11
+ /**
12
+ * Add polling delay to state
13
+ */
14
+ withPolling: <T>(delayMs: number) => (state: T) => T;
15
+ /**
16
+ * Set error state with message and stop polling
17
+ */
18
+ withError: <T>(errorMessage: string) => (state: T) => T;
19
+ /**
20
+ * Preserve existing state with updates
21
+ */
22
+ update: <T>(updates: Partial<T>) => (state: T) => T;
23
+ };
24
+ /**
25
+ * Simple pipe utility for composing state transformations
26
+ */
27
+ export declare const pipe: <T>(value: T, ...fns: Array<(val: T) => T>) => T;
28
+ //# sourceMappingURL=state-effects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-effects.d.ts","sourceRoot":"","sources":["../../../src/runtime/streaming/state-effects.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;OAEG;SACE,CAAC,SAAS;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,SAAS,MAAM,YAAW,OAAO,CAAC,CAAC,CAAC,MAClE,OAAO,CAAC,KAAG,CAAC;IAEf;;OAEG;kBACW,CAAC,WAAW,MAAM,MAC7B,OAAO,CAAC,KAAG,CAAC;IAEf;;OAEG;gBACS,CAAC,gBAAgB,MAAM,MAChC,OAAO,CAAC,KAAG,CAAC;IAOf;;OAEG;aACM,CAAC,WAAW,OAAO,CAAC,CAAC,CAAC,MAC5B,OAAO,CAAC,KAAG,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAG,CACxB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * State transition helpers for common patterns
3
+ */
4
+ export const StateTransitions = {
5
+ /**
6
+ * Transition to a new phase with optional updates
7
+ */
8
+ to: (phase, updates = {}) => (state) => ({ ...state, phase, ...updates }),
9
+ /**
10
+ * Add polling delay to state
11
+ */
12
+ withPolling: (delayMs) => (state) => ({ ...state, nextPollMs: delayMs }),
13
+ /**
14
+ * Set error state with message and stop polling
15
+ */
16
+ withError: (errorMessage) => (state) => ({
17
+ ...state,
18
+ phase: 'error',
19
+ errorMessage,
20
+ nextPollMs: null
21
+ }),
22
+ /**
23
+ * Preserve existing state with updates
24
+ */
25
+ update: (updates) => (state) => ({ ...state, ...updates }),
26
+ };
27
+ /**
28
+ * Simple pipe utility for composing state transformations
29
+ */
30
+ export const pipe = (value, ...fns) => fns.reduce((acc, fn) => fn(acc), value);
@@ -0,0 +1,8 @@
1
+ import { Effect, Stream } from "effect";
2
+ import type { z } from "zod";
3
+ import type { Plugin } from "../../plugin";
4
+ import type { PluginRuntimeError } from "../errors";
5
+ import type { InitializedPlugin } from "../types";
6
+ import type { StreamingOptions } from "./types";
7
+ export declare const createSourceStream: <T extends Plugin, TInput extends z.infer<T["inputSchema"]>, TItem, TPluginState extends z.infer<T["stateSchema"]>>(initializedPlugin: InitializedPlugin<T>, executePlugin: (plugin: InitializedPlugin<T>, input: TInput) => Effect.Effect<any, PluginRuntimeError>, input: TInput, options?: StreamingOptions<TItem, TPluginState>) => Stream.Stream<TItem, PluginRuntimeError>;
8
+ //# sourceMappingURL=streaming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../../src/runtime/streaming/streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAyB,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAe,MAAM,SAAS,CAAC;AA8B7D,eAAO,MAAM,kBAAkB,GAC7B,CAAC,SAAS,MAAM,EAChB,MAAM,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EACxC,KAAK,EACL,YAAY,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EAE9C,mBAAmB,iBAAiB,CAAC,CAAC,CAAC,EACvC,eAAe,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,kBAAkB,CAAC,EACtG,OAAO,MAAM,EACb,UAAS,gBAAgB,CAAC,KAAK,EAAE,YAAY,CAAM,KAClD,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB,CAyGzC,CAAC"}
@@ -0,0 +1,107 @@
1
+ import { Duration, Effect, Stream } from "effect";
2
+ /**
3
+ * Extract delay from plugin state (nextPollMs field)
4
+ * Returns null if nextPollMs is null (signals termination) or undefined (no delay specified)
5
+ */
6
+ const extractDelayFromState = (state) => {
7
+ const stateWithPolling = state;
8
+ if (stateWithPolling?.nextPollMs === null) {
9
+ return null; // Explicit termination signal
10
+ }
11
+ return stateWithPolling?.nextPollMs ? Duration.millis(stateWithPolling.nextPollMs) : null;
12
+ };
13
+ /**
14
+ * Check if plugin state signals stream termination
15
+ */
16
+ const isTerminalState = (state) => {
17
+ const stateWithPolling = state;
18
+ return stateWithPolling?.nextPollMs === null;
19
+ };
20
+ export const createSourceStream = (initializedPlugin, executePlugin, input, options = {}) => {
21
+ // Create initial stream state with plugin's initial state
22
+ const initialStreamState = {
23
+ invocations: 0,
24
+ pluginState: input.state,
25
+ lastItemCount: 0,
26
+ };
27
+ // Use Stream.async for full control over emission timing and delays
28
+ return Stream.async((emit) => {
29
+ let currentStreamState = initialStreamState;
30
+ let totalItemsEmitted = 0;
31
+ const loop = async () => {
32
+ try {
33
+ while (true) {
34
+ console.log(`[STREAMING] Starting iteration ${currentStreamState.invocations + 1}`);
35
+ // Check invocation limit BEFORE executing
36
+ if (options.maxInvocations && currentStreamState.invocations >= options.maxInvocations) {
37
+ console.log(`[STREAMING] Reached maxInvocations limit: ${options.maxInvocations}`);
38
+ break;
39
+ }
40
+ // Check maxItems limit BEFORE executing
41
+ if (options.maxItems && totalItemsEmitted >= options.maxItems) {
42
+ console.log(`[STREAMING] Reached maxItems limit: ${options.maxItems}`);
43
+ break;
44
+ }
45
+ // Execute plugin with current plugin state
46
+ const pluginInput = {
47
+ ...input,
48
+ state: currentStreamState.pluginState ?? null
49
+ };
50
+ console.log(`[STREAMING] About to execute plugin with input:`, JSON.stringify(pluginInput, null, 2));
51
+ console.log(`[STREAMING] Plugin state:`, JSON.stringify(currentStreamState.pluginState, null, 2));
52
+ const rawResult = await Effect.runPromise(executePlugin(initializedPlugin, pluginInput));
53
+ console.log(`[STREAMING] Plugin execution completed`);
54
+ // Transform raw plugin result to streaming format
55
+ const resultObj = rawResult;
56
+ const items = Array.isArray(resultObj.items) ? resultObj.items : [];
57
+ const nextPluginState = resultObj.nextState;
58
+ console.log(`[STREAMING] Transformed result: ${items.length} items`);
59
+ // Update stream state (increment AFTER execution)
60
+ currentStreamState = {
61
+ invocations: currentStreamState.invocations + 1,
62
+ pluginState: nextPluginState,
63
+ lastItemCount: items.length,
64
+ };
65
+ console.log(`[STREAMING] Invocation ${currentStreamState.invocations}, Items: ${items.length}`);
66
+ // Call state change hook if provided
67
+ if (options.onStateChange) {
68
+ await Effect.runPromise(options.onStateChange(nextPluginState, items));
69
+ }
70
+ // Emit items immediately (before any delays)
71
+ for (const item of items) {
72
+ if (options.maxItems && totalItemsEmitted >= options.maxItems) {
73
+ console.log(`[STREAMING] Stopping emission at maxItems limit: ${options.maxItems}`);
74
+ break;
75
+ }
76
+ emit.single(item);
77
+ totalItemsEmitted++;
78
+ }
79
+ // Check for termination conditions
80
+ if (nextPluginState && isTerminalState(nextPluginState)) {
81
+ console.log(`[STREAMING] Plugin signaled termination`);
82
+ break;
83
+ }
84
+ // Check stopWhenEmpty condition
85
+ if (options.stopWhenEmpty && items.length === 0) {
86
+ console.log(`[STREAMING] Stopping due to empty result and stopWhenEmpty=true`);
87
+ break;
88
+ }
89
+ // Handle delay AFTER emission, BEFORE next iteration
90
+ const nextDelay = extractDelayFromState(nextPluginState);
91
+ if (nextDelay && Duration.toMillis(nextDelay) > 0) {
92
+ console.log(`[STREAMING] Sleeping for ${Duration.toMillis(nextDelay)}ms before next iteration`);
93
+ await Effect.runPromise(Effect.sleep(nextDelay));
94
+ }
95
+ }
96
+ // End the stream
97
+ emit.end();
98
+ }
99
+ catch (error) {
100
+ console.log(`[STREAMING] Error occurred:`, error);
101
+ emit.fail(error);
102
+ }
103
+ };
104
+ // Start the loop
105
+ loop();
106
+ });
107
+ };
@@ -0,0 +1,19 @@
1
+ import type { Effect } from "effect";
2
+ /**
3
+ * Internal stream state managed by the runtime
4
+ */
5
+ export interface StreamState<TPluginState> {
6
+ readonly invocations: number;
7
+ readonly pluginState: TPluginState;
8
+ readonly lastItemCount: number;
9
+ }
10
+ /**
11
+ * Enhanced streaming options with Effect-based hooks
12
+ */
13
+ export interface StreamingOptions<TItem = unknown, TPluginState = unknown> {
14
+ maxItems?: number;
15
+ maxInvocations?: number;
16
+ stopWhenEmpty?: boolean;
17
+ onStateChange?: (newPluginState: TPluginState, items: TItem[]) => Effect.Effect<void>;
18
+ }
19
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/runtime/streaming/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,YAAY;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,YAAY,GAAG,OAAO;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,aAAa,CAAC,EAAE,CAAC,cAAc,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACvF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,3 @@
1
1
  import type { PluginLogger } from "../plugin";
2
2
  export declare const createTestLogger: () => PluginLogger;
3
- //# sourceMappingURL=test-utils.d.ts.map
3
+ //# sourceMappingURL=test-utils.d.ts.map
@@ -1,13 +1,7 @@
1
1
  import { Effect } from "effect";
2
2
  export const createTestLogger = () => ({
3
- logInfo: (message, context) =>
4
- Effect.sync(() => console.log(`[INFO] ${message}`, context || "")),
5
- logWarning: (message, context) =>
6
- Effect.sync(() => console.warn(`[WARNING] ${message}`, context || "")),
7
- logError: (message, error, context) =>
8
- Effect.sync(() =>
9
- console.error(`[ERROR] ${message}`, error, context || ""),
10
- ),
11
- logDebug: (message, context) =>
12
- Effect.sync(() => console.log(`[DEBUG] ${message}`, context || "")),
3
+ logInfo: (message, context) => Effect.sync(() => console.log(`[INFO] ${message}`, context || '')),
4
+ logWarning: (message, context) => Effect.sync(() => console.warn(`[WARNING] ${message}`, context || '')),
5
+ logError: (message, error, context) => Effect.sync(() => console.error(`[ERROR] ${message}`, error, context || '')),
6
+ logDebug: (message, context) => Effect.sync(() => console.log(`[DEBUG] ${message}`, context || '')),
13
7
  });
@@ -1,40 +1,40 @@
1
1
  import type { z } from "zod";
2
2
  import type { Plugin, PluginLogger, PluginRegistry } from "../plugin";
3
3
  export interface PluginRuntimeConfig {
4
- registry: PluginRegistry;
5
- secrets?: SecretsConfig;
6
- logger?: PluginLogger;
4
+ registry: PluginRegistry;
5
+ secrets?: SecretsConfig;
6
+ logger?: PluginLogger;
7
7
  }
8
8
  export interface SecretsConfig {
9
- [key: string]: string;
9
+ [key: string]: string;
10
10
  }
11
- export type AnyPlugin = Plugin<z.ZodTypeAny, z.ZodTypeAny, z.ZodTypeAny>;
11
+ export type AnyPlugin = Plugin<any, z.ZodTypeAny, z.ZodTypeAny>;
12
12
  export interface PluginConstructor {
13
- readonly ctor: new () => AnyPlugin;
14
- readonly metadata: {
15
- readonly pluginId: string;
16
- readonly version?: string;
17
- readonly description?: string;
18
- readonly type?: string;
19
- };
13
+ readonly ctor: new () => AnyPlugin;
14
+ readonly metadata: {
15
+ readonly pluginId: string;
16
+ readonly version?: string;
17
+ readonly description?: string;
18
+ readonly type?: string;
19
+ };
20
20
  }
21
21
  export interface PluginInstance<T extends AnyPlugin = AnyPlugin> {
22
- readonly plugin: T;
23
- readonly metadata: {
24
- readonly pluginId: string;
25
- readonly version?: string;
26
- readonly description?: string;
27
- readonly type?: string;
28
- };
22
+ readonly plugin: T;
23
+ readonly metadata: {
24
+ readonly pluginId: string;
25
+ readonly version?: string;
26
+ readonly description?: string;
27
+ readonly type?: string;
28
+ };
29
29
  }
30
30
  export interface InitializedPlugin<T extends AnyPlugin = AnyPlugin> {
31
- readonly plugin: T;
32
- readonly metadata: {
33
- readonly pluginId: string;
34
- readonly version?: string;
35
- readonly description?: string;
36
- readonly type?: string;
37
- };
38
- readonly config: z.infer<T["configSchema"]>;
31
+ readonly plugin: T;
32
+ readonly metadata: {
33
+ readonly pluginId: string;
34
+ readonly version?: string;
35
+ readonly description?: string;
36
+ readonly type?: string;
37
+ };
38
+ readonly config: z.infer<T["configSchema"]>;
39
39
  }
40
- //# sourceMappingURL=types.d.ts.map
40
+ //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtE,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB;AAGD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;AAEzE,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,IAAI,EAAE,UAAU,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACF;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IAC9D,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACF;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IACjE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;CAC5C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtE,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB;AAGD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,IAAI,EAAE,UAAU,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACF;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IAC9D,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACF;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IACjE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IAClB,QAAQ,CAAC,QAAQ,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;CAC5C"}
@@ -1,10 +1,5 @@
1
1
  import { Effect } from "effect";
2
2
  import type { z } from "zod";
3
3
  import { ValidationError } from "./errors";
4
- export declare const validate: <T>(
5
- schema: z.ZodSchema<T>,
6
- data: unknown,
7
- pluginId: string,
8
- stage: "config" | "input" | "output" | "state",
9
- ) => Effect.Effect<T, ValidationError>;
10
- //# sourceMappingURL=validation.d.ts.map
4
+ export declare const validate: <T>(schema: z.ZodSchema<T>, data: unknown, pluginId: string, stage: "config" | "input" | "output" | "state") => Effect.Effect<T, ValidationError>;
5
+ //# sourceMappingURL=validation.d.ts.map
@@ -1,16 +1,13 @@
1
1
  import { Effect } from "effect";
2
2
  import { ValidationError } from "./errors";
3
- export const validate = (schema, data, pluginId, stage) =>
4
- Effect.gen(function* () {
5
- const result = schema.safeParse(data);
6
- if (result.success) {
7
- return result.data;
8
- }
9
- return yield* Effect.fail(
10
- new ValidationError({
11
- pluginId,
12
- stage,
13
- zodError: result.error,
14
- }),
15
- );
16
- });
3
+ export const validate = (schema, data, pluginId, stage) => Effect.gen(function* () {
4
+ const result = schema.safeParse(data);
5
+ if (result.success) {
6
+ return result.data;
7
+ }
8
+ return yield* Effect.fail(new ValidationError({
9
+ pluginId,
10
+ stage,
11
+ zodError: result.error,
12
+ }));
13
+ });
@@ -0,0 +1,25 @@
1
+ import { Effect, Layer, ManagedRuntime } from "effect";
2
+ import { type PluginRegistry } from "../plugin";
3
+ import { PluginRuntime } from "../runtime";
4
+ import type { PluginRuntimeConfig } from "../runtime/types";
5
+ import { type TestPluginMap } from "./mocks/module-federation.service";
6
+ export declare const createTestLogger: () => {
7
+ logInfo: (message: string, context?: unknown) => Effect.Effect<void, never, never>;
8
+ logWarning: (message: string, context?: unknown) => Effect.Effect<void, never, never>;
9
+ logError: (message: string, error?: unknown, context?: unknown) => Effect.Effect<void, never, never>;
10
+ logDebug: (message: string, context?: unknown) => Effect.Effect<void, never, never>;
11
+ };
12
+ /**
13
+ * Creates a test layer with mock ModuleFederationService for unit testing.
14
+ * This layer provides all the necessary services for testing plugin runtime
15
+ * without requiring real module federation infrastructure.
16
+ */
17
+ export declare const createTestLayer: (config: PluginRuntimeConfig, pluginMap: TestPluginMap) => Layer.Layer<PluginRuntime, never, never>;
18
+ /**
19
+ * Creates a test plugin runtime using mock services.
20
+ * This is similar to createPluginRuntime but uses MockModuleFederationService
21
+ * instead of the real one, making it suitable for unit tests.
22
+ */
23
+ export declare const createTestPluginRuntime: (config: PluginRuntimeConfig, pluginMap: TestPluginMap) => ManagedRuntime.ManagedRuntime<PluginRuntime, never>;
24
+ export type { PluginRegistry, PluginRuntimeConfig, TestPluginMap };
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,EAAmB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAG/G,eAAO,MAAM,gBAAgB;uBACR,MAAM,YAAY,OAAO;0BAEtB,MAAM,YAAY,OAAO;wBAE3B,MAAM,UAAU,OAAO,YAAY,OAAO;wBAE1C,MAAM,YAAY,OAAO;CAE7C,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,mBAAmB,EAAE,WAAW,aAAa,6CAgCpF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,mBAAmB,EAAE,WAAW,aAAa,wDACpC,CAAC;AAG1D,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { Effect, Layer, ManagedRuntime } from "effect";
2
+ import { PluginLoggerTag } from "../plugin";
3
+ import { PluginRuntime } from "../runtime";
4
+ import { PluginService, SecretsService } from "../runtime/services";
5
+ // Import the mock service factory and types
6
+ import { createMockModuleFederationServiceLayer } from "./mocks/module-federation.service";
7
+ // Create test logger
8
+ export const createTestLogger = () => ({
9
+ logInfo: (message, context) => Effect.sync(() => console.log(`[INFO] ${message}`, context || '')),
10
+ logWarning: (message, context) => Effect.sync(() => console.warn(`[WARNING] ${message}`, context || '')),
11
+ logError: (message, error, context) => Effect.sync(() => console.error(`[ERROR] ${message}`, error, context || '')),
12
+ logDebug: (message, context) => Effect.sync(() => console.log(`[DEBUG] ${message}`, context || '')),
13
+ });
14
+ /**
15
+ * Creates a test layer with mock ModuleFederationService for unit testing.
16
+ * This layer provides all the necessary services for testing plugin runtime
17
+ * without requiring real module federation infrastructure.
18
+ */
19
+ export const createTestLayer = (config, pluginMap) => {
20
+ const secrets = config.secrets || {};
21
+ const logger = config.logger || createTestLogger();
22
+ return Layer.effect(PluginRuntime, Effect.gen(function* () {
23
+ const pluginService = yield* PluginService;
24
+ return {
25
+ loadPlugin: pluginService.loadPlugin,
26
+ instantiatePlugin: pluginService.instantiatePlugin,
27
+ initializePlugin: pluginService.initializePlugin,
28
+ executePlugin: pluginService.executePlugin,
29
+ usePlugin: pluginService.usePlugin,
30
+ streamPlugin: pluginService.streamPlugin,
31
+ shutdown: () => pluginService.cleanup(),
32
+ };
33
+ })).pipe(Layer.provide(PluginService.Live(config.registry, secrets).pipe(Layer.provide(Layer.mergeAll(createMockModuleFederationServiceLayer(pluginMap), SecretsService.Live(secrets), Layer.succeed(PluginLoggerTag, logger))))));
34
+ };
35
+ /**
36
+ * Creates a test plugin runtime using mock services.
37
+ * This is similar to createPluginRuntime but uses MockModuleFederationService
38
+ * instead of the real one, making it suitable for unit tests.
39
+ */
40
+ export const createTestPluginRuntime = (config, pluginMap) => ManagedRuntime.make(createTestLayer(config, pluginMap));
@@ -0,0 +1,8 @@
1
+ import { Layer } from "effect";
2
+ import { ModuleFederationService } from "../../runtime/services/module-federation.service";
3
+ import type { AnyPlugin } from "../../runtime/types";
4
+ export interface TestPluginMap {
5
+ [pluginId: string]: new () => AnyPlugin;
6
+ }
7
+ export declare const createMockModuleFederationServiceLayer: (pluginMap: TestPluginMap) => Layer.Layer<ModuleFederationService, never, never>;
8
+ //# sourceMappingURL=module-federation.service.d.ts.map
@@ -0,0 +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,qBAAqB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,SAAS,CAAC;CACzC;AA6CD,eAAO,MAAM,sCAAsC,GAAI,WAAW,aAAa,uDACT,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { Effect, Layer } from "effect";
2
+ import { ModuleFederationError } from "../../runtime/errors";
3
+ import { ModuleFederationService } from "../../runtime/services/module-federation.service";
4
+ // Create the mock service implementation
5
+ const createMockService = (pluginMap) => ({
6
+ 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;
11
+ }
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
+ }));
18
+ }),
19
+ 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
22
+ const PluginConstructor = pluginMap[pluginId];
23
+ if (PluginConstructor) {
24
+ return PluginConstructor;
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
+ }));
32
+ }),
33
+ });
34
+ // Create a Layer that provides the mock ModuleFederationService
35
+ export const createMockModuleFederationServiceLayer = (pluginMap) => Layer.succeed(ModuleFederationService, createMockService(pluginMap));