{"version":3,"file":"index.cjs","names":["Hash","Effect","PluginRuntimeError","effect","Exit","Cause","Option","PluginService","ManagedRuntime"],"sources":["../../src/runtime/index.ts"],"sourcesContent":["import { createRouterClient } from \"@orpc/server\";\nimport { Cause, Effect, Exit, Hash, ManagedRuntime, Option } from \"effect\";\nimport type {\n  AnyPlugin,\n  AnyPluginConstructor,\n  InferRegistryFromEntries,\n  InitializedPlugin,\n  LoadedPlugin,\n  PluginConfigInput,\n  PluginInstance,\n  PluginRegistry,\n  PluginRegistryEntry,\n  PluginRouterType,\n  PluginRuntimeConfig,\n  RegisteredPlugin,\n  RegisteredPlugins,\n  UsePluginResult,\n} from \"../types\";\nimport { PluginRuntimeError } from \"./errors\";\nimport { PluginService } from \"./services/plugin.service\";\n\nexport class PluginRuntime<R = RegisteredPlugins> {\n  readonly __registryType?: R;\n\n  private pluginCache = new Map<\n    string,\n    Effect.Effect<InitializedPlugin<AnyPlugin>, PluginRuntimeError>\n  >();\n\n  constructor(\n    private runtime: ManagedRuntime.ManagedRuntime<PluginService, never>,\n    private registry: PluginRegistry,\n  ) {}\n\n  private generateCacheKey(pluginId: string, config: unknown): string {\n    const configHash = Hash.structure(config as object).toString();\n    return `${pluginId}:${configHash}`;\n  }\n\n  private validatePluginId(pluginId: string): Effect.Effect<string, PluginRuntimeError> {\n    if (!(pluginId in this.registry)) {\n      return Effect.fail(\n        new PluginRuntimeError({\n          pluginId: String(pluginId),\n          operation: \"validate-plugin-id\",\n          cause: new Error(`Plugin ID '${String(pluginId)}' not found in registry.`),\n          retryable: false,\n        }),\n      );\n    }\n    return Effect.succeed(String(pluginId));\n  }\n\n  private async runPromise<A, E>(effect: Effect.Effect<A, E, PluginService>): Promise<A> {\n    const exit = await this.runtime.runPromiseExit(effect);\n\n    if (Exit.isFailure(exit)) {\n      const error = Cause.failureOption(exit.cause);\n      if (Option.isSome(error)) {\n        throw error.value;\n      }\n      throw Cause.squash(exit.cause);\n    }\n\n    return exit.value;\n  }\n\n  async usePlugin<K extends keyof R & string>(\n    pluginId: K,\n    config: PluginConfigInput<R[K]>,\n    plugins?: Record<string, unknown>,\n  ): Promise<UsePluginResult<K, R>> {\n    const cacheKey = this.generateCacheKey(pluginId, { ...config, __plugins: plugins ?? {} });\n\n    let cachedPlugin = this.pluginCache.get(cacheKey);\n    if (!cachedPlugin) {\n      const operation = Effect.gen(this, function* () {\n        const pluginService = yield* PluginService;\n        const validatedId = yield* this.validatePluginId(pluginId);\n\n        // Load → Instantiate → Initialize → Register\n        const ctor = yield* pluginService.loadPlugin(validatedId);\n        const instance = yield* pluginService.instantiatePlugin(pluginId, ctor);\n        const initialized = yield* pluginService.initializePlugin(instance, config, plugins);\n        yield* pluginService.registerPlugin(initialized);\n\n        return initialized;\n      }).pipe(Effect.annotateLogs({ plugin: pluginId }), Effect.provide(this.runtime));\n\n      cachedPlugin = Effect.cached(operation).pipe(Effect.flatten);\n      this.pluginCache.set(cacheKey, cachedPlugin);\n    }\n\n    let initialized: InitializedPlugin<AnyPlugin>;\n    try {\n      initialized = await this.runPromise(cachedPlugin);\n    } catch (error) {\n      // Evict failed initializations so the next call retries instead\n      // of returning the permanently-cached failure from Effect.cached.\n      this.pluginCache.delete(cacheKey);\n      throw error;\n    }\n\n    // Construct the router once per plugin instance, not per client/request.\n    const router = initialized.plugin.createRouter(initialized.context) as PluginRouterType<R[K]>;\n\n    // Create client factory that accepts request context\n    const createClient = (context?: any) => createRouterClient(router, { context: context ?? {} });\n\n    return {\n      createClient: createClient as any,\n      router,\n      metadata: initialized.metadata,\n      initialized: initialized as InitializedPlugin<RegisteredPlugin<K, R>>,\n    } as UsePluginResult<K, R>;\n  }\n\n  async loadPlugin<K extends keyof R & string>(\n    pluginId: K,\n  ): Promise<LoadedPlugin<RegisteredPlugin<K, R>>> {\n    const effect = Effect.gen(function* () {\n      const pluginService = yield* PluginService;\n      return yield* pluginService.loadPlugin(pluginId);\n    }).pipe(Effect.annotateLogs({ plugin: pluginId }));\n    return this.runPromise(effect) as Promise<LoadedPlugin<RegisteredPlugin<K, R>>>;\n  }\n\n  async instantiatePlugin<K extends keyof R & string>(\n    pluginId: K,\n    loadedPlugin: LoadedPlugin<RegisteredPlugin<K, R>>,\n  ): Promise<PluginInstance<RegisteredPlugin<K, R>>> {\n    const effect = Effect.gen(function* () {\n      const pluginService = yield* PluginService;\n      return yield* pluginService.instantiatePlugin(pluginId, loadedPlugin);\n    }).pipe(Effect.annotateLogs({ plugin: pluginId }));\n    return this.runPromise(effect) as Promise<PluginInstance<RegisteredPlugin<K, R>>>;\n  }\n\n  async initializePlugin<T extends AnyPlugin>(\n    instance: PluginInstance<T>,\n    config: any,\n    plugins?: Record<string, unknown>,\n  ): Promise<InitializedPlugin<T>> {\n    const effect = Effect.gen(function* () {\n      const pluginService = yield* PluginService;\n      const initialized = yield* pluginService.initializePlugin(instance, config, plugins);\n      yield* pluginService.registerPlugin(initialized);\n      return initialized;\n    }).pipe(Effect.annotateLogs({ plugin: instance.plugin.id }));\n    return this.runPromise(effect);\n  }\n\n  async shutdown(): Promise<void> {\n    const effect = Effect.gen(function* () {\n      const pluginService = yield* PluginService;\n      yield* pluginService.cleanup();\n    });\n    await this.runPromise(effect);\n    await this.runtime.dispose();\n  }\n\n  async evictPlugin<K extends keyof R & string>(\n    pluginId: K,\n    config: PluginConfigInput<R[K]>,\n    plugins?: Record<string, unknown>,\n  ): Promise<void> {\n    const cacheKey = this.generateCacheKey(pluginId, { ...config, __plugins: plugins ?? {} });\n\n    const effect = Effect.gen(this, function* () {\n      const pluginService = yield* PluginService;\n      const cachedPlugin = this.pluginCache.get(cacheKey);\n\n      if (cachedPlugin) {\n        this.pluginCache.delete(cacheKey);\n\n        const pluginResult = yield* cachedPlugin.pipe(Effect.catchAll(() => Effect.succeed(null)));\n\n        if (pluginResult) {\n          yield* pluginService\n            .shutdownPlugin(pluginResult)\n            .pipe(\n              Effect.catchAll((error) =>\n                Effect.logWarning(`Failed to shutdown evicted plugin ${pluginId}`, error),\n              ),\n            );\n        }\n      }\n    }).pipe(\n      Effect.catchAll((error) =>\n        Effect.logWarning(`Plugin eviction failed for ${pluginId}`, error),\n      ),\n    );\n\n    return this.runPromise(effect);\n  }\n}\n\n/**\n * Normalizes a remote URL to ensure it points to remoteEntry.js\n * If the URL doesn't end with a file extension, appends /remoteEntry.js\n */\nfunction normalizeRemoteUrl(url: string): string {\n  if (!url) return url;\n  if (url.endsWith(\".js\") || url.endsWith(\".json\")) return url;\n  return `${url.endsWith(\"/\") ? url.slice(0, -1) : url}/remoteEntry.js`;\n}\n\n/**\n * Extract plugin map (module constructors) from registry entries\n */\nfunction extractPluginMap(\n  registry: Record<string, PluginRegistryEntry>,\n): Record<string, AnyPluginConstructor> {\n  const pluginMap: Record<string, AnyPluginConstructor> = {};\n\n  for (const [pluginId, entry] of Object.entries(registry)) {\n    if (\"module\" in entry && entry.module) {\n      pluginMap[pluginId] = entry.module;\n    }\n  }\n\n  return pluginMap;\n}\n\n/**\n * Normalize registry entries - ensure remote URLs are properly formatted\n */\nfunction normalizeRegistry(registry: Record<string, PluginRegistryEntry>): PluginRegistry {\n  const normalized: Record<string, PluginRegistryEntry> = {};\n\n  for (const [pluginId, entry] of Object.entries(registry)) {\n    if (\"module\" in entry) {\n      normalized[pluginId] = {\n        ...entry,\n        remote: entry.remote ? normalizeRemoteUrl(entry.remote) : undefined,\n      };\n    } else {\n      normalized[pluginId] = {\n        ...entry,\n        remote: normalizeRemoteUrl(entry.remote),\n      };\n    }\n  }\n\n  return normalized as PluginRegistry;\n}\n\n/**\n * Creates a plugin runtime with support for both module and remote plugin entries.\n *\n * @example\n * ```typescript\n * // With module entries (types inferred automatically)\n * const runtime = createPluginRuntime({\n *   registry: {\n *     telegram: { module: TelegramPlugin },\n *     gopher: { remote: \"https://cdn.example.com/gopher/remoteEntry.js\" }\n *   },\n *   secrets: { API_KEY: \"...\" }\n * });\n *\n * // Types are automatically inferred from module entries!\n * const { router } = await runtime.usePlugin(\"telegram\", config);\n * ```\n */\nexport function createPluginRuntime<TRegistry extends Record<string, PluginRegistryEntry>>(\n  config: PluginRuntimeConfig<TRegistry>,\n): PluginRuntime<InferRegistryFromEntries<TRegistry>> {\n  const secrets = config.secrets || {};\n  const normalizedRegistry = normalizeRegistry(config.registry);\n  const pluginMap = extractPluginMap(config.registry);\n\n  const layer = PluginService.Live(normalizedRegistry, secrets, pluginMap);\n  const runtime = ManagedRuntime.make(layer);\n\n  return new PluginRuntime(runtime, normalizedRegistry) as PluginRuntime<\n    InferRegistryFromEntries<TRegistry>\n  >;\n}\n"],"mappings":"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"}