conduithub 0.0.3 → 1.0.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/dist/core/conduit-hub/index.cjs +188 -0
- package/dist/core/conduit-hub/index.d.cts +44 -0
- package/dist/core/conduit-hub/index.d.mts +44 -0
- package/dist/core/conduit-hub/index.d.ts +44 -0
- package/dist/core/conduit-hub/index.mjs +186 -0
- package/dist/core/config-manager/index.cjs +216 -0
- package/dist/core/config-manager/index.d.cts +7 -0
- package/dist/core/config-manager/index.d.mts +7 -0
- package/dist/core/config-manager/index.d.ts +7 -0
- package/dist/core/config-manager/index.mjs +214 -0
- package/dist/core/event-bus/index.cjs +154 -53
- package/dist/core/event-bus/index.d.cts +2 -42
- package/dist/core/event-bus/index.d.mts +2 -42
- package/dist/core/event-bus/index.d.ts +2 -42
- package/dist/core/event-bus/index.mjs +153 -52
- package/dist/core/hook/index.cjs +185 -148
- package/dist/core/hook/index.d.cts +28 -16
- package/dist/core/hook/index.d.mts +28 -16
- package/dist/core/hook/index.d.ts +28 -16
- package/dist/core/hook/index.mjs +183 -146
- package/dist/core/index.cjs +17 -1
- package/dist/core/index.d.cts +184 -3
- package/dist/core/index.d.mts +184 -3
- package/dist/core/index.d.ts +184 -3
- package/dist/core/index.mjs +12 -1
- package/dist/core/plugin/index.cjs +271 -0
- package/dist/core/plugin/index.d.cts +7 -0
- package/dist/core/plugin/index.d.mts +7 -0
- package/dist/core/plugin/index.d.ts +7 -0
- package/dist/core/plugin/index.mjs +268 -0
- package/dist/core/service-container/index.cjs +306 -0
- package/dist/core/service-container/index.d.cts +51 -0
- package/dist/core/service-container/index.d.mts +51 -0
- package/dist/core/service-container/index.d.ts +51 -0
- package/dist/core/service-container/index.mjs +304 -0
- package/dist/core/state-manager/index.cjs +195 -0
- package/dist/core/state-manager/index.d.cts +39 -0
- package/dist/core/state-manager/index.d.mts +39 -0
- package/dist/core/state-manager/index.d.ts +39 -0
- package/dist/core/state-manager/index.mjs +193 -0
- package/dist/index.cjs +34 -5
- package/dist/index.d.cts +54 -2
- package/dist/index.d.mts +54 -2
- package/dist/index.d.ts +54 -2
- package/dist/index.mjs +13 -1
- package/dist/shared/conduithub.BDwZXllF.mjs +63 -0
- package/dist/shared/{conduithub.CvMLTa-R.cjs → conduithub.BNQsddJO.cjs} +2 -9
- package/dist/shared/{conduithub.74V0wiLi.mjs → conduithub.BNefRQsK.mjs} +3 -9
- package/dist/shared/conduithub.BZQmkQy7.d.cts +52 -0
- package/dist/shared/conduithub.BqUYv04j.cjs +68 -0
- package/dist/shared/conduithub.Bq_7Xj0J.cjs +18 -0
- package/dist/shared/conduithub.BzLwccre.d.mts +52 -0
- package/dist/shared/conduithub.CkOQG3cD.mjs +14 -0
- package/dist/shared/conduithub.CmZo_Vuc.cjs +38 -0
- package/dist/shared/conduithub.DQO1dRnn.cjs +33 -0
- package/dist/shared/conduithub.DQOWQ-Bx.d.ts +52 -0
- package/dist/shared/conduithub.DsOOeNwU.cjs +269 -0
- package/dist/shared/conduithub.DyQQrHW9.mjs +267 -0
- package/dist/shared/conduithub.G7ICpZIy.mjs +36 -0
- package/dist/shared/conduithub.alPiaJax.mjs +29 -0
- package/dist/shared/conduithub.bsiNMTVD.mjs +59 -0
- package/dist/shared/conduithub.gF2DFc43.cjs +76 -0
- package/dist/utils/index.cjs +18 -5
- package/dist/utils/index.d.cts +33 -2
- package/dist/utils/index.d.mts +33 -2
- package/dist/utils/index.d.ts +33 -2
- package/dist/utils/index.mjs +7 -1
- package/package.json +52 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class ConduithubError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
details;
|
|
6
|
+
timestamp;
|
|
7
|
+
constructor(message, context) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "ConduithubError";
|
|
10
|
+
this.code = context?.code;
|
|
11
|
+
this.details = context?.details;
|
|
12
|
+
this.timestamp = context?.timestamp ?? Date.now();
|
|
13
|
+
Error.captureStackTrace?.(this, ConduithubError);
|
|
14
|
+
}
|
|
15
|
+
toJSON() {
|
|
16
|
+
return {
|
|
17
|
+
name: this.name,
|
|
18
|
+
message: this.message,
|
|
19
|
+
code: this.code,
|
|
20
|
+
details: this.details,
|
|
21
|
+
timestamp: this.timestamp,
|
|
22
|
+
stack: this.stack
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
class PackageManagerRegistry {
|
|
27
|
+
manager = "";
|
|
28
|
+
set(manager) {
|
|
29
|
+
if (!this.isValidManager(manager)) {
|
|
30
|
+
throw new ConduithubError(`Invalid package manager: ${manager}`, {
|
|
31
|
+
code: "INVALID_PACKAGE_MANAGER",
|
|
32
|
+
details: { manager, validManagers: ["npm", "pnpm", "yarn", "bun"] }
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
this.manager = manager;
|
|
36
|
+
}
|
|
37
|
+
get() {
|
|
38
|
+
return this.manager;
|
|
39
|
+
}
|
|
40
|
+
isValidManager(manager) {
|
|
41
|
+
return ["npm", "pnpm", "yarn", "bun"].includes(manager);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const packageManagerRegistry = new PackageManagerRegistry();
|
|
45
|
+
function setPkgManager(manager) {
|
|
46
|
+
packageManagerRegistry.set(manager);
|
|
47
|
+
}
|
|
48
|
+
function getPkgManager() {
|
|
49
|
+
return packageManagerRegistry.get();
|
|
50
|
+
}
|
|
51
|
+
class MissingDependencyError extends ConduithubError {
|
|
52
|
+
constructor(pkgName) {
|
|
53
|
+
const manager = getPkgManager() || "npm";
|
|
54
|
+
const message = `The package ${pkgName} is missing from the dependencies. Please install it using "${manager} add ${pkgName}"`;
|
|
55
|
+
super(message, {
|
|
56
|
+
code: "MISSING_DEPENDENCY",
|
|
57
|
+
details: {
|
|
58
|
+
packageName: pkgName,
|
|
59
|
+
suggestedCommand: `${manager} add ${pkgName}`
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.ConduithubError = ConduithubError;
|
|
66
|
+
exports.MissingDependencyError = MissingDependencyError;
|
|
67
|
+
exports.getPkgManager = getPkgManager;
|
|
68
|
+
exports.setPkgManager = setPkgManager;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const uuid = require('uuid');
|
|
4
|
+
|
|
5
|
+
function generateUuid() {
|
|
6
|
+
return uuid.v4();
|
|
7
|
+
}
|
|
8
|
+
function generateShortId() {
|
|
9
|
+
return generateUuid().split("-")[0];
|
|
10
|
+
}
|
|
11
|
+
function isValidUuid(value) {
|
|
12
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
13
|
+
return uuidRegex.test(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.generateShortId = generateShortId;
|
|
17
|
+
exports.generateUuid = generateUuid;
|
|
18
|
+
exports.isValidUuid = isValidUuid;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { a as Logger } from './conduithub.B7aryjPG.mjs';
|
|
2
|
+
|
|
3
|
+
interface EventData<T extends string, P> {
|
|
4
|
+
type: T;
|
|
5
|
+
payload: P;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
source: string;
|
|
8
|
+
context?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface EventBusOptions<EM extends Record<string, unknown>> {
|
|
12
|
+
readonly logger?: Logger;
|
|
13
|
+
readonly maxHandlersPerEvent?: number;
|
|
14
|
+
readonly handlerTimeoutMs?: number;
|
|
15
|
+
readonly onError?: (err: unknown, eventType: keyof EM) => void;
|
|
16
|
+
}
|
|
17
|
+
interface EventBusStats<EM extends Record<string, unknown>> {
|
|
18
|
+
readonly totalEvents: number;
|
|
19
|
+
readonly totalListeners: number;
|
|
20
|
+
readonly eventNames: (keyof EM)[];
|
|
21
|
+
readonly listenerCount: Record<keyof EM, number>;
|
|
22
|
+
}
|
|
23
|
+
declare class EventBus<EM extends Record<string, unknown>> {
|
|
24
|
+
private readonly handlers;
|
|
25
|
+
private readonly locks;
|
|
26
|
+
private initialized;
|
|
27
|
+
private readonly logger;
|
|
28
|
+
private readonly maxHandlersPerEvent;
|
|
29
|
+
private readonly handlerTimeoutMs;
|
|
30
|
+
private readonly onError?;
|
|
31
|
+
constructor(options?: EventBusOptions<EM>);
|
|
32
|
+
private withEventLock;
|
|
33
|
+
private ensureInitialized;
|
|
34
|
+
private sanitizeLog;
|
|
35
|
+
initialize(): Promise<void>;
|
|
36
|
+
shutdown(): Promise<void>;
|
|
37
|
+
private getTotalHandlerCount;
|
|
38
|
+
private clearAllHandlers;
|
|
39
|
+
on<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>, context?: Record<string, unknown>, signal?: AbortSignal) => Promise<void> | void, priority?: number, customId?: string): string;
|
|
40
|
+
once<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>, context?: Record<string, unknown>, signal?: AbortSignal) => Promise<void> | void, priority?: number, customId?: string): string;
|
|
41
|
+
private registerHandler;
|
|
42
|
+
off<K extends keyof EM>(type: K, id?: string): void;
|
|
43
|
+
emit<K extends keyof EM>(type: K, payload: EM[K], source?: string, context?: Record<string, unknown>): Promise<void>;
|
|
44
|
+
removeAllListeners<K extends keyof EM>(type?: K): void;
|
|
45
|
+
listenerCount<K extends keyof EM>(type: K): number;
|
|
46
|
+
eventNames(): Array<keyof EM>;
|
|
47
|
+
getStats(): EventBusStats<EM>;
|
|
48
|
+
get isInitialized(): boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { EventBus as E };
|
|
52
|
+
export type { EventData as a };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { v4 } from 'uuid';
|
|
2
|
+
|
|
3
|
+
function generateUuid() {
|
|
4
|
+
return v4();
|
|
5
|
+
}
|
|
6
|
+
function generateShortId() {
|
|
7
|
+
return generateUuid().split("-")[0];
|
|
8
|
+
}
|
|
9
|
+
function isValidUuid(value) {
|
|
10
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
11
|
+
return uuidRegex.test(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { generateShortId as a, generateUuid as g, isValidUuid as i };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ERROR_CODE = {
|
|
4
|
+
// Configuration errors
|
|
5
|
+
INVALID_JSON: "Invalid JSON format",
|
|
6
|
+
INVALID_CONFIG: "Configuration validation failed",
|
|
7
|
+
UNSUPPORTED_CONFIG_FORMAT: "JavaScript config files are not supported. Use JSON format.",
|
|
8
|
+
// Initialization errors
|
|
9
|
+
STATE_MANAGER_NOT_INITIALIZED: "StateManager is not initialized",
|
|
10
|
+
SERVICE_CONTAINER_NOT_INITIALIZED: "Service Container is not initialized",
|
|
11
|
+
EVENT_BUS_NOT_INITIALIZED: "EventBus is not initialized",
|
|
12
|
+
HOOK_SYSTEM_NOT_INITIALIZED: "Hook system is not initialized",
|
|
13
|
+
// Handler limit errors
|
|
14
|
+
EVENT_HANDLER_LIMIT_EXCEEDED: "Handler limit exceeded for event",
|
|
15
|
+
HOOK_HANDLER_LIMIT_EXCEEDED: "Handler limit exceeded for hook",
|
|
16
|
+
// Duplicate ID errors
|
|
17
|
+
DUPLICATE_EVENT_HANDLER_ID: "Duplicate custom ID for event",
|
|
18
|
+
DUPLICATE_HOOK_HANDLER_ID: "Duplicate custom ID for hook",
|
|
19
|
+
// State management errors
|
|
20
|
+
INVALID_STATE_JSON_FORMAT: "Invalid state JSON format",
|
|
21
|
+
// Execution errors
|
|
22
|
+
HOOK_EXECUTION_FAILED: "Hook execution failed",
|
|
23
|
+
UNKNOWN_ERROR: "Unknown error",
|
|
24
|
+
// Service container errors
|
|
25
|
+
CIRCULAR_DEPENDENCY_DETECTED: "Circular dependency detected",
|
|
26
|
+
SERVICE_NOT_FOUND: "Service not found",
|
|
27
|
+
SERVICE_CREATION_FAILED: "Service creation failed",
|
|
28
|
+
SERVICE_IS_SINGLETON: "Service is a singleton and cannot be registered again",
|
|
29
|
+
// Plugin errors
|
|
30
|
+
PLUGIN_NOT_INITIALIZED: "Plugin is not initialized",
|
|
31
|
+
PLUGIN_ALREADY_INITIALIZED: "Plugin is already initialized",
|
|
32
|
+
PLUGIN_NOT_RUNNING: "Plugin is not running",
|
|
33
|
+
// ConfigManager errors
|
|
34
|
+
CONFIG_MANAGER_NOT_INITIALIZED: "ConfigManager is not initialized",
|
|
35
|
+
CONFIG_MANAGER_ALREADY_INITIALIZED: "ConfigManager is already initialized"
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
exports.ERROR_CODE = ERROR_CODE;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ISO8601_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
4
|
+
function parseJson(data) {
|
|
5
|
+
try {
|
|
6
|
+
return JSON.parse(data, dateReviver);
|
|
7
|
+
} catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function stringifyJson(value, replacer, space) {
|
|
12
|
+
return JSON.stringify(value, replacer, space);
|
|
13
|
+
}
|
|
14
|
+
function safeStringifyJson(value) {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
} catch {
|
|
18
|
+
return "[Circular or Non-Serializable Object]";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function dateReviver(_, value) {
|
|
22
|
+
if (typeof value === "string" && ISO8601_REGEX.test(value)) {
|
|
23
|
+
const date = new Date(value);
|
|
24
|
+
if (!Number.isNaN(date.getTime())) {
|
|
25
|
+
return date;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.parseJson = parseJson;
|
|
32
|
+
exports.safeStringifyJson = safeStringifyJson;
|
|
33
|
+
exports.stringifyJson = stringifyJson;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { a as Logger } from './conduithub.B7aryjPG.js';
|
|
2
|
+
|
|
3
|
+
interface EventData<T extends string, P> {
|
|
4
|
+
type: T;
|
|
5
|
+
payload: P;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
source: string;
|
|
8
|
+
context?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface EventBusOptions<EM extends Record<string, unknown>> {
|
|
12
|
+
readonly logger?: Logger;
|
|
13
|
+
readonly maxHandlersPerEvent?: number;
|
|
14
|
+
readonly handlerTimeoutMs?: number;
|
|
15
|
+
readonly onError?: (err: unknown, eventType: keyof EM) => void;
|
|
16
|
+
}
|
|
17
|
+
interface EventBusStats<EM extends Record<string, unknown>> {
|
|
18
|
+
readonly totalEvents: number;
|
|
19
|
+
readonly totalListeners: number;
|
|
20
|
+
readonly eventNames: (keyof EM)[];
|
|
21
|
+
readonly listenerCount: Record<keyof EM, number>;
|
|
22
|
+
}
|
|
23
|
+
declare class EventBus<EM extends Record<string, unknown>> {
|
|
24
|
+
private readonly handlers;
|
|
25
|
+
private readonly locks;
|
|
26
|
+
private initialized;
|
|
27
|
+
private readonly logger;
|
|
28
|
+
private readonly maxHandlersPerEvent;
|
|
29
|
+
private readonly handlerTimeoutMs;
|
|
30
|
+
private readonly onError?;
|
|
31
|
+
constructor(options?: EventBusOptions<EM>);
|
|
32
|
+
private withEventLock;
|
|
33
|
+
private ensureInitialized;
|
|
34
|
+
private sanitizeLog;
|
|
35
|
+
initialize(): Promise<void>;
|
|
36
|
+
shutdown(): Promise<void>;
|
|
37
|
+
private getTotalHandlerCount;
|
|
38
|
+
private clearAllHandlers;
|
|
39
|
+
on<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>, context?: Record<string, unknown>, signal?: AbortSignal) => Promise<void> | void, priority?: number, customId?: string): string;
|
|
40
|
+
once<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>, context?: Record<string, unknown>, signal?: AbortSignal) => Promise<void> | void, priority?: number, customId?: string): string;
|
|
41
|
+
private registerHandler;
|
|
42
|
+
off<K extends keyof EM>(type: K, id?: string): void;
|
|
43
|
+
emit<K extends keyof EM>(type: K, payload: EM[K], source?: string, context?: Record<string, unknown>): Promise<void>;
|
|
44
|
+
removeAllListeners<K extends keyof EM>(type?: K): void;
|
|
45
|
+
listenerCount<K extends keyof EM>(type: K): number;
|
|
46
|
+
eventNames(): Array<keyof EM>;
|
|
47
|
+
getStats(): EventBusStats<EM>;
|
|
48
|
+
get isInitialized(): boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { EventBus as E };
|
|
52
|
+
export type { EventData as a };
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class PluginManager {
|
|
4
|
+
constructor(eventBus, logger, serviceContainer, stateManager, hookSystem, configManager) {
|
|
5
|
+
this.eventBus = eventBus;
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
this.serviceContainer = serviceContainer;
|
|
8
|
+
this.stateManager = stateManager;
|
|
9
|
+
this.hookSystem = hookSystem;
|
|
10
|
+
this.configManager = configManager;
|
|
11
|
+
}
|
|
12
|
+
plugins = /* @__PURE__ */ new Map();
|
|
13
|
+
pluginStatuses = /* @__PURE__ */ new Map();
|
|
14
|
+
pluginConfigs = /* @__PURE__ */ new Map();
|
|
15
|
+
log(level, message, ...args) {
|
|
16
|
+
const l = this.logger;
|
|
17
|
+
if (l && typeof l.log === "function") {
|
|
18
|
+
l.log(level, message, ...args);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const anyLogger = l;
|
|
22
|
+
const fn = anyLogger?.[level];
|
|
23
|
+
if (typeof fn === "function") fn(message, ...args);
|
|
24
|
+
}
|
|
25
|
+
async registerPlugin(plugin, config) {
|
|
26
|
+
const pluginName = plugin.constructor.name;
|
|
27
|
+
if (this.plugins.has(pluginName)) {
|
|
28
|
+
throw new Error(`Plugin ${pluginName} already registered`);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const existing = this.pluginConfigs.get(pluginName) ?? await this.configManager.getPluginConfig(pluginName);
|
|
32
|
+
const metaVersion = plugin.getMetadata().version;
|
|
33
|
+
const pluginConfig = {
|
|
34
|
+
name: pluginName,
|
|
35
|
+
version: config?.version ?? existing?.version ?? metaVersion,
|
|
36
|
+
enabled: config?.enabled ?? existing?.enabled ?? true,
|
|
37
|
+
dependencies: config?.dependencies ?? existing?.dependencies ?? [],
|
|
38
|
+
config: { ...existing?.config ?? {}, ...config?.config ?? {} }
|
|
39
|
+
};
|
|
40
|
+
plugin.updateConfig(pluginConfig);
|
|
41
|
+
this.plugins.set(pluginName, plugin);
|
|
42
|
+
this.pluginConfigs.set(pluginName, pluginConfig);
|
|
43
|
+
this.pluginStatuses.set(pluginName, {
|
|
44
|
+
name: pluginName,
|
|
45
|
+
version: pluginConfig.version,
|
|
46
|
+
status: "registered",
|
|
47
|
+
config: pluginConfig,
|
|
48
|
+
lastActivity: Date.now()
|
|
49
|
+
});
|
|
50
|
+
this.log("info", `Plugin ${pluginName} registered successfully`);
|
|
51
|
+
await this.hookSystem.executeHook("plugin:registered", {
|
|
52
|
+
plugin: pluginName,
|
|
53
|
+
config: pluginConfig
|
|
54
|
+
});
|
|
55
|
+
await this.eventBus.emit("plugin:registered", {
|
|
56
|
+
plugin: pluginName,
|
|
57
|
+
config: pluginConfig
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
this.log("error", `Failed to register plugin ${pluginName}`, error);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async unregisterPlugin(pluginName) {
|
|
65
|
+
const plugin = this.plugins.get(pluginName);
|
|
66
|
+
if (!plugin) {
|
|
67
|
+
throw new Error(`Plugin ${pluginName} is not registered`);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
if (plugin.isPluginRunning()) {
|
|
71
|
+
await this.stopPlugin(pluginName);
|
|
72
|
+
}
|
|
73
|
+
if (plugin.isPluginInitialized()) {
|
|
74
|
+
await plugin.destroy();
|
|
75
|
+
}
|
|
76
|
+
this.plugins.delete(pluginName);
|
|
77
|
+
this.pluginConfigs.delete(pluginName);
|
|
78
|
+
this.pluginStatuses.delete(pluginName);
|
|
79
|
+
this.log("info", `Plugin ${pluginName} unregistered successfully`);
|
|
80
|
+
await this.eventBus.emit("plugin:unregistered", {
|
|
81
|
+
plugin: pluginName
|
|
82
|
+
});
|
|
83
|
+
await this.hookSystem.executeHook("plugin:unregistered", {
|
|
84
|
+
plugin: pluginName
|
|
85
|
+
});
|
|
86
|
+
} catch (error) {
|
|
87
|
+
this.log("error", `Failed to unregister plugin ${pluginName}`, error);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async initializePlugin(pluginName) {
|
|
92
|
+
const plugin = this.plugins.get(pluginName);
|
|
93
|
+
if (!plugin) {
|
|
94
|
+
throw new Error(`Plugin ${pluginName} is not registered`);
|
|
95
|
+
}
|
|
96
|
+
const status = this.pluginStatuses.get(pluginName);
|
|
97
|
+
if (status?.status === "initialized" || status?.status === "running") {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const context = {
|
|
102
|
+
eventBus: this.eventBus,
|
|
103
|
+
logger: this.logger,
|
|
104
|
+
config: this.pluginConfigs.get(pluginName),
|
|
105
|
+
serviceContainer: this.serviceContainer,
|
|
106
|
+
stateManager: this.stateManager,
|
|
107
|
+
hookSystem: this.hookSystem
|
|
108
|
+
};
|
|
109
|
+
await plugin.initialize(context);
|
|
110
|
+
this.pluginStatuses.set(pluginName, {
|
|
111
|
+
...status,
|
|
112
|
+
status: "initialized",
|
|
113
|
+
lastActivity: Date.now()
|
|
114
|
+
});
|
|
115
|
+
this.log("info", `Plugin ${pluginName} initialized successfully`);
|
|
116
|
+
await this.eventBus.emit("plugin:initialized", { plugin: pluginName });
|
|
117
|
+
await this.hookSystem.executeHook("plugin:initialized", {
|
|
118
|
+
plugin: pluginName
|
|
119
|
+
});
|
|
120
|
+
} catch (error) {
|
|
121
|
+
this.log("error", `Failed to initialize plugin ${pluginName}`, error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async startPlugin(pluginName) {
|
|
126
|
+
const plugin = this.plugins.get(pluginName);
|
|
127
|
+
if (!plugin) {
|
|
128
|
+
throw new Error(`Plugin ${pluginName} is not registered`);
|
|
129
|
+
}
|
|
130
|
+
const status = this.pluginStatuses.get(pluginName);
|
|
131
|
+
if (status?.status === "running") {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
if (!plugin.isPluginInitialized()) {
|
|
136
|
+
await this.initializePlugin(pluginName);
|
|
137
|
+
}
|
|
138
|
+
await plugin.start();
|
|
139
|
+
this.pluginStatuses.set(pluginName, {
|
|
140
|
+
...status,
|
|
141
|
+
status: "running",
|
|
142
|
+
lastActivity: Date.now()
|
|
143
|
+
});
|
|
144
|
+
this.log("info", `Plugin ${pluginName} started successfully`);
|
|
145
|
+
await this.eventBus.emit("plugin:started", { plugin: pluginName });
|
|
146
|
+
await this.hookSystem.executeHook("plugin:started", {
|
|
147
|
+
plugin: pluginName
|
|
148
|
+
});
|
|
149
|
+
} catch (error) {
|
|
150
|
+
this.pluginStatuses.set(pluginName, {
|
|
151
|
+
...this.pluginStatuses.get(pluginName),
|
|
152
|
+
status: "error",
|
|
153
|
+
error: error instanceof Error ? error.message : String(error),
|
|
154
|
+
lastActivity: Date.now()
|
|
155
|
+
});
|
|
156
|
+
this.log("error", `Failed to start plugin ${pluginName}`, error);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async stopPlugin(pluginName) {
|
|
161
|
+
const plugin = this.plugins.get(pluginName);
|
|
162
|
+
if (!plugin) {
|
|
163
|
+
throw new Error(`Plugin ${pluginName} is not registered`);
|
|
164
|
+
}
|
|
165
|
+
const status = this.pluginStatuses.get(pluginName);
|
|
166
|
+
if (status?.status !== "running") {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
await plugin.stop();
|
|
171
|
+
this.pluginStatuses.set(pluginName, {
|
|
172
|
+
...status,
|
|
173
|
+
status: "stopped",
|
|
174
|
+
lastActivity: Date.now()
|
|
175
|
+
});
|
|
176
|
+
this.log("info", `Plugin ${pluginName} stopped successfully`);
|
|
177
|
+
await this.eventBus.emit("plugin:stopped", { plugin: pluginName });
|
|
178
|
+
await this.hookSystem.executeHook("plugin:stopped", {
|
|
179
|
+
plugin: pluginName
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
this.pluginStatuses.set(pluginName, {
|
|
183
|
+
...this.pluginStatuses.get(pluginName),
|
|
184
|
+
status: "error",
|
|
185
|
+
error: error instanceof Error ? error.message : String(error),
|
|
186
|
+
lastActivity: Date.now()
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async shutdownAll() {
|
|
191
|
+
this.log("info", "Shutting down all plugins...");
|
|
192
|
+
const shutdownPromises = Array.from(this.plugins.keys()).map(
|
|
193
|
+
async (pluginName) => {
|
|
194
|
+
try {
|
|
195
|
+
await this.unregisterPlugin(pluginName);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
this.log("error", `Failed to shutdown plugin ${pluginName}`, error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
await Promise.all(shutdownPromises);
|
|
202
|
+
this.log("info", "All plugins shutdown successfully");
|
|
203
|
+
}
|
|
204
|
+
isPluginRegistered(pluginName) {
|
|
205
|
+
return this.plugins.has(pluginName);
|
|
206
|
+
}
|
|
207
|
+
isPluginRunning(pluginName) {
|
|
208
|
+
const status = this.pluginStatuses.get(pluginName);
|
|
209
|
+
return status?.status === "running";
|
|
210
|
+
}
|
|
211
|
+
getPluginStatus(pluginName) {
|
|
212
|
+
return this.pluginStatuses.get(pluginName);
|
|
213
|
+
}
|
|
214
|
+
listPlugins() {
|
|
215
|
+
return Array.from(this.plugins.keys());
|
|
216
|
+
}
|
|
217
|
+
getAllPluginStatuses() {
|
|
218
|
+
return Array.from(this.pluginStatuses.values());
|
|
219
|
+
}
|
|
220
|
+
getPlugin(pluginName) {
|
|
221
|
+
return this.plugins.get(pluginName);
|
|
222
|
+
}
|
|
223
|
+
getPluginConfig(pluginName) {
|
|
224
|
+
return this.pluginConfigs.get(pluginName);
|
|
225
|
+
}
|
|
226
|
+
async updatePluginConfig(pluginName, config) {
|
|
227
|
+
const plugin = this.plugins.get(pluginName);
|
|
228
|
+
if (!plugin) {
|
|
229
|
+
throw new Error(`Plugin ${pluginName} is not registered`);
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const currentConfig = this.pluginConfigs.get(pluginName);
|
|
233
|
+
if (!currentConfig) {
|
|
234
|
+
throw new Error(`Plugin config not found for ${pluginName}`);
|
|
235
|
+
}
|
|
236
|
+
const newConfig = {
|
|
237
|
+
name: currentConfig.name,
|
|
238
|
+
version: config?.version ?? currentConfig.version,
|
|
239
|
+
enabled: config?.enabled ?? currentConfig.enabled,
|
|
240
|
+
dependencies: config?.dependencies ?? currentConfig.dependencies ?? [],
|
|
241
|
+
config: { ...currentConfig.config ?? {}, ...config?.config ?? {} }
|
|
242
|
+
};
|
|
243
|
+
this.pluginConfigs.set(pluginName, newConfig);
|
|
244
|
+
plugin.updateConfig(newConfig);
|
|
245
|
+
const status = this.pluginStatuses.get(pluginName);
|
|
246
|
+
if (status) {
|
|
247
|
+
this.pluginStatuses.set(pluginName, {
|
|
248
|
+
...status,
|
|
249
|
+
config: newConfig,
|
|
250
|
+
lastActivity: Date.now()
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
this.log("info", `Plugin ${pluginName} config updated successfully`);
|
|
254
|
+
await this.eventBus.emit("plugin:configUpdated", {
|
|
255
|
+
plugin: pluginName,
|
|
256
|
+
config: newConfig
|
|
257
|
+
});
|
|
258
|
+
await this.hookSystem.executeHook("plugin:configUpdated", {
|
|
259
|
+
plugin: pluginName,
|
|
260
|
+
config: newConfig
|
|
261
|
+
});
|
|
262
|
+
} catch (error) {
|
|
263
|
+
this.log("error", `Failed to update plugin ${pluginName} config`, error);
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
exports.PluginManager = PluginManager;
|