UNPKG

vybcel

Version:

Vybcel Development Agent and Vite Plugin for seamless code sync and auto-deploy

223 lines (222 loc) 8.52 kB
// src/plugin.ts import { readFileSync, existsSync } from "fs"; import { resolve, join, dirname } from "path"; import { fileURLToPath } from "url"; var __filename = fileURLToPath(import.meta.url); var __dirname = dirname(__filename); var getPluginVersion = () => { try { const packageJsonPath = join(__dirname, "..", "package.json"); const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")); return packageJson.version; } catch (error) { console.warn("[Vybcel] Could not read version from package.json, using fallback"); return "1.1.27"; } }; var PLUGIN_VERSION = getPluginVersion(); var DEFAULT_UPDATE_ENDPOINT = process.env.TOOLBAR_UPDATE_ENDPOINT || "http://localhost:3004/api/toolbar"; var findToolbarBundle = () => { const __filename2 = fileURLToPath(import.meta.url); const __dirname2 = dirname(__filename2); const locations = [ // Direct in dist/toolbar folder (new package structure) join(__dirname2, "toolbar", "index.global.js"), // In node_modules join(dirname(dirname(__dirname2)), "dist", "toolbar", "index.global.js"), // One level up (when used as dependency) join(dirname(dirname(dirname(__dirname2))), "vybcel", "dist", "toolbar", "index.global.js") ]; for (const location of locations) { if (existsSync(location)) { return location; } } console.warn("[Vybcel] Could not find toolbar bundle at any of these locations:", locations); return null; }; function vybcelPlugin(options = {}) { const { configPath = "vybcel.config.json", websocketUrl = "wss://api.vybcel.com", autoUpdate = true, updateEndpoint = DEFAULT_UPDATE_ENDPOINT } = options; let config = null; let toolbarEnabled = false; let cachedToolbarCode = null; let lastUpdateCheck = 0; const UPDATE_CACHE_DURATION = 0; async function checkForUpdates() { if (!autoUpdate || Date.now() - lastUpdateCheck < UPDATE_CACHE_DURATION) { return null; } try { const channel = config?.toolbar?.updateChannel || "stable"; const response = await fetch(`${updateEndpoint}/check`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ currentVersion: PLUGIN_VERSION, channel, projectId: config?.projectId }) }); if (response.ok) { lastUpdateCheck = Date.now(); return await response.json(); } } catch (error) { if (config?.debug) { console.warn("[vybcel-plugin] Update check failed:", error); } } return null; } async function downloadToolbarUpdate(version) { try { const response = await fetch(version.url); if (response.ok) { const code = await response.text(); const actualChecksum = Buffer.from(code).toString("base64").slice(0, 8); if (actualChecksum !== version.checksum.slice(0, 8)) { console.warn("[vybcel-plugin] Checksum mismatch, using local version"); return null; } cachedToolbarCode = code; console.log(`[vybcel-plugin] Updated to toolbar version ${version.version}`); return code; } } catch (error) { console.warn("[vybcel-plugin] Failed to download toolbar update:", error); } return null; } return { name: "vite-plugin-vybcel", configResolved(resolvedConfig) { const configFilePath = resolve(resolvedConfig.root, configPath); console.log(`[Vybcel] Looking for config at: ${configFilePath}`); if (existsSync(configFilePath)) { try { const configContent = readFileSync(configFilePath, "utf-8"); config = JSON.parse(configContent); console.log(`[Vybcel] Config loaded:`, { projectId: config?.projectId, wsUrl: config?.wsUrl, toolbarEnabled: config?.toolbar?.enabled }); toolbarEnabled = config?.toolbar?.enabled !== false && process.env.VYBCEL_TOOLBAR !== "false"; console.log(`[Vybcel] Toolbar enabled: ${toolbarEnabled}`); } catch (error) { console.warn("[vybcel-plugin] Failed to read config:", error); } } else { console.log(`[Vybcel] Config file not found at: ${configFilePath}`); } }, configureServer(server) { if (!toolbarEnabled || !config) return; server.middlewares.use("/vybcel/config.js", (req, res, next) => { try { const toolbarConfig = { projectId: config?.projectId || "", websocketUrl: config?.wsUrl || websocketUrl, // ✅ Всегда из конфига в первую очередь position: config?.toolbar?.position || "top", version: PLUGIN_VERSION, autoUpdate: config?.toolbar?.autoUpdate !== false, updateChannel: config?.toolbar?.updateChannel || "stable", debug: config?.debug || false }; if (config?.debug) { console.log(`[Vybcel] Creating toolbar config...`); console.log(`[Vybcel] Config object:`, config); console.log(`[Vybcel] Final toolbar config:`, toolbarConfig); } res.writeHead(200, { "Content-Type": "application/javascript" }); res.end(`window.VYBCEL_CONFIG = ${JSON.stringify(toolbarConfig)};`); } catch (err) { console.error("[Vybcel] Error serving config:", err); res.writeHead(500, { "Content-Type": "text/plain" }); res.end("Error generating toolbar config"); } }); server.middlewares.use("/vybcel/toolbar.js", async (req, res, next) => { try { let toolbarCode = cachedToolbarCode; try { if (config?.toolbar?.autoUpdate !== false) { const updateCheck = await checkForUpdates(); if (updateCheck?.hasUpdate && updateCheck.latestVersion) { if (config?.debug) { console.log(`[Vybcel] Using latest toolbar from ${updateCheck.latestVersion.url}`); } const updatedCode = await downloadToolbarUpdate(updateCheck.latestVersion); if (updatedCode) { toolbarCode = updatedCode; } } } } catch (fetchError) { if (config?.debug) { console.log(`[Vybcel] Could not fetch remote toolbar: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`); } } if (!toolbarCode) { const toolbarPath = findToolbarBundle(); if (toolbarPath) { if (config?.debug) { console.log(`[Vybcel] Using local toolbar from ${toolbarPath}`); } toolbarCode = readFileSync(toolbarPath, "utf-8"); } } if (toolbarCode) { res.writeHead(200, { "Content-Type": "application/javascript" }); res.end(toolbarCode); } else { console.error("[Vybcel] Toolbar bundle not found"); res.writeHead(404, { "Content-Type": "text/plain" }); res.end("Toolbar bundle not found"); } } catch (err) { console.error("[Vybcel] Error serving toolbar:", err); res.writeHead(500, { "Content-Type": "text/plain" }); res.end("Error loading toolbar"); } }); server.middlewares.use("/vybcel/api/update-check", async (req, res) => { if (req.method !== "POST") { res.statusCode = 405; res.end("Method not allowed"); return; } try { const updateCheck = await checkForUpdates(); res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify(updateCheck || { hasUpdate: false, currentVersion: PLUGIN_VERSION })); } catch (error) { res.statusCode = 500; res.end(JSON.stringify({ error: "Update check failed" })); } }); }, transformIndexHtml(html) { if (!toolbarEnabled || !config) return html; const timestamp = Date.now(); const toolbarScript = ` <script src="/vybcel/config.js?v=${timestamp}"></script> <script src="/vybcel/toolbar.js?v=${timestamp}"></script> `; return html.replace("</body>", `${toolbarScript}</body>`); } }; } var plugin_default = vybcelPlugin; export { plugin_default as default, vybcelPlugin };