UNPKG

every-plugin

Version:
192 lines (190 loc) 7.09 kB
//#region src/build/rspack/dev-server-middleware.ts const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS", "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization" }; const applyCorsHeaders = (res) => { Object.entries(corsHeaders).forEach(([key, value]) => { res.setHeader(key, value); }); }; const normalizePrefix = (prefix) => { if (!prefix) return ""; const cleaned = prefix.replace(/^\/+|\/+$/g, ""); return cleaned ? `/${cleaned}` : ""; }; function setupPluginMiddleware(devServer, pluginInfo, devConfig, port) { const rpcPrefix = normalizePrefix(devConfig?.prefix); const handlers = { rpc: null, api: null }; let cleanup = null; const performCleanup = async () => { if (cleanup) { await cleanup(); cleanup = null; } }; (async () => { await performCleanup(); try { const { createPluginRuntime } = await Promise.resolve().then(() => require("../../index.cjs")); const { RPCHandler } = await import("@orpc/server/fetch"); const { OpenAPIHandler } = await import("@orpc/openapi/fetch"); const { OpenAPIReferencePlugin } = await import("@orpc/openapi/plugins"); const { ZodToJsonSchemaConverter } = await import("@orpc/zod/zod4"); const { onError } = await Promise.resolve().then(() => require("../../orpc.cjs")); const { formatORPCError } = await Promise.resolve().then(() => require("../../errors.cjs")); const pluginId = devConfig?.pluginId || pluginInfo.normalizedName; const runtime = createPluginRuntime({ registry: { [pluginId]: { remote: `http://localhost:${port}/remoteEntry.js` } } }); const loaded = await runtime.usePlugin(pluginId, devConfig?.config ?? { variables: {}, secrets: {} }); cleanup = async () => { if (runtime) await runtime.shutdown(); handlers.rpc = null; handlers.api = null; if (devServer.app.locals.handlers) devServer.app.locals.handlers = null; }; handlers.rpc = new RPCHandler(loaded.router, { interceptors: [onError((error) => { formatORPCError(error); })] }); handlers.api = new OpenAPIHandler(loaded.router, { plugins: [new OpenAPIReferencePlugin({ schemaConverters: [new ZodToJsonSchemaConverter()] })], interceptors: [onError((error) => { formatORPCError(error); })] }); console.log(`╭─────────────────────────────────────────────`); console.log(`│ ✅ Plugin dev server ready: `); console.log(`├─────────────────────────────────────────────`); console.log(`│ 📡 RPC: http://localhost:${port}/api/rpc${rpcPrefix}`); console.log(`│ 📖 Docs: http://localhost:${port}/api`); console.log(`│ 💚 Health: http://localhost:${port}/`); console.log(`╰─────────────────────────────────────────────`); devServer.app.locals.handlers = handlers; if (devServer.server) devServer.server.once("close", async () => { await performCleanup(); }); } catch (error) { console.error("❌ Failed to load plugin:", error); await performCleanup(); } })().catch((err) => { console.error("❌ Plugin dev server fatal error:", err); }); process.once("SIGINT", async () => { const timeout = setTimeout(() => process.exit(0), 3e3); await performCleanup(); clearTimeout(timeout); }); process.once("SIGTERM", async () => { const timeout = setTimeout(() => process.exit(0), 3e3); await performCleanup(); clearTimeout(timeout); }); devServer.app.options("*", (_req, res) => { applyCorsHeaders(res); res.status(200).end(); }); devServer.app.get("/", (_req, res) => { applyCorsHeaders(res); res.json({ ok: true, plugin: pluginInfo.normalizedName, version: pluginInfo.version, status: devServer.app.locals.handlers?.rpc ? "ready" : "loading", endpoints: { health: "/", docs: "/api", rpc: `/api/rpc${rpcPrefix}` } }); }); devServer.app.get("/health", (_req, res) => { applyCorsHeaders(res); res.status(200).send("OK"); }); const buildDevContext = (_req, webRequest) => { const rawClone = webRequest.method === "GET" || webRequest.method === "HEAD" ? null : webRequest.clone(); let cachedRawBody = null; return { reqHeaders: webRequest.headers, getRawBody: async () => { if (cachedRawBody !== null) return cachedRawBody; if (!rawClone) { cachedRawBody = ""; return cachedRawBody; } cachedRawBody = await rawClone.text(); return cachedRawBody; } }; }; const handleApiRequest = async (req, res) => { applyCorsHeaders(res); const apiHandler = devServer.app.locals.handlers?.api; if (!apiHandler) return res.status(503).json({ error: "Plugin still loading..." }); try { const url = `http://${req.headers.host}${req.url}`; const webRequest = new Request(url, { method: req.method, headers: req.headers, body: req.method !== "GET" && req.method !== "HEAD" ? req : void 0, duplex: req.method !== "GET" && req.method !== "HEAD" ? "half" : void 0 }); const result = await apiHandler.handle(webRequest, { prefix: "/api", context: buildDevContext(req, webRequest) }); if (result.response) { res.status(result.response.status); result.response.headers.forEach((value, key) => { res.setHeader(key, value); }); const text = await result.response.text(); res.send(text); } else res.status(404).send("Not Found"); } catch (error) { console.error("OpenAPI error:", error); res.status(500).json({ error: error.message }); } }; devServer.app.all(`/api/rpc${rpcPrefix}/*`, async (req, res) => { applyCorsHeaders(res); const rpcHandler = devServer.app.locals.handlers?.rpc; if (!rpcHandler) return res.status(503).json({ error: "Plugin still loading..." }); try { const url = `http://${req.headers.host}${req.url}`; const webRequest = new Request(url, { method: req.method, headers: req.headers, body: req.method !== "GET" && req.method !== "HEAD" ? req : void 0, duplex: req.method !== "GET" && req.method !== "HEAD" ? "half" : void 0 }); const result = await rpcHandler.handle(webRequest, { prefix: `/api/rpc${rpcPrefix}`, context: buildDevContext(req, webRequest) }); if (result.response) { res.status(result.response.status); result.response.headers.forEach((value, key) => { res.setHeader(key, value); }); const text = await result.response.text(); res.send(text); } else res.status(404).send("Not Found"); } catch (error) { console.error("RPC error:", error); res.status(500).json({ error: error.message }); } }); devServer.app.all("/api", handleApiRequest); devServer.app.all("/api/*", handleApiRequest); } //#endregion exports.setupPluginMiddleware = setupPluginMiddleware; //# sourceMappingURL=dev-server-middleware.cjs.map