every-plugin 0.0.6 → 0.1.0
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.
- package/README.md +77 -13
- package/dist/errors.js +10 -10
- package/dist/plugin.d.ts +98 -44
- package/dist/plugin.js +17 -15
- package/dist/runtime/errors.d.ts +22 -1
- package/dist/runtime/errors.d.ts.map +1 -1
- package/dist/runtime/errors.js +8 -6
- package/dist/runtime/index.d.ts +68 -16
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +126 -27
- package/dist/runtime/mf.test.d.ts +2 -0
- package/dist/runtime/mf.test.d.ts.map +1 -0
- package/dist/runtime/mf.test.js +135 -0
- package/dist/runtime/runtime.test.d.ts +1 -1
- package/dist/runtime/runtime.test.js +366 -296
- package/dist/runtime/services/module-federation.service.d.ts +36 -9
- package/dist/runtime/services/module-federation.service.d.ts.map +1 -1
- package/dist/runtime/services/module-federation.service.js +122 -99
- package/dist/runtime/services/plugin.service.d.ts +66 -13
- package/dist/runtime/services/plugin.service.d.ts.map +1 -1
- package/dist/runtime/services/plugin.service.js +330 -122
- package/dist/runtime/services/secrets.service.d.ts +29 -9
- package/dist/runtime/services/secrets.service.d.ts.map +1 -1
- package/dist/runtime/services/secrets.service.js +30 -26
- package/dist/runtime/services.d.ts +1 -2
- package/dist/runtime/services.d.ts.map +1 -1
- package/dist/runtime/services.js +0 -1
- package/dist/runtime/streaming.d.ts +29 -0
- package/dist/runtime/streaming.d.ts.map +1 -0
- package/dist/runtime/streaming.js +59 -0
- package/dist/runtime/streaming.test.d.ts +2 -0
- package/dist/runtime/streaming.test.d.ts.map +1 -0
- package/dist/runtime/streaming.test.js +271 -0
- package/dist/runtime/test-utils.d.ts +3 -0
- package/dist/runtime/test-utils.d.ts.map +1 -0
- package/dist/runtime/test-utils.js +13 -0
- package/dist/runtime/types.d.ts +27 -27
- package/dist/runtime/validation.d.ts +1 -1
- package/dist/runtime/validation.d.ts.map +1 -1
- package/dist/runtime/validation.js +14 -11
- package/dist/source.d.ts +62 -190
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +32 -85
- package/package.json +7 -3
- package/dist/runtime/runtime.d.ts +0 -58
- package/dist/runtime/runtime.d.ts.map +0 -1
- package/dist/runtime/runtime.js +0 -75
- package/dist/runtime/services/plugin-cache.service.d.ts +0 -18
- package/dist/runtime/services/plugin-cache.service.d.ts.map +0 -1
- package/dist/runtime/services/plugin-cache.service.js +0 -55
package/dist/runtime/index.js
CHANGED
|
@@ -1,34 +1,133 @@
|
|
|
1
1
|
import { Effect, Layer, ManagedRuntime } from "effect";
|
|
2
2
|
import { PluginLoggerTag } from "../plugin";
|
|
3
|
-
import {
|
|
3
|
+
import { PluginRuntimeError } from "./errors";
|
|
4
|
+
import {
|
|
5
|
+
ModuleFederationService,
|
|
6
|
+
PluginService,
|
|
7
|
+
SecretsService,
|
|
8
|
+
} from "./services";
|
|
9
|
+
import { createSourceStream } from "./streaming";
|
|
10
|
+
import { validate } from "./validation";
|
|
11
|
+
|
|
4
12
|
// Default logger implementation
|
|
5
13
|
const createDefaultLogger = () => ({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
logInfo: (message, context) =>
|
|
15
|
+
Effect.logInfo(message).pipe(
|
|
16
|
+
Effect.annotateLogs({ source: "plugin", context }),
|
|
17
|
+
),
|
|
18
|
+
logWarning: (message, context) =>
|
|
19
|
+
Effect.logWarning(message).pipe(
|
|
20
|
+
Effect.annotateLogs({ source: "plugin", context }),
|
|
21
|
+
),
|
|
22
|
+
logError: (message, error, context) =>
|
|
23
|
+
Effect.logError(message, error).pipe(
|
|
24
|
+
Effect.annotateLogs({ source: "plugin", error, context }),
|
|
25
|
+
),
|
|
26
|
+
logDebug: (message, context) =>
|
|
27
|
+
Effect.logDebug(message).pipe(
|
|
28
|
+
Effect.annotateLogs({ source: "plugin", context }),
|
|
29
|
+
),
|
|
10
30
|
});
|
|
11
31
|
export class PluginRuntime extends Effect.Tag("PluginRuntime")() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
static Live = (config) => {
|
|
33
|
+
const secrets = config.secrets || {};
|
|
34
|
+
const logger = config.logger || createDefaultLogger();
|
|
35
|
+
return Layer.effect(
|
|
36
|
+
PluginRuntime,
|
|
37
|
+
Effect.gen(function* () {
|
|
38
|
+
const pluginService = yield* PluginService;
|
|
39
|
+
return {
|
|
40
|
+
loadPlugin: pluginService.loadPlugin,
|
|
41
|
+
instantiatePlugin: pluginService.instantiatePlugin,
|
|
42
|
+
initializePlugin: pluginService.initializePlugin,
|
|
43
|
+
executePlugin: pluginService.executePlugin,
|
|
44
|
+
usePlugin: (pluginId, config) =>
|
|
45
|
+
pluginService.usePlugin(pluginId, config),
|
|
46
|
+
streamPlugin: (pluginId, config, input, options) =>
|
|
47
|
+
Effect.gen(function* () {
|
|
48
|
+
// Get initialized plugin (benefits from caching)
|
|
49
|
+
const initializedPlugin = yield* pluginService.usePlugin(
|
|
50
|
+
pluginId,
|
|
51
|
+
config,
|
|
52
|
+
);
|
|
53
|
+
// Validate plugin type
|
|
54
|
+
if (initializedPlugin.plugin.type !== "source") {
|
|
55
|
+
return yield* Effect.fail(
|
|
56
|
+
new PluginRuntimeError({
|
|
57
|
+
pluginId,
|
|
58
|
+
operation: "stream-plugin-validate",
|
|
59
|
+
cause: new Error(
|
|
60
|
+
`Plugin ${pluginId} is not a source plugin (type: ${initializedPlugin.plugin.type})`,
|
|
61
|
+
),
|
|
62
|
+
retryable: false,
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
// Check if procedure is streamable and validate state
|
|
67
|
+
const procedureName = input.procedure;
|
|
68
|
+
const isStreamable =
|
|
69
|
+
initializedPlugin.plugin.isStreamable(procedureName);
|
|
70
|
+
if (isStreamable) {
|
|
71
|
+
// Check stateSchema exists
|
|
72
|
+
if (
|
|
73
|
+
!("stateSchema" in initializedPlugin.plugin) ||
|
|
74
|
+
!initializedPlugin.plugin.stateSchema
|
|
75
|
+
) {
|
|
76
|
+
return yield* Effect.fail(
|
|
77
|
+
new PluginRuntimeError({
|
|
78
|
+
pluginId: initializedPlugin.plugin.id,
|
|
79
|
+
operation: "validate-state",
|
|
80
|
+
cause: new Error(
|
|
81
|
+
`Streamable plugin ${initializedPlugin.plugin.id} must have a stateSchema`,
|
|
82
|
+
),
|
|
83
|
+
retryable: false,
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
// Validate initial state
|
|
88
|
+
yield* validate(
|
|
89
|
+
initializedPlugin.plugin.stateSchema,
|
|
90
|
+
input.state,
|
|
91
|
+
initializedPlugin.plugin.id,
|
|
92
|
+
"state",
|
|
93
|
+
).pipe(
|
|
94
|
+
Effect.mapError(
|
|
95
|
+
(validationError) =>
|
|
96
|
+
new PluginRuntimeError({
|
|
97
|
+
pluginId: initializedPlugin.plugin.id,
|
|
98
|
+
operation: "validate-state",
|
|
99
|
+
cause: validationError.zodError,
|
|
100
|
+
retryable: false,
|
|
101
|
+
}),
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
// Create and return the stream
|
|
106
|
+
return createSourceStream(
|
|
107
|
+
initializedPlugin,
|
|
108
|
+
pluginService.executePlugin,
|
|
109
|
+
input,
|
|
110
|
+
options,
|
|
111
|
+
isStreamable,
|
|
112
|
+
);
|
|
113
|
+
}),
|
|
114
|
+
shutdown: () => pluginService.cleanup(),
|
|
115
|
+
};
|
|
116
|
+
}),
|
|
117
|
+
).pipe(
|
|
118
|
+
Layer.provide(
|
|
119
|
+
PluginService.Live(config.registry, secrets).pipe(
|
|
120
|
+
Layer.provide(
|
|
121
|
+
Layer.mergeAll(
|
|
122
|
+
ModuleFederationService.Live,
|
|
123
|
+
SecretsService.Live(secrets),
|
|
124
|
+
Layer.succeed(PluginLoggerTag, logger),
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
};
|
|
33
131
|
}
|
|
34
|
-
export const createPluginRuntime = (config) =>
|
|
132
|
+
export const createPluginRuntime = (config) =>
|
|
133
|
+
ManagedRuntime.make(PluginRuntime.Live(config));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mf.test.d.ts","sourceRoot":"","sources":["../../src/runtime/mf.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Effect, Layer } from "effect";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { PluginLoggerTag } from "../plugin";
|
|
4
|
+
import { ModuleFederationService } from "./services/module-federation.service";
|
|
5
|
+
import { createTestLogger } from "./test-utils";
|
|
6
|
+
|
|
7
|
+
// Test registry for diagnostics
|
|
8
|
+
const TEST_PLUGIN_ID = "test-plugin";
|
|
9
|
+
const TEST_REMOTE_URL = "http://localhost:3000/remoteEntry.js";
|
|
10
|
+
const testLayer = Layer.succeed(PluginLoggerTag, createTestLogger());
|
|
11
|
+
describe("Module Federation Diagnostics", () => {
|
|
12
|
+
it("should verify remote URL is accessible (sanity check)", async () => {
|
|
13
|
+
console.log("=== Testing Remote URL Accessibility ===");
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(TEST_REMOTE_URL, { method: "HEAD" });
|
|
16
|
+
console.log(`Remote URL status: ${response.status}`);
|
|
17
|
+
console.log(
|
|
18
|
+
`Remote URL headers:`,
|
|
19
|
+
Object.fromEntries(response.headers.entries()),
|
|
20
|
+
);
|
|
21
|
+
expect(response.ok).toBe(true);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error("Failed to access remote URL:", error);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
it("should test name transformation logic", async () => {
|
|
28
|
+
console.log("=== Testing Name Transformation ===");
|
|
29
|
+
// Test the same logic used in module-federation.service.ts
|
|
30
|
+
const remoteName = TEST_PLUGIN_ID.toLowerCase()
|
|
31
|
+
.replace("@", "")
|
|
32
|
+
.replace("/", "_");
|
|
33
|
+
const modulePath = `${remoteName}/plugin`;
|
|
34
|
+
console.log(`Original plugin ID: ${TEST_PLUGIN_ID}`);
|
|
35
|
+
console.log(`Transformed remote name: ${remoteName}`);
|
|
36
|
+
console.log(`Module path: ${modulePath}`);
|
|
37
|
+
expect(remoteName).toBe("test-plugin");
|
|
38
|
+
expect(modulePath).toBe("test-plugin/plugin");
|
|
39
|
+
});
|
|
40
|
+
it("should register remote successfully", async () => {
|
|
41
|
+
console.log("=== Testing Remote Registration ===");
|
|
42
|
+
const result = await Effect.runPromise(
|
|
43
|
+
Effect.gen(function* () {
|
|
44
|
+
const mfService = yield* ModuleFederationService;
|
|
45
|
+
console.log("Attempting to register remote...");
|
|
46
|
+
yield* mfService.registerRemote(TEST_PLUGIN_ID, TEST_REMOTE_URL);
|
|
47
|
+
console.log("Remote registration completed successfully");
|
|
48
|
+
return "success";
|
|
49
|
+
}).pipe(
|
|
50
|
+
Effect.provide(ModuleFederationService.Live),
|
|
51
|
+
Effect.provide(testLayer),
|
|
52
|
+
Effect.catchAll((error) => {
|
|
53
|
+
console.error("Remote registration failed:", error);
|
|
54
|
+
return Effect.succeed(`failed: ${error}`);
|
|
55
|
+
}),
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
console.log(`Registration result: ${result}`);
|
|
59
|
+
expect(result).toBe("success");
|
|
60
|
+
});
|
|
61
|
+
it.skip("should inspect module federation instance", async () => {
|
|
62
|
+
console.log("=== Inspecting Module Federation Instance ===");
|
|
63
|
+
const result = await Effect.runPromise(
|
|
64
|
+
Effect.gen(function* () {
|
|
65
|
+
const mfService = yield* ModuleFederationService;
|
|
66
|
+
// First register the remote
|
|
67
|
+
yield* mfService.registerRemote(TEST_PLUGIN_ID, TEST_REMOTE_URL);
|
|
68
|
+
// Access the internal MF instance to inspect it
|
|
69
|
+
// Note: This is a bit hacky but needed for diagnostics
|
|
70
|
+
const mfInstance = mfService.mf || globalThis.__FEDERATION__;
|
|
71
|
+
console.log("Module Federation instance:", typeof mfInstance);
|
|
72
|
+
console.log(
|
|
73
|
+
"Available methods:",
|
|
74
|
+
Object.getOwnPropertyNames(mfInstance || {}),
|
|
75
|
+
);
|
|
76
|
+
if (mfInstance && mfInstance.options) {
|
|
77
|
+
console.log("MF options:", mfInstance.options);
|
|
78
|
+
}
|
|
79
|
+
return "inspected";
|
|
80
|
+
}).pipe(
|
|
81
|
+
Effect.provide(ModuleFederationService.Live),
|
|
82
|
+
Effect.provide(testLayer),
|
|
83
|
+
Effect.catchAll((error) => {
|
|
84
|
+
console.error("MF instance inspection failed:", error);
|
|
85
|
+
return Effect.succeed(`failed: ${error}`);
|
|
86
|
+
}),
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
expect(result).toBe("inspected");
|
|
90
|
+
});
|
|
91
|
+
it.skip("should attempt to load remote container with detailed logging", async () => {
|
|
92
|
+
console.log("=== Testing Remote Container Loading ===");
|
|
93
|
+
const result = await Effect.runPromise(
|
|
94
|
+
Effect.gen(function* () {
|
|
95
|
+
const mfService = yield* ModuleFederationService;
|
|
96
|
+
// Register remote first
|
|
97
|
+
console.log("Step 1: Registering remote...");
|
|
98
|
+
yield* mfService.registerRemote(TEST_PLUGIN_ID, TEST_REMOTE_URL);
|
|
99
|
+
console.log("Step 1: ✓ Remote registered");
|
|
100
|
+
// Now try to load the constructor
|
|
101
|
+
console.log("Step 2: Loading remote constructor...");
|
|
102
|
+
const ctor = yield* mfService.loadRemoteConstructor(
|
|
103
|
+
TEST_PLUGIN_ID,
|
|
104
|
+
TEST_REMOTE_URL,
|
|
105
|
+
);
|
|
106
|
+
console.log("Step 2: ✓ Constructor loaded:", typeof ctor);
|
|
107
|
+
// Try to instantiate it
|
|
108
|
+
console.log("Step 3: Attempting to instantiate constructor...");
|
|
109
|
+
const instance = new ctor();
|
|
110
|
+
console.log("Step 3: ✓ Instance created:", typeof instance);
|
|
111
|
+
console.log(
|
|
112
|
+
"Instance properties:",
|
|
113
|
+
Object.getOwnPropertyNames(instance),
|
|
114
|
+
);
|
|
115
|
+
console.log("Instance id:", instance.id);
|
|
116
|
+
return "success";
|
|
117
|
+
}).pipe(
|
|
118
|
+
Effect.provide(ModuleFederationService.Live),
|
|
119
|
+
Effect.provide(testLayer),
|
|
120
|
+
Effect.catchAll((error) => {
|
|
121
|
+
console.error("Container loading failed at some step:", error);
|
|
122
|
+
console.error("Error details:", {
|
|
123
|
+
message: error.message,
|
|
124
|
+
cause: error.cause,
|
|
125
|
+
stack: error.stack,
|
|
126
|
+
});
|
|
127
|
+
return Effect.succeed(`failed: ${error.message}`);
|
|
128
|
+
}),
|
|
129
|
+
),
|
|
130
|
+
);
|
|
131
|
+
console.log(`Final result: ${result}`);
|
|
132
|
+
// Don't fail the test - we want to see what happens
|
|
133
|
+
expect(typeof result).toBe("string");
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export {};
|
|
2
|
-
//# sourceMappingURL=runtime.test.d.ts.map
|
|
2
|
+
//# sourceMappingURL=runtime.test.d.ts.map
|