every-plugin 2.5.3 → 2.5.5

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.
@@ -74,7 +74,9 @@ function setupPluginMiddleware(devServer, pluginInfo, devConfig, port) {
74
74
  console.error("❌ Failed to load plugin:", error);
75
75
  await performCleanup();
76
76
  }
77
- })();
77
+ })().catch((err) => {
78
+ console.error("❌ Plugin dev server fatal error:", err);
79
+ });
78
80
  process.once("SIGINT", async () => {
79
81
  const timeout = setTimeout(() => process.exit(0), 3e3);
80
82
  await performCleanup();
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server-middleware.cjs","names":[],"sources":["../../../src/build/rspack/dev-server-middleware.ts"],"sourcesContent":["import type { PluginInfo } from \"./utils\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, PATCH, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"X-Requested-With, content-type, Authorization\",\n};\n\nconst applyCorsHeaders = (res: any) => {\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n};\n\nconst normalizePrefix = (prefix?: string): string => {\n if (!prefix) return \"\";\n const cleaned = prefix.replace(/^\\/+|\\/+$/g, \"\");\n return cleaned ? `/${cleaned}` : \"\";\n};\n\nexport function setupPluginMiddleware(\n devServer: any,\n pluginInfo: PluginInfo,\n devConfig: any,\n port: number,\n) {\n const rpcPrefix = normalizePrefix(devConfig?.prefix);\n const handlers: { rpc: any; api: any } = { rpc: null, api: null };\n let cleanup: (() => Promise<void>) | null = null;\n\n const performCleanup = async () => {\n if (cleanup) {\n await cleanup();\n cleanup = null;\n }\n };\n\n (async () => {\n await performCleanup();\n\n try {\n const { createPluginRuntime } = await import(\"every-plugin\");\n const { RPCHandler } = await import(\"@orpc/server/fetch\");\n const { OpenAPIHandler } = await import(\"@orpc/openapi/fetch\");\n const { OpenAPIReferencePlugin } = await import(\"@orpc/openapi/plugins\");\n const { ZodToJsonSchemaConverter } = await import(\"@orpc/zod/zod4\");\n const { onError } = await import(\"every-plugin/orpc\");\n const { formatORPCError } = await import(\"every-plugin/errors\");\n\n const pluginId = devConfig?.pluginId || pluginInfo.normalizedName;\n\n const runtime = createPluginRuntime({\n registry: {\n [pluginId]: {\n remote: `http://localhost:${port}/remoteEntry.js`,\n },\n },\n });\n\n const defaultConfig = { variables: {}, secrets: {} };\n\n // @ts-expect-error we don't know the plugin id\n const loaded = await runtime.usePlugin(pluginId, (devConfig?.config ?? defaultConfig) as any);\n\n cleanup = async () => {\n if (runtime) await runtime.shutdown();\n handlers.rpc = null;\n handlers.api = null;\n if (devServer.app.locals.handlers) {\n devServer.app.locals.handlers = null;\n }\n };\n\n handlers.rpc = new RPCHandler(loaded.router, {\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n handlers.api = new OpenAPIHandler(loaded.router, {\n plugins: [\n new OpenAPIReferencePlugin({\n schemaConverters: [new ZodToJsonSchemaConverter()],\n }),\n ],\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n console.log(`╭─────────────────────────────────────────────`);\n console.log(`│ ✅ Plugin dev server ready: `);\n console.log(`├─────────────────────────────────────────────`);\n console.log(`│ 📡 RPC: http://localhost:${port}/api/rpc${rpcPrefix}`);\n console.log(`│ 📖 Docs: http://localhost:${port}/api`);\n console.log(`│ 💚 Health: http://localhost:${port}/`);\n console.log(`╰─────────────────────────────────────────────`);\n\n devServer.app.locals.handlers = handlers;\n\n if (devServer.server) {\n devServer.server.once(\"close\", async () => {\n await performCleanup();\n });\n }\n } catch (error) {\n console.error(\"❌ Failed to load plugin:\", error);\n await performCleanup();\n }\n })();\n\n process.once(\"SIGINT\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n process.once(\"SIGTERM\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n\n devServer.app.options(\"*\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).end();\n });\n\n devServer.app.get(\"/\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.json({\n ok: true,\n plugin: pluginInfo.normalizedName,\n version: pluginInfo.version,\n status: devServer.app.locals.handlers?.rpc ? \"ready\" : \"loading\",\n endpoints: {\n health: \"/\",\n docs: \"/api\",\n rpc: `/api/rpc${rpcPrefix}`,\n },\n });\n });\n\n devServer.app.get(\"/health\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).send(\"OK\");\n });\n\n const handleApiRequest = async (req: any, res: any) => {\n applyCorsHeaders(res);\n const apiHandler = devServer.app.locals.handlers?.api;\n if (!apiHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await apiHandler.handle(webRequest, {\n prefix: \"/api\",\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"OpenAPI error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n };\n\n devServer.app.all(`/api/rpc${rpcPrefix}/*`, async (req: any, res: any) => {\n applyCorsHeaders(res);\n const rpcHandler = devServer.app.locals.handlers?.rpc;\n if (!rpcHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await rpcHandler.handle(webRequest, {\n prefix: `/api/rpc${rpcPrefix}`,\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"RPC error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n devServer.app.all(\"/api\", handleApiRequest);\n devServer.app.all(\"/api/*\", handleApiRequest);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dev-server-middleware.cjs","names":[],"sources":["../../../src/build/rspack/dev-server-middleware.ts"],"sourcesContent":["import type { PluginInfo } from \"./utils\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, PATCH, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"X-Requested-With, content-type, Authorization\",\n};\n\nconst applyCorsHeaders = (res: any) => {\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n};\n\nconst normalizePrefix = (prefix?: string): string => {\n if (!prefix) return \"\";\n const cleaned = prefix.replace(/^\\/+|\\/+$/g, \"\");\n return cleaned ? `/${cleaned}` : \"\";\n};\n\nexport function setupPluginMiddleware(\n devServer: any,\n pluginInfo: PluginInfo,\n devConfig: any,\n port: number,\n) {\n const rpcPrefix = normalizePrefix(devConfig?.prefix);\n const handlers: { rpc: any; api: any } = { rpc: null, api: null };\n let cleanup: (() => Promise<void>) | null = null;\n\n const performCleanup = async () => {\n if (cleanup) {\n await cleanup();\n cleanup = null;\n }\n };\n\n (async () => {\n await performCleanup();\n\n try {\n const { createPluginRuntime } = await import(\"every-plugin\");\n const { RPCHandler } = await import(\"@orpc/server/fetch\");\n const { OpenAPIHandler } = await import(\"@orpc/openapi/fetch\");\n const { OpenAPIReferencePlugin } = await import(\"@orpc/openapi/plugins\");\n const { ZodToJsonSchemaConverter } = await import(\"@orpc/zod/zod4\");\n const { onError } = await import(\"every-plugin/orpc\");\n const { formatORPCError } = await import(\"every-plugin/errors\");\n\n const pluginId = devConfig?.pluginId || pluginInfo.normalizedName;\n\n const runtime = createPluginRuntime({\n registry: {\n [pluginId]: {\n remote: `http://localhost:${port}/remoteEntry.js`,\n },\n },\n });\n\n const defaultConfig = { variables: {}, secrets: {} };\n\n // @ts-expect-error we don't know the plugin id\n const loaded = await runtime.usePlugin(pluginId, (devConfig?.config ?? defaultConfig) as any);\n\n cleanup = async () => {\n if (runtime) await runtime.shutdown();\n handlers.rpc = null;\n handlers.api = null;\n if (devServer.app.locals.handlers) {\n devServer.app.locals.handlers = null;\n }\n };\n\n handlers.rpc = new RPCHandler(loaded.router, {\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n handlers.api = new OpenAPIHandler(loaded.router, {\n plugins: [\n new OpenAPIReferencePlugin({\n schemaConverters: [new ZodToJsonSchemaConverter()],\n }),\n ],\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n console.log(`╭─────────────────────────────────────────────`);\n console.log(`│ ✅ Plugin dev server ready: `);\n console.log(`├─────────────────────────────────────────────`);\n console.log(`│ 📡 RPC: http://localhost:${port}/api/rpc${rpcPrefix}`);\n console.log(`│ 📖 Docs: http://localhost:${port}/api`);\n console.log(`│ 💚 Health: http://localhost:${port}/`);\n console.log(`╰─────────────────────────────────────────────`);\n\n devServer.app.locals.handlers = handlers;\n\n if (devServer.server) {\n devServer.server.once(\"close\", async () => {\n await performCleanup();\n });\n }\n } catch (error) {\n console.error(\"❌ Failed to load plugin:\", error);\n await performCleanup();\n }\n })().catch((err) => {\n console.error(\"❌ Plugin dev server fatal error:\", err);\n });\n\n process.once(\"SIGINT\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n process.once(\"SIGTERM\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n\n devServer.app.options(\"*\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).end();\n });\n\n devServer.app.get(\"/\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.json({\n ok: true,\n plugin: pluginInfo.normalizedName,\n version: pluginInfo.version,\n status: devServer.app.locals.handlers?.rpc ? \"ready\" : \"loading\",\n endpoints: {\n health: \"/\",\n docs: \"/api\",\n rpc: `/api/rpc${rpcPrefix}`,\n },\n });\n });\n\n devServer.app.get(\"/health\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).send(\"OK\");\n });\n\n const handleApiRequest = async (req: any, res: any) => {\n applyCorsHeaders(res);\n const apiHandler = devServer.app.locals.handlers?.api;\n if (!apiHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await apiHandler.handle(webRequest, {\n prefix: \"/api\",\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"OpenAPI error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n };\n\n devServer.app.all(`/api/rpc${rpcPrefix}/*`, async (req: any, res: any) => {\n applyCorsHeaders(res);\n const rpcHandler = devServer.app.locals.handlers?.rpc;\n if (!rpcHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await rpcHandler.handle(webRequest, {\n prefix: `/api/rpc${rpcPrefix}`,\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"RPC error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n devServer.app.all(\"/api\", handleApiRequest);\n devServer.app.all(\"/api/*\", handleApiRequest);\n}\n"],"mappings":"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"}
@@ -73,7 +73,9 @@ function setupPluginMiddleware(devServer, pluginInfo, devConfig, port) {
73
73
  console.error("❌ Failed to load plugin:", error);
74
74
  await performCleanup();
75
75
  }
76
- })();
76
+ })().catch((err) => {
77
+ console.error("❌ Plugin dev server fatal error:", err);
78
+ });
77
79
  process.once("SIGINT", async () => {
78
80
  const timeout = setTimeout(() => process.exit(0), 3e3);
79
81
  await performCleanup();
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server-middleware.mjs","names":[],"sources":["../../../src/build/rspack/dev-server-middleware.ts"],"sourcesContent":["import type { PluginInfo } from \"./utils\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, PATCH, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"X-Requested-With, content-type, Authorization\",\n};\n\nconst applyCorsHeaders = (res: any) => {\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n};\n\nconst normalizePrefix = (prefix?: string): string => {\n if (!prefix) return \"\";\n const cleaned = prefix.replace(/^\\/+|\\/+$/g, \"\");\n return cleaned ? `/${cleaned}` : \"\";\n};\n\nexport function setupPluginMiddleware(\n devServer: any,\n pluginInfo: PluginInfo,\n devConfig: any,\n port: number,\n) {\n const rpcPrefix = normalizePrefix(devConfig?.prefix);\n const handlers: { rpc: any; api: any } = { rpc: null, api: null };\n let cleanup: (() => Promise<void>) | null = null;\n\n const performCleanup = async () => {\n if (cleanup) {\n await cleanup();\n cleanup = null;\n }\n };\n\n (async () => {\n await performCleanup();\n\n try {\n const { createPluginRuntime } = await import(\"every-plugin\");\n const { RPCHandler } = await import(\"@orpc/server/fetch\");\n const { OpenAPIHandler } = await import(\"@orpc/openapi/fetch\");\n const { OpenAPIReferencePlugin } = await import(\"@orpc/openapi/plugins\");\n const { ZodToJsonSchemaConverter } = await import(\"@orpc/zod/zod4\");\n const { onError } = await import(\"every-plugin/orpc\");\n const { formatORPCError } = await import(\"every-plugin/errors\");\n\n const pluginId = devConfig?.pluginId || pluginInfo.normalizedName;\n\n const runtime = createPluginRuntime({\n registry: {\n [pluginId]: {\n remote: `http://localhost:${port}/remoteEntry.js`,\n },\n },\n });\n\n const defaultConfig = { variables: {}, secrets: {} };\n\n // @ts-expect-error we don't know the plugin id\n const loaded = await runtime.usePlugin(pluginId, (devConfig?.config ?? defaultConfig) as any);\n\n cleanup = async () => {\n if (runtime) await runtime.shutdown();\n handlers.rpc = null;\n handlers.api = null;\n if (devServer.app.locals.handlers) {\n devServer.app.locals.handlers = null;\n }\n };\n\n handlers.rpc = new RPCHandler(loaded.router, {\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n handlers.api = new OpenAPIHandler(loaded.router, {\n plugins: [\n new OpenAPIReferencePlugin({\n schemaConverters: [new ZodToJsonSchemaConverter()],\n }),\n ],\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n console.log(`╭─────────────────────────────────────────────`);\n console.log(`│ ✅ Plugin dev server ready: `);\n console.log(`├─────────────────────────────────────────────`);\n console.log(`│ 📡 RPC: http://localhost:${port}/api/rpc${rpcPrefix}`);\n console.log(`│ 📖 Docs: http://localhost:${port}/api`);\n console.log(`│ 💚 Health: http://localhost:${port}/`);\n console.log(`╰─────────────────────────────────────────────`);\n\n devServer.app.locals.handlers = handlers;\n\n if (devServer.server) {\n devServer.server.once(\"close\", async () => {\n await performCleanup();\n });\n }\n } catch (error) {\n console.error(\"❌ Failed to load plugin:\", error);\n await performCleanup();\n }\n })();\n\n process.once(\"SIGINT\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n process.once(\"SIGTERM\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n\n devServer.app.options(\"*\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).end();\n });\n\n devServer.app.get(\"/\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.json({\n ok: true,\n plugin: pluginInfo.normalizedName,\n version: pluginInfo.version,\n status: devServer.app.locals.handlers?.rpc ? \"ready\" : \"loading\",\n endpoints: {\n health: \"/\",\n docs: \"/api\",\n rpc: `/api/rpc${rpcPrefix}`,\n },\n });\n });\n\n devServer.app.get(\"/health\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).send(\"OK\");\n });\n\n const handleApiRequest = async (req: any, res: any) => {\n applyCorsHeaders(res);\n const apiHandler = devServer.app.locals.handlers?.api;\n if (!apiHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await apiHandler.handle(webRequest, {\n prefix: \"/api\",\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"OpenAPI error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n };\n\n devServer.app.all(`/api/rpc${rpcPrefix}/*`, async (req: any, res: any) => {\n applyCorsHeaders(res);\n const rpcHandler = devServer.app.locals.handlers?.rpc;\n if (!rpcHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await rpcHandler.handle(webRequest, {\n prefix: `/api/rpc${rpcPrefix}`,\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"RPC error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n devServer.app.all(\"/api\", handleApiRequest);\n devServer.app.all(\"/api/*\", handleApiRequest);\n}\n"],"mappings":";AAEA,MAAM,cAAc;CAClB,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;CACjC;AAED,MAAM,oBAAoB,QAAa;AACrC,QAAO,QAAQ,YAAY,CAAC,SAAS,CAAC,KAAK,WAAW;AACpD,MAAI,UAAU,KAAK,MAAM;GACzB;;AAGJ,MAAM,mBAAmB,WAA4B;AACnD,KAAI,CAAC,OAAQ,QAAO;CACpB,MAAM,UAAU,OAAO,QAAQ,cAAc,GAAG;AAChD,QAAO,UAAU,IAAI,YAAY;;AAGnC,SAAgB,sBACd,WACA,YACA,WACA,MACA;CACA,MAAM,YAAY,gBAAgB,WAAW,OAAO;CACpD,MAAM,WAAmC;EAAE,KAAK;EAAM,KAAK;EAAM;CACjE,IAAI,UAAwC;CAE5C,MAAM,iBAAiB,YAAY;AACjC,MAAI,SAAS;AACX,SAAM,SAAS;AACf,aAAU;;;AAId,EAAC,YAAY;AACX,QAAM,gBAAgB;AAEtB,MAAI;GACF,MAAM,EAAE,wBAAwB,MAAM,OAAO;GAC7C,MAAM,EAAE,eAAe,MAAM,OAAO;GACpC,MAAM,EAAE,mBAAmB,MAAM,OAAO;GACxC,MAAM,EAAE,2BAA2B,MAAM,OAAO;GAChD,MAAM,EAAE,6BAA6B,MAAM,OAAO;GAClD,MAAM,EAAE,YAAY,MAAM,OAAO;GACjC,MAAM,EAAE,oBAAoB,MAAM,OAAO;GAEzC,MAAM,WAAW,WAAW,YAAY,WAAW;GAEnD,MAAM,UAAU,oBAAoB,EAClC,UAAU,GACP,WAAW,EACV,QAAQ,oBAAoB,KAAK,kBAClC,EACF,EACF,CAAC;GAKF,MAAM,SAAS,MAAM,QAAQ,UAAU,UAAW,WAAW,UAHvC;IAAE,WAAW,EAAE;IAAE,SAAS,EAAE;IAAE,CAGyC;AAE7F,aAAU,YAAY;AACpB,QAAI,QAAS,OAAM,QAAQ,UAAU;AACrC,aAAS,MAAM;AACf,aAAS,MAAM;AACf,QAAI,UAAU,IAAI,OAAO,SACvB,WAAU,IAAI,OAAO,WAAW;;AAIpC,YAAS,MAAM,IAAI,WAAW,OAAO,QAAQ,EAC3C,cAAc,CACZ,SAAS,UAAe;AACtB,oBAAgB,MAAM;KACtB,CACH,EACF,CAAC;AAEF,YAAS,MAAM,IAAI,eAAe,OAAO,QAAQ;IAC/C,SAAS,CACP,IAAI,uBAAuB,EACzB,kBAAkB,CAAC,IAAI,0BAA0B,CAAC,EACnD,CAAC,CACH;IACD,cAAc,CACZ,SAAS,UAAe;AACtB,qBAAgB,MAAM;MACtB,CACH;IACF,CAAC;AAEF,WAAQ,IAAI,iDAAiD;AAC7D,WAAQ,IAAI,iCAAiC;AAC7C,WAAQ,IAAI,iDAAiD;AAC7D,WAAQ,IAAI,kCAAkC,KAAK,UAAU,YAAY;AACzE,WAAQ,IAAI,kCAAkC,KAAK,MAAM;AACzD,WAAQ,IAAI,kCAAkC,KAAK,GAAG;AACtD,WAAQ,IAAI,iDAAiD;AAE7D,aAAU,IAAI,OAAO,WAAW;AAEhC,OAAI,UAAU,OACZ,WAAU,OAAO,KAAK,SAAS,YAAY;AACzC,UAAM,gBAAgB;KACtB;WAEG,OAAO;AACd,WAAQ,MAAM,4BAA4B,MAAM;AAChD,SAAM,gBAAgB;;KAEtB;AAEJ,SAAQ,KAAK,UAAU,YAAY;EACjC,MAAM,UAAU,iBAAiB,QAAQ,KAAK,EAAE,EAAE,IAAK;AACvD,QAAM,gBAAgB;AACtB,eAAa,QAAQ;GACrB;AACF,SAAQ,KAAK,WAAW,YAAY;EAClC,MAAM,UAAU,iBAAiB,QAAQ,KAAK,EAAE,EAAE,IAAK;AACvD,QAAM,gBAAgB;AACtB,eAAa,QAAQ;GACrB;AAEF,WAAU,IAAI,QAAQ,MAAM,MAAW,QAAa;AAClD,mBAAiB,IAAI;AACrB,MAAI,OAAO,IAAI,CAAC,KAAK;GACrB;AAEF,WAAU,IAAI,IAAI,MAAM,MAAW,QAAa;AAC9C,mBAAiB,IAAI;AACrB,MAAI,KAAK;GACP,IAAI;GACJ,QAAQ,WAAW;GACnB,SAAS,WAAW;GACpB,QAAQ,UAAU,IAAI,OAAO,UAAU,MAAM,UAAU;GACvD,WAAW;IACT,QAAQ;IACR,MAAM;IACN,KAAK,WAAW;IACjB;GACF,CAAC;GACF;AAEF,WAAU,IAAI,IAAI,YAAY,MAAW,QAAa;AACpD,mBAAiB,IAAI;AACrB,MAAI,OAAO,IAAI,CAAC,KAAK,KAAK;GAC1B;CAEF,MAAM,mBAAmB,OAAO,KAAU,QAAa;AACrD,mBAAiB,IAAI;EACrB,MAAM,aAAa,UAAU,IAAI,OAAO,UAAU;AAClD,MAAI,CAAC,WACH,QAAO,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAGnE,MAAI;GACF,MAAM,MAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;GAC7C,MAAM,aAAa,IAAI,QAAQ,KAAK;IAClC,QAAQ,IAAI;IACZ,SAAS,IAAI;IACb,MAAM,IAAI,WAAW,SAAS,IAAI,WAAW,SAAS,MAAM;IAC5D,QAAQ,IAAI,WAAW,SAAS,IAAI,WAAW,SAAS,SAAS;IAClE,CAAgB;GAEjB,MAAM,SAAS,MAAM,WAAW,OAAO,YAAY;IACjD,QAAQ;IACR,SAAS,EAAE;IACZ,CAAC;AAEF,OAAI,OAAO,UAAU;AACnB,QAAI,OAAO,OAAO,SAAS,OAAO;AAClC,WAAO,SAAS,QAAQ,SAAS,OAAe,QAAgB;AAC9D,SAAI,UAAU,KAAK,MAAM;MACzB;IACF,MAAM,OAAO,MAAM,OAAO,SAAS,MAAM;AACzC,QAAI,KAAK,KAAK;SAEd,KAAI,OAAO,IAAI,CAAC,KAAK,YAAY;WAE5B,OAAO;AACd,WAAQ,MAAM,kBAAkB,MAAM;AACtC,OAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAQ,MAAgB,SAAS,CAAC;;;AAI7D,WAAU,IAAI,IAAI,WAAW,UAAU,KAAK,OAAO,KAAU,QAAa;AACxE,mBAAiB,IAAI;EACrB,MAAM,aAAa,UAAU,IAAI,OAAO,UAAU;AAClD,MAAI,CAAC,WACH,QAAO,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAGnE,MAAI;GACF,MAAM,MAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;GAC7C,MAAM,aAAa,IAAI,QAAQ,KAAK;IAClC,QAAQ,IAAI;IACZ,SAAS,IAAI;IACb,MAAM,IAAI,WAAW,SAAS,IAAI,WAAW,SAAS,MAAM;IAC5D,QAAQ,IAAI,WAAW,SAAS,IAAI,WAAW,SAAS,SAAS;IAClE,CAAgB;GAEjB,MAAM,SAAS,MAAM,WAAW,OAAO,YAAY;IACjD,QAAQ,WAAW;IACnB,SAAS,EAAE;IACZ,CAAC;AAEF,OAAI,OAAO,UAAU;AACnB,QAAI,OAAO,OAAO,SAAS,OAAO;AAClC,WAAO,SAAS,QAAQ,SAAS,OAAe,QAAgB;AAC9D,SAAI,UAAU,KAAK,MAAM;MACzB;IACF,MAAM,OAAO,MAAM,OAAO,SAAS,MAAM;AACzC,QAAI,KAAK,KAAK;SAEd,KAAI,OAAO,IAAI,CAAC,KAAK,YAAY;WAE5B,OAAO;AACd,WAAQ,MAAM,cAAc,MAAM;AAClC,OAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAQ,MAAgB,SAAS,CAAC;;GAE3D;AAEF,WAAU,IAAI,IAAI,QAAQ,iBAAiB;AAC3C,WAAU,IAAI,IAAI,UAAU,iBAAiB"}
1
+ {"version":3,"file":"dev-server-middleware.mjs","names":[],"sources":["../../../src/build/rspack/dev-server-middleware.ts"],"sourcesContent":["import type { PluginInfo } from \"./utils\";\n\nconst corsHeaders = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, PATCH, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"X-Requested-With, content-type, Authorization\",\n};\n\nconst applyCorsHeaders = (res: any) => {\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n};\n\nconst normalizePrefix = (prefix?: string): string => {\n if (!prefix) return \"\";\n const cleaned = prefix.replace(/^\\/+|\\/+$/g, \"\");\n return cleaned ? `/${cleaned}` : \"\";\n};\n\nexport function setupPluginMiddleware(\n devServer: any,\n pluginInfo: PluginInfo,\n devConfig: any,\n port: number,\n) {\n const rpcPrefix = normalizePrefix(devConfig?.prefix);\n const handlers: { rpc: any; api: any } = { rpc: null, api: null };\n let cleanup: (() => Promise<void>) | null = null;\n\n const performCleanup = async () => {\n if (cleanup) {\n await cleanup();\n cleanup = null;\n }\n };\n\n (async () => {\n await performCleanup();\n\n try {\n const { createPluginRuntime } = await import(\"every-plugin\");\n const { RPCHandler } = await import(\"@orpc/server/fetch\");\n const { OpenAPIHandler } = await import(\"@orpc/openapi/fetch\");\n const { OpenAPIReferencePlugin } = await import(\"@orpc/openapi/plugins\");\n const { ZodToJsonSchemaConverter } = await import(\"@orpc/zod/zod4\");\n const { onError } = await import(\"every-plugin/orpc\");\n const { formatORPCError } = await import(\"every-plugin/errors\");\n\n const pluginId = devConfig?.pluginId || pluginInfo.normalizedName;\n\n const runtime = createPluginRuntime({\n registry: {\n [pluginId]: {\n remote: `http://localhost:${port}/remoteEntry.js`,\n },\n },\n });\n\n const defaultConfig = { variables: {}, secrets: {} };\n\n // @ts-expect-error we don't know the plugin id\n const loaded = await runtime.usePlugin(pluginId, (devConfig?.config ?? defaultConfig) as any);\n\n cleanup = async () => {\n if (runtime) await runtime.shutdown();\n handlers.rpc = null;\n handlers.api = null;\n if (devServer.app.locals.handlers) {\n devServer.app.locals.handlers = null;\n }\n };\n\n handlers.rpc = new RPCHandler(loaded.router, {\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n handlers.api = new OpenAPIHandler(loaded.router, {\n plugins: [\n new OpenAPIReferencePlugin({\n schemaConverters: [new ZodToJsonSchemaConverter()],\n }),\n ],\n interceptors: [\n onError((error: any) => {\n formatORPCError(error);\n }),\n ],\n });\n\n console.log(`╭─────────────────────────────────────────────`);\n console.log(`│ ✅ Plugin dev server ready: `);\n console.log(`├─────────────────────────────────────────────`);\n console.log(`│ 📡 RPC: http://localhost:${port}/api/rpc${rpcPrefix}`);\n console.log(`│ 📖 Docs: http://localhost:${port}/api`);\n console.log(`│ 💚 Health: http://localhost:${port}/`);\n console.log(`╰─────────────────────────────────────────────`);\n\n devServer.app.locals.handlers = handlers;\n\n if (devServer.server) {\n devServer.server.once(\"close\", async () => {\n await performCleanup();\n });\n }\n } catch (error) {\n console.error(\"❌ Failed to load plugin:\", error);\n await performCleanup();\n }\n })().catch((err) => {\n console.error(\"❌ Plugin dev server fatal error:\", err);\n });\n\n process.once(\"SIGINT\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n process.once(\"SIGTERM\", async () => {\n const timeout = setTimeout(() => process.exit(0), 3000);\n await performCleanup();\n clearTimeout(timeout);\n });\n\n devServer.app.options(\"*\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).end();\n });\n\n devServer.app.get(\"/\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.json({\n ok: true,\n plugin: pluginInfo.normalizedName,\n version: pluginInfo.version,\n status: devServer.app.locals.handlers?.rpc ? \"ready\" : \"loading\",\n endpoints: {\n health: \"/\",\n docs: \"/api\",\n rpc: `/api/rpc${rpcPrefix}`,\n },\n });\n });\n\n devServer.app.get(\"/health\", (_req: any, res: any) => {\n applyCorsHeaders(res);\n res.status(200).send(\"OK\");\n });\n\n const handleApiRequest = async (req: any, res: any) => {\n applyCorsHeaders(res);\n const apiHandler = devServer.app.locals.handlers?.api;\n if (!apiHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await apiHandler.handle(webRequest, {\n prefix: \"/api\",\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"OpenAPI error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n };\n\n devServer.app.all(`/api/rpc${rpcPrefix}/*`, async (req: any, res: any) => {\n applyCorsHeaders(res);\n const rpcHandler = devServer.app.locals.handlers?.rpc;\n if (!rpcHandler) {\n return res.status(503).json({ error: \"Plugin still loading...\" });\n }\n\n try {\n const url = `http://${req.headers.host}${req.url}`;\n const webRequest = new Request(url, {\n method: req.method,\n headers: req.headers,\n body: req.method !== \"GET\" && req.method !== \"HEAD\" ? req : undefined,\n duplex: req.method !== \"GET\" && req.method !== \"HEAD\" ? \"half\" : undefined,\n } as RequestInit);\n\n const result = await rpcHandler.handle(webRequest, {\n prefix: `/api/rpc${rpcPrefix}`,\n context: {},\n });\n\n if (result.response) {\n res.status(result.response.status);\n result.response.headers.forEach((value: string, key: string) => {\n res.setHeader(key, value);\n });\n const text = await result.response.text();\n res.send(text);\n } else {\n res.status(404).send(\"Not Found\");\n }\n } catch (error) {\n console.error(\"RPC error:\", error);\n res.status(500).json({ error: (error as Error).message });\n }\n });\n\n devServer.app.all(\"/api\", handleApiRequest);\n devServer.app.all(\"/api/*\", handleApiRequest);\n}\n"],"mappings":"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"}
@@ -84,7 +84,8 @@ var PluginRuntime = class {
84
84
  const effect$5 = effect.Effect.gen(function* () {
85
85
  yield* (yield* require_plugin_service.PluginService).cleanup();
86
86
  });
87
- return this.runPromise(effect$5);
87
+ await this.runPromise(effect$5);
88
+ await this.runtime.dispose();
88
89
  }
89
90
  async evictPlugin(pluginId, config) {
90
91
  const cacheKey = this.generateCacheKey(pluginId, config);
@@ -1 +1 @@
1
- {"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\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\n return initialized;\n }).pipe(Effect.provide(this.runtime));\n\n cachedPlugin = Effect.cached(operation).pipe(Effect.flatten);\n this.pluginCache.set(cacheKey, cachedPlugin);\n }\n\n const initialized = await this.runPromise(cachedPlugin);\n\n // Create client factory that accepts request context\n const createClient = (context?: any) => {\n const router = initialized.plugin.createRouter(initialized.context);\n return createRouterClient(router, { context: context ?? {} });\n };\n\n return {\n createClient: createClient as any,\n router: initialized.plugin.createRouter(initialized.context) as PluginRouterType<R[K]>,\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 });\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 });\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 return yield* pluginService.initializePlugin(instance, config, plugins);\n });\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 return this.runPromise(effect);\n }\n\n async evictPlugin<K extends keyof R & string>(\n pluginId: K,\n config: PluginConfigInput<R[K]>,\n ): Promise<void> {\n const cacheKey = this.generateCacheKey(pluginId, config);\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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"}
1
+ {"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\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\n return initialized;\n }).pipe(Effect.provide(this.runtime));\n\n cachedPlugin = Effect.cached(operation).pipe(Effect.flatten);\n this.pluginCache.set(cacheKey, cachedPlugin);\n }\n\n const initialized = await this.runPromise(cachedPlugin);\n\n // Create client factory that accepts request context\n const createClient = (context?: any) => {\n const router = initialized.plugin.createRouter(initialized.context);\n return createRouterClient(router, { context: context ?? {} });\n };\n\n return {\n createClient: createClient as any,\n router: initialized.plugin.createRouter(initialized.context) as PluginRouterType<R[K]>,\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 });\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 });\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 return yield* pluginService.initializePlugin(instance, config, plugins);\n });\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 ): Promise<void> {\n const cacheKey = this.generateCacheKey(pluginId, config);\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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/runtime/index.ts"],"mappings":";;;;;cAqBa,aAAA,KAAkB,iBAAA;EAAA,QASnB,OAAA;EAAA,QACA,QAAA;EAAA,SATD,cAAA,GAAiB,CAAA;EAAA,QAElB,WAAA;cAME,OAAA,EAAS,cAAA,CAAe,cAAA,CAAe,aAAA,UACvC,QAAA,EAAU,cAAA;EAAA,QAGZ,gBAAA;EAAA,QAKA,gBAAA;EAAA,QAcM,UAAA;EAcR,SAAA,iBAA0B,CAAA,UAAA,CAC9B,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,IAC5B,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,eAAA,CAAgB,CAAA,EAAG,CAAA;EAqCxB,UAAA,iBAA2B,CAAA,UAAA,CAC/B,QAAA,EAAU,CAAA,GACT,OAAA,CAAQ,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQtC,iBAAA,iBAAkC,CAAA,UAAA,CACtC,QAAA,EAAU,CAAA,EACV,YAAA,EAAc,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA,KAC9C,OAAA,CAAQ,cAAA,CAAe,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQxC,gBAAA,WAA2B,SAAA,CAAA,CAC/B,QAAA,EAAU,cAAA,CAAe,CAAA,GACzB,MAAA,OACA,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,iBAAA,CAAkB,CAAA;EAQvB,QAAA,CAAA,GAAY,OAAA;EAQZ,WAAA,iBAA4B,CAAA,UAAA,CAChC,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,KAC3B,OAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAoGW,mBAAA,mBAAsC,MAAA,SAAe,mBAAA,EAAA,CACnE,MAAA,EAAQ,mBAAA,CAAoB,SAAA,IAC3B,aAAA,CAAc,wBAAA,CAAyB,SAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/runtime/index.ts"],"mappings":";;;;;cAqBa,aAAA,KAAkB,iBAAA;EAAA,QASnB,OAAA;EAAA,QACA,QAAA;EAAA,SATD,cAAA,GAAiB,CAAA;EAAA,QAElB,WAAA;cAME,OAAA,EAAS,cAAA,CAAe,cAAA,CAAe,aAAA,UACvC,QAAA,EAAU,cAAA;EAAA,QAGZ,gBAAA;EAAA,QAKA,gBAAA;EAAA,QAcM,UAAA;EAcR,SAAA,iBAA0B,CAAA,UAAA,CAC9B,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,IAC5B,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,eAAA,CAAgB,CAAA,EAAG,CAAA;EAqCxB,UAAA,iBAA2B,CAAA,UAAA,CAC/B,QAAA,EAAU,CAAA,GACT,OAAA,CAAQ,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQtC,iBAAA,iBAAkC,CAAA,UAAA,CACtC,QAAA,EAAU,CAAA,EACV,YAAA,EAAc,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA,KAC9C,OAAA,CAAQ,cAAA,CAAe,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQxC,gBAAA,WAA2B,SAAA,CAAA,CAC/B,QAAA,EAAU,cAAA,CAAe,CAAA,GACzB,MAAA,OACA,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,iBAAA,CAAkB,CAAA;EAQvB,QAAA,CAAA,GAAY,OAAA;EASZ,WAAA,iBAA4B,CAAA,UAAA,CAChC,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,KAC3B,OAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAoGW,mBAAA,mBAAsC,MAAA,SAAe,mBAAA,EAAA,CACnE,MAAA,EAAQ,mBAAA,CAAoB,SAAA,IAC3B,aAAA,CAAc,wBAAA,CAAyB,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/runtime/index.ts"],"mappings":";;;;;cAqBa,aAAA,KAAkB,iBAAA;EAAA,QASnB,OAAA;EAAA,QACA,QAAA;EAAA,SATD,cAAA,GAAiB,CAAA;EAAA,QAElB,WAAA;cAME,OAAA,EAAS,cAAA,CAAe,cAAA,CAAe,aAAA,UACvC,QAAA,EAAU,cAAA;EAAA,QAGZ,gBAAA;EAAA,QAKA,gBAAA;EAAA,QAcM,UAAA;EAcR,SAAA,iBAA0B,CAAA,UAAA,CAC9B,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,IAC5B,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,eAAA,CAAgB,CAAA,EAAG,CAAA;EAqCxB,UAAA,iBAA2B,CAAA,UAAA,CAC/B,QAAA,EAAU,CAAA,GACT,OAAA,CAAQ,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQtC,iBAAA,iBAAkC,CAAA,UAAA,CACtC,QAAA,EAAU,CAAA,EACV,YAAA,EAAc,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA,KAC9C,OAAA,CAAQ,cAAA,CAAe,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQxC,gBAAA,WAA2B,SAAA,CAAA,CAC/B,QAAA,EAAU,cAAA,CAAe,CAAA,GACzB,MAAA,OACA,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,iBAAA,CAAkB,CAAA;EAQvB,QAAA,CAAA,GAAY,OAAA;EAQZ,WAAA,iBAA4B,CAAA,UAAA,CAChC,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,KAC3B,OAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAoGW,mBAAA,mBAAsC,MAAA,SAAe,mBAAA,EAAA,CACnE,MAAA,EAAQ,mBAAA,CAAoB,SAAA,IAC3B,aAAA,CAAc,wBAAA,CAAyB,SAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/runtime/index.ts"],"mappings":";;;;;cAqBa,aAAA,KAAkB,iBAAA;EAAA,QASnB,OAAA;EAAA,QACA,QAAA;EAAA,SATD,cAAA,GAAiB,CAAA;EAAA,QAElB,WAAA;cAME,OAAA,EAAS,cAAA,CAAe,cAAA,CAAe,aAAA,UACvC,QAAA,EAAU,cAAA;EAAA,QAGZ,gBAAA;EAAA,QAKA,gBAAA;EAAA,QAcM,UAAA;EAcR,SAAA,iBAA0B,CAAA,UAAA,CAC9B,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,IAC5B,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,eAAA,CAAgB,CAAA,EAAG,CAAA;EAqCxB,UAAA,iBAA2B,CAAA,UAAA,CAC/B,QAAA,EAAU,CAAA,GACT,OAAA,CAAQ,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQtC,iBAAA,iBAAkC,CAAA,UAAA,CACtC,QAAA,EAAU,CAAA,EACV,YAAA,EAAc,YAAA,CAAa,gBAAA,CAAiB,CAAA,EAAG,CAAA,KAC9C,OAAA,CAAQ,cAAA,CAAe,gBAAA,CAAiB,CAAA,EAAG,CAAA;EAQxC,gBAAA,WAA2B,SAAA,CAAA,CAC/B,QAAA,EAAU,cAAA,CAAe,CAAA,GACzB,MAAA,OACA,OAAA,GAAU,MAAA,oBACT,OAAA,CAAQ,iBAAA,CAAkB,CAAA;EAQvB,QAAA,CAAA,GAAY,OAAA;EASZ,WAAA,iBAA4B,CAAA,UAAA,CAChC,QAAA,EAAU,CAAA,EACV,MAAA,EAAQ,iBAAA,CAAkB,CAAA,CAAE,CAAA,KAC3B,OAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAoGW,mBAAA,mBAAsC,MAAA,SAAe,mBAAA,EAAA,CACnE,MAAA,EAAQ,mBAAA,CAAoB,SAAA,IAC3B,aAAA,CAAc,wBAAA,CAAyB,SAAA"}
@@ -82,7 +82,8 @@ var PluginRuntime = class {
82
82
  const effect = Effect.gen(function* () {
83
83
  yield* (yield* PluginService).cleanup();
84
84
  });
85
- return this.runPromise(effect);
85
+ await this.runPromise(effect);
86
+ await this.runtime.dispose();
86
87
  }
87
88
  async evictPlugin(pluginId, config) {
88
89
  const cacheKey = this.generateCacheKey(pluginId, config);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"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\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\n return initialized;\n }).pipe(Effect.provide(this.runtime));\n\n cachedPlugin = Effect.cached(operation).pipe(Effect.flatten);\n this.pluginCache.set(cacheKey, cachedPlugin);\n }\n\n const initialized = await this.runPromise(cachedPlugin);\n\n // Create client factory that accepts request context\n const createClient = (context?: any) => {\n const router = initialized.plugin.createRouter(initialized.context);\n return createRouterClient(router, { context: context ?? {} });\n };\n\n return {\n createClient: createClient as any,\n router: initialized.plugin.createRouter(initialized.context) as PluginRouterType<R[K]>,\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 });\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 });\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 return yield* pluginService.initializePlugin(instance, config, plugins);\n });\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 return this.runPromise(effect);\n }\n\n async evictPlugin<K extends keyof R & string>(\n pluginId: K,\n config: PluginConfigInput<R[K]>,\n ): Promise<void> {\n const cacheKey = this.generateCacheKey(pluginId, config);\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":";;;;;;AAqBA,IAAa,gBAAb,MAAkD;CAChD,AAAS;CAET,AAAQ,8BAAc,IAAI,KAGvB;CAEH,YACE,AAAQ,SACR,AAAQ,UACR;EAFQ;EACA;;CAGV,AAAQ,iBAAiB,UAAkB,QAAyB;AAElE,SAAO,GAAG,SAAS,GADA,KAAK,UAAU,OAAiB,CAAC,UAAU;;CAIhE,AAAQ,iBAAiB,UAA6D;AACpF,MAAI,EAAE,YAAY,KAAK,UACrB,QAAO,OAAO,KACZ,IAAI,mBAAmB;GACrB,UAAU,OAAO,SAAS;GAC1B,WAAW;GACX,uBAAO,IAAI,MAAM,cAAc,OAAO,SAAS,CAAC,0BAA0B;GAC1E,WAAW;GACZ,CAAC,CACH;AAEH,SAAO,OAAO,QAAQ,OAAO,SAAS,CAAC;;CAGzC,MAAc,WAAiB,QAAwD;EACrF,MAAM,OAAO,MAAM,KAAK,QAAQ,eAAe,OAAO;AAEtD,MAAI,KAAK,UAAU,KAAK,EAAE;GACxB,MAAM,QAAQ,MAAM,cAAc,KAAK,MAAM;AAC7C,OAAI,OAAO,OAAO,MAAM,CACtB,OAAM,MAAM;AAEd,SAAM,MAAM,OAAO,KAAK,MAAM;;AAGhC,SAAO,KAAK;;CAGd,MAAM,UACJ,UACA,QACA,SACgC;EAChC,MAAM,WAAW,KAAK,iBAAiB,UAAU;GAAE,GAAG;GAAQ,WAAW,WAAW,EAAE;GAAE,CAAC;EAEzF,IAAI,eAAe,KAAK,YAAY,IAAI,SAAS;AACjD,MAAI,CAAC,cAAc;GACjB,MAAM,YAAY,OAAO,IAAI,MAAM,aAAa;IAC9C,MAAM,gBAAgB,OAAO;IAC7B,MAAM,cAAc,OAAO,KAAK,iBAAiB,SAAS;IAG1D,MAAM,OAAO,OAAO,cAAc,WAAW,YAAY;IACzD,MAAM,WAAW,OAAO,cAAc,kBAAkB,UAAU,KAAK;AAGvE,WAFoB,OAAO,cAAc,iBAAiB,UAAU,QAAQ,QAAQ;KAGpF,CAAC,KAAK,OAAO,QAAQ,KAAK,QAAQ,CAAC;AAErC,kBAAe,OAAO,OAAO,UAAU,CAAC,KAAK,OAAO,QAAQ;AAC5D,QAAK,YAAY,IAAI,UAAU,aAAa;;EAG9C,MAAM,cAAc,MAAM,KAAK,WAAW,aAAa;EAGvD,MAAM,gBAAgB,YAAkB;AAEtC,UAAO,mBADQ,YAAY,OAAO,aAAa,YAAY,QAAQ,EACjC,EAAE,SAAS,WAAW,EAAE,EAAE,CAAC;;AAG/D,SAAO;GACS;GACd,QAAQ,YAAY,OAAO,aAAa,YAAY,QAAQ;GAC5D,UAAU,YAAY;GACT;GACd;;CAGH,MAAM,WACJ,UAC+C;EAC/C,MAAM,SAAS,OAAO,IAAI,aAAa;AAErC,UAAO,QADe,OAAO,eACD,WAAW,SAAS;IAChD;AACF,SAAO,KAAK,WAAW,OAAO;;CAGhC,MAAM,kBACJ,UACA,cACiD;EACjD,MAAM,SAAS,OAAO,IAAI,aAAa;AAErC,UAAO,QADe,OAAO,eACD,kBAAkB,UAAU,aAAa;IACrE;AACF,SAAO,KAAK,WAAW,OAAO;;CAGhC,MAAM,iBACJ,UACA,QACA,SAC+B;EAC/B,MAAM,SAAS,OAAO,IAAI,aAAa;AAErC,UAAO,QADe,OAAO,eACD,iBAAiB,UAAU,QAAQ,QAAQ;IACvE;AACF,SAAO,KAAK,WAAW,OAAO;;CAGhC,MAAM,WAA0B;EAC9B,MAAM,SAAS,OAAO,IAAI,aAAa;AAErC,WADsB,OAAO,eACR,SAAS;IAC9B;AACF,SAAO,KAAK,WAAW,OAAO;;CAGhC,MAAM,YACJ,UACA,QACe;EACf,MAAM,WAAW,KAAK,iBAAiB,UAAU,OAAO;EAExD,MAAM,SAAS,OAAO,IAAI,MAAM,aAAa;GAC3C,MAAM,gBAAgB,OAAO;GAC7B,MAAM,eAAe,KAAK,YAAY,IAAI,SAAS;AAEnD,OAAI,cAAc;AAChB,SAAK,YAAY,OAAO,SAAS;IAEjC,MAAM,eAAe,OAAO,aAAa,KAAK,OAAO,eAAe,OAAO,QAAQ,KAAK,CAAC,CAAC;AAE1F,QAAI,aACF,QAAO,cACJ,eAAe,aAAa,CAC5B,KACC,OAAO,UAAU,UACf,OAAO,WAAW,qCAAqC,YAAY,MAAM,CAC1E,CACF;;IAGP,CAAC,KACD,OAAO,UAAU,UACf,OAAO,WAAW,8BAA8B,YAAY,MAAM,CACnE,CACF;AAED,SAAO,KAAK,WAAW,OAAO;;;;;;;AAQlC,SAAS,mBAAmB,KAAqB;AAC/C,KAAI,CAAC,IAAK,QAAO;AACjB,KAAI,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,QAAQ,CAAE,QAAO;AACzD,QAAO,GAAG,IAAI,SAAS,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,IAAI;;;;;AAMvD,SAAS,iBACP,UACsC;CACtC,MAAM,YAAkD,EAAE;AAE1D,MAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,SAAS,CACtD,KAAI,YAAY,SAAS,MAAM,OAC7B,WAAU,YAAY,MAAM;AAIhC,QAAO;;;;;AAMT,SAAS,kBAAkB,UAA+D;CACxF,MAAM,aAAkD,EAAE;AAE1D,MAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,SAAS,CACtD,KAAI,YAAY,MACd,YAAW,YAAY;EACrB,GAAG;EACH,QAAQ,MAAM,SAAS,mBAAmB,MAAM,OAAO,GAAG;EAC3D;KAED,YAAW,YAAY;EACrB,GAAG;EACH,QAAQ,mBAAmB,MAAM,OAAO;EACzC;AAIL,QAAO;;;;;;;;;;;;;;;;;;;;AAqBT,SAAgB,oBACd,QACoD;CACpD,MAAM,UAAU,OAAO,WAAW,EAAE;CACpC,MAAM,qBAAqB,kBAAkB,OAAO,SAAS;CAC7D,MAAM,YAAY,iBAAiB,OAAO,SAAS;CAEnD,MAAM,QAAQ,cAAc,KAAK,oBAAoB,SAAS,UAAU;AAGxE,QAAO,IAAI,cAFK,eAAe,KAAK,MAAM,EAER,mBAAmB"}
1
+ {"version":3,"file":"index.mjs","names":[],"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\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\n return initialized;\n }).pipe(Effect.provide(this.runtime));\n\n cachedPlugin = Effect.cached(operation).pipe(Effect.flatten);\n this.pluginCache.set(cacheKey, cachedPlugin);\n }\n\n const initialized = await this.runPromise(cachedPlugin);\n\n // Create client factory that accepts request context\n const createClient = (context?: any) => {\n const router = initialized.plugin.createRouter(initialized.context);\n return createRouterClient(router, { context: context ?? {} });\n };\n\n return {\n createClient: createClient as any,\n router: initialized.plugin.createRouter(initialized.context) as PluginRouterType<R[K]>,\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 });\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 });\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 return yield* pluginService.initializePlugin(instance, config, plugins);\n });\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 ): Promise<void> {\n const cacheKey = this.generateCacheKey(pluginId, config);\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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"}
@@ -12,7 +12,7 @@ function getInstalledPackageVersion(packageName, fallbackRange) {
12
12
  return match ? match[0] : fallbackRange.replace(/^[\^~>=<\s]+/, "");
13
13
  }
14
14
  }
15
- const PLUGIN_VERSION = "2.5.3";
15
+ const PLUGIN_VERSION = "2.5.5";
16
16
  const SHARE_CONFIG = {
17
17
  singleton: true,
18
18
  requiredVersion: false,
@@ -10,7 +10,7 @@ function getInstalledPackageVersion(packageName, fallbackRange) {
10
10
  return match ? match[0] : fallbackRange.replace(/^[\^~>=<\s]+/, "");
11
11
  }
12
12
  }
13
- const PLUGIN_VERSION = "2.5.3";
13
+ const PLUGIN_VERSION = "2.5.5";
14
14
  const SHARE_CONFIG = {
15
15
  singleton: true,
16
16
  requiredVersion: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "every-plugin",
3
- "version": "2.5.3",
3
+ "version": "2.5.5",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -111,7 +111,9 @@ export function setupPluginMiddleware(
111
111
  console.error("❌ Failed to load plugin:", error);
112
112
  await performCleanup();
113
113
  }
114
- })();
114
+ })().catch((err) => {
115
+ console.error("❌ Plugin dev server fatal error:", err);
116
+ });
115
117
 
116
118
  process.once("SIGINT", async () => {
117
119
  const timeout = setTimeout(() => process.exit(0), 3000);
@@ -144,7 +144,8 @@ export class PluginRuntime<R = RegisteredPlugins> {
144
144
  const pluginService = yield* PluginService;
145
145
  yield* pluginService.cleanup();
146
146
  });
147
- return this.runPromise(effect);
147
+ await this.runPromise(effect);
148
+ await this.runtime.dispose();
148
149
  }
149
150
 
150
151
  async evictPlugin<K extends keyof R & string>(