UNPKG

every-plugin

Version:
165 lines (163 loc) 6.41 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const require_runtime = require('../_virtual/_rolldown/runtime.cjs'); const require_errors = require('./errors.cjs'); const require_plugin_service = require('./services/plugin.service.cjs'); let effect = require("effect"); let _orpc_server = require("@orpc/server"); //#region src/runtime/index.ts var PluginRuntime = class { __registryType; pluginCache = /* @__PURE__ */ new Map(); constructor(runtime, registry) { this.runtime = runtime; this.registry = registry; } generateCacheKey(pluginId, config) { return `${pluginId}:${effect.Hash.structure(config).toString()}`; } validatePluginId(pluginId) { if (!(pluginId in this.registry)) return effect.Effect.fail(new require_errors.PluginRuntimeError({ pluginId: String(pluginId), operation: "validate-plugin-id", cause: /* @__PURE__ */ new Error(`Plugin ID '${String(pluginId)}' not found in registry.`), retryable: false })); return effect.Effect.succeed(String(pluginId)); } async runPromise(effect$1) { const exit = await this.runtime.runPromiseExit(effect$1); if (effect.Exit.isFailure(exit)) { const error = effect.Cause.failureOption(exit.cause); if (effect.Option.isSome(error)) throw error.value; throw effect.Cause.squash(exit.cause); } return exit.value; } async usePlugin(pluginId, config, plugins) { const cacheKey = this.generateCacheKey(pluginId, { ...config, __plugins: plugins ?? {} }); let cachedPlugin = this.pluginCache.get(cacheKey); if (!cachedPlugin) { const operation = effect.Effect.gen(this, function* () { const pluginService = yield* require_plugin_service.PluginService; const validatedId = yield* this.validatePluginId(pluginId); const ctor = yield* pluginService.loadPlugin(validatedId); const instance = yield* pluginService.instantiatePlugin(pluginId, ctor); return yield* pluginService.initializePlugin(instance, config, plugins); }).pipe(effect.Effect.provide(this.runtime)); cachedPlugin = effect.Effect.cached(operation).pipe(effect.Effect.flatten); this.pluginCache.set(cacheKey, cachedPlugin); } const initialized = await this.runPromise(cachedPlugin); const createClient = (context) => { return (0, _orpc_server.createRouterClient)(initialized.plugin.createRouter(initialized.context), { context: context ?? {} }); }; return { createClient, router: initialized.plugin.createRouter(initialized.context), metadata: initialized.metadata, initialized }; } async loadPlugin(pluginId) { const effect$2 = effect.Effect.gen(function* () { return yield* (yield* require_plugin_service.PluginService).loadPlugin(pluginId); }); return this.runPromise(effect$2); } async instantiatePlugin(pluginId, loadedPlugin) { const effect$3 = effect.Effect.gen(function* () { return yield* (yield* require_plugin_service.PluginService).instantiatePlugin(pluginId, loadedPlugin); }); return this.runPromise(effect$3); } async initializePlugin(instance, config, plugins) { const effect$4 = effect.Effect.gen(function* () { return yield* (yield* require_plugin_service.PluginService).initializePlugin(instance, config, plugins); }); return this.runPromise(effect$4); } async shutdown() { const effect$5 = effect.Effect.gen(function* () { yield* (yield* require_plugin_service.PluginService).cleanup(); }); await this.runPromise(effect$5); await this.runtime.dispose(); } async evictPlugin(pluginId, config) { const cacheKey = this.generateCacheKey(pluginId, config); const effect$6 = effect.Effect.gen(this, function* () { const pluginService = yield* require_plugin_service.PluginService; const cachedPlugin = this.pluginCache.get(cacheKey); if (cachedPlugin) { this.pluginCache.delete(cacheKey); const pluginResult = yield* cachedPlugin.pipe(effect.Effect.catchAll(() => effect.Effect.succeed(null))); if (pluginResult) yield* pluginService.shutdownPlugin(pluginResult).pipe(effect.Effect.catchAll((error) => effect.Effect.logWarning(`Failed to shutdown evicted plugin ${pluginId}`, error))); } }).pipe(effect.Effect.catchAll((error) => effect.Effect.logWarning(`Plugin eviction failed for ${pluginId}`, error))); return this.runPromise(effect$6); } }; /** * Normalizes a remote URL to ensure it points to remoteEntry.js * If the URL doesn't end with a file extension, appends /remoteEntry.js */ function normalizeRemoteUrl(url) { if (!url) return url; if (url.endsWith(".js") || url.endsWith(".json")) return url; return `${url.endsWith("/") ? url.slice(0, -1) : url}/remoteEntry.js`; } /** * Extract plugin map (module constructors) from registry entries */ function extractPluginMap(registry) { const pluginMap = {}; for (const [pluginId, entry] of Object.entries(registry)) if ("module" in entry && entry.module) pluginMap[pluginId] = entry.module; return pluginMap; } /** * Normalize registry entries - ensure remote URLs are properly formatted */ function normalizeRegistry(registry) { const normalized = {}; for (const [pluginId, entry] of Object.entries(registry)) if ("module" in entry) normalized[pluginId] = { ...entry, remote: entry.remote ? normalizeRemoteUrl(entry.remote) : void 0 }; else normalized[pluginId] = { ...entry, remote: normalizeRemoteUrl(entry.remote) }; return normalized; } /** * Creates a plugin runtime with support for both module and remote plugin entries. * * @example * ```typescript * // With module entries (types inferred automatically) * const runtime = createPluginRuntime({ * registry: { * telegram: { module: TelegramPlugin }, * gopher: { remote: "https://cdn.example.com/gopher/remoteEntry.js" } * }, * secrets: { API_KEY: "..." } * }); * * // Types are automatically inferred from module entries! * const { router } = await runtime.usePlugin("telegram", config); * ``` */ function createPluginRuntime(config) { const secrets = config.secrets || {}; const normalizedRegistry = normalizeRegistry(config.registry); const pluginMap = extractPluginMap(config.registry); const layer = require_plugin_service.PluginService.Live(normalizedRegistry, secrets, pluginMap); return new PluginRuntime(effect.ManagedRuntime.make(layer), normalizedRegistry); } //#endregion exports.PluginRuntime = PluginRuntime; exports.createPluginRuntime = createPluginRuntime; //# sourceMappingURL=index.cjs.map