plugin(telemetry-watcher): inline plugin SDK to break ESM TS chain
@fusion/plugin-sdk's package.json points its import entry at
src/index.ts (TS source), and that file imports core/src/plugin-types.js
via relative path. Node 22 ESM has no TS loader so the chain
unraveled at runtime: the plugin loader successfully resolved our
compiled dist/index.js, but the very first `import { definePlugin }
from "@fusion/plugin-sdk"` walked into TS source and fell over.
definePlugin is a pure typed identity function — it adds no runtime
behavior. Inline its source plus a structural copy of the plugin
context/route/manifest types we use, drop the @fusion/plugin-sdk
dependency entirely. The compiled output now imports nothing outside
node:crypto and Node builtins, so it can load anywhere fusion can
spawn ESM modules.
When fusion publishes a compiled SDK build, swap the inline types
back to import statements and restore the workspace dependency.
This commit is contained in:
@@ -23,13 +23,73 @@
|
||||
*/
|
||||
|
||||
import { createHash } from "node:crypto";
|
||||
import { definePlugin } from "@fusion/plugin-sdk";
|
||||
import type {
|
||||
FusionPlugin,
|
||||
PluginContext,
|
||||
PluginRouteDefinition,
|
||||
PluginSettingSchema,
|
||||
} from "@fusion/plugin-sdk";
|
||||
|
||||
// ── Inline plugin SDK surface ──────────────────────────────────────────────
|
||||
//
|
||||
// We deliberately do NOT import from "@fusion/plugin-sdk" at runtime. The
|
||||
// SDK package has its `import` export entry pointing at a TypeScript file
|
||||
// (src/index.ts) which itself imports more TS files from @fusion/core via
|
||||
// relative paths. Node 22 ESM cannot resolve those without a TS loader at
|
||||
// runtime, so the loader fails before our handler ever runs. The SDK
|
||||
// surface we actually use is structural: definePlugin is a typed identity
|
||||
// helper, and the type aliases are erased at compile time. Inlining these
|
||||
// lets the compiled dist/index.js load without traversing into TS sources.
|
||||
//
|
||||
// When fusion publishes a compiled SDK build, swap these back to import
|
||||
// statements and remove the local declarations.
|
||||
|
||||
interface PluginSettingSchema {
|
||||
type: "string" | "number" | "boolean" | "enum" | "password" | "array";
|
||||
label?: string;
|
||||
description?: string;
|
||||
defaultValue?: unknown;
|
||||
required?: boolean;
|
||||
enumValues?: string[];
|
||||
multiline?: boolean;
|
||||
itemType?: "string" | "number";
|
||||
}
|
||||
|
||||
interface PluginLogger {
|
||||
info(message: string, ...args: unknown[]): void;
|
||||
warn(message: string, ...args: unknown[]): void;
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
debug(message: string, ...args: unknown[]): void;
|
||||
}
|
||||
|
||||
interface PluginContext {
|
||||
pluginId: string;
|
||||
taskStore: unknown;
|
||||
settings: Record<string, unknown>;
|
||||
logger: PluginLogger;
|
||||
emitEvent: (event: string, data: unknown) => void;
|
||||
}
|
||||
|
||||
interface PluginRouteDefinition {
|
||||
method: "GET" | "POST" | "PUT" | "DELETE";
|
||||
path: string;
|
||||
description?: string;
|
||||
handler: (req: unknown, ctx: PluginContext) => Promise<unknown>;
|
||||
}
|
||||
|
||||
interface FusionPlugin {
|
||||
manifest: {
|
||||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
description?: string;
|
||||
settingsSchema?: Record<string, PluginSettingSchema>;
|
||||
};
|
||||
state: "installed" | "started" | "stopped" | "error";
|
||||
hooks?: {
|
||||
onLoad?: (ctx: PluginContext) => Promise<void> | void;
|
||||
onUnload?: () => Promise<void> | void;
|
||||
};
|
||||
routes?: PluginRouteDefinition[];
|
||||
}
|
||||
|
||||
function definePlugin(plugin: FusionPlugin): FusionPlugin {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
// ── Severity classifier ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -532,7 +592,11 @@ const plugin: FusionPlugin = definePlugin({
|
||||
);
|
||||
|
||||
try {
|
||||
const task = await ctx.taskStore.createTask({
|
||||
const taskStore = ctx.taskStore as {
|
||||
createTask: (input: Record<string, unknown>) => Promise<{ id: string }>;
|
||||
updateTask?: (id: string, patch: Record<string, unknown>) => Promise<unknown>;
|
||||
};
|
||||
const task = await taskStore.createTask({
|
||||
title: `[${severity}] ${item.alertname}`,
|
||||
description,
|
||||
column: "triage",
|
||||
@@ -545,20 +609,15 @@ const plugin: FusionPlugin = definePlugin({
|
||||
} as never,
|
||||
});
|
||||
|
||||
if (triageAgentId) {
|
||||
const store = ctx.taskStore as unknown as {
|
||||
updateTask?: (id: string, patch: Record<string, unknown>) => Promise<unknown>;
|
||||
};
|
||||
if (typeof store.updateTask === "function") {
|
||||
try {
|
||||
await store.updateTask(task.id, { assignedAgentId: triageAgentId });
|
||||
} catch (assignErr) {
|
||||
ctx.logger.warn(
|
||||
`Could not auto-assign task ${task.id}: ${
|
||||
assignErr instanceof Error ? assignErr.message : String(assignErr)
|
||||
}`,
|
||||
);
|
||||
}
|
||||
if (triageAgentId && typeof taskStore.updateTask === "function") {
|
||||
try {
|
||||
await taskStore.updateTask(task.id, { assignedAgentId: triageAgentId });
|
||||
} catch (assignErr) {
|
||||
ctx.logger.warn(
|
||||
`Could not auto-assign task ${task.id}: ${
|
||||
assignErr instanceof Error ? assignErr.message : String(assignErr)
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user