UNPKG

n8n-nodes-agent-chat-interface

Version:

N8N custom node that serves a React chat interface as static content

97 lines (96 loc) 5.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RuntimeThemeInjector = void 0; class RuntimeThemeInjector { static injectWebhookUrl(content, webhookUrl, fileExtension) { if (!webhookUrl || webhookUrl === '') { return content; } const cleanWebhookUrl = webhookUrl.endsWith('/') ? webhookUrl.slice(0, -1) : webhookUrl; const cacheBuster = Date.now(); switch (fileExtension) { case '.html': return this.injectWebhookUrlIntoHtml(content, cleanWebhookUrl, cacheBuster); case '.css': return this.injectWebhookUrlIntoCss(content, cleanWebhookUrl, cacheBuster); case '.js': return this.injectWebhookUrlIntoJs(content, cleanWebhookUrl, cacheBuster); default: return content; } } static injectWebhookUrlIntoHtml(htmlContent, webhookUrl, cacheBuster) { const placeholder = '/__N8N_WEBHOOK_PLACEHOLDER__/'; const cleanWebhookUrl = webhookUrl.endsWith('/') ? webhookUrl.slice(0, -1) : webhookUrl; return htmlContent.split(placeholder).join(`${cleanWebhookUrl}?cb=${cacheBuster}&path=`); } static injectWebhookUrlIntoCss(cssContent, webhookUrl, cacheBuster) { const placeholder = '/__N8N_WEBHOOK_PLACEHOLDER__/'; const cleanWebhookUrl = webhookUrl.endsWith('/') ? webhookUrl.slice(0, -1) : webhookUrl; return cssContent.split(placeholder).join(`${cleanWebhookUrl}?cb=${cacheBuster}&path=`); } static injectWebhookUrlIntoJs(jsContent, webhookUrl, cacheBuster) { const placeholder = '/__N8N_WEBHOOK_PLACEHOLDER__/'; const cleanWebhookUrl = webhookUrl.endsWith('/') ? webhookUrl.slice(0, -1) : webhookUrl; return jsContent.split(placeholder).join(`${cleanWebhookUrl}?cb=${cacheBuster}&path=`); } static injectThemeIntoHtml(htmlContent, themeConfig) { const cleanConfig = Object.fromEntries(Object.entries(themeConfig).filter(([_, value]) => value !== undefined && value !== '')); // Base64 encode footnote for safe HTML injection if (cleanConfig.VITE_AGENT_MESSAGE_FOOTNOTE) { cleanConfig.VITE_AGENT_MESSAGE_FOOTNOTE = Buffer.from(cleanConfig.VITE_AGENT_MESSAGE_FOOTNOTE, 'utf8').toString('base64'); } if (cleanConfig.VITE_WELCOME_MESSAGE) { cleanConfig.VITE_WELCOME_MESSAGE = Buffer.from(cleanConfig.VITE_WELCOME_MESSAGE, 'utf8').toString('base64'); } const themeScript = ` <script> window.__CHAT_THEME_CONFIG__ = ${JSON.stringify(cleanConfig)}; </script>`; return htmlContent.replace('</head>', `${themeScript}\n</head>`); } static injectApiConfigIntoHtml(htmlContent, apiUrl, title) { const apiConfig = { VITE_CHAT_API_URL: apiUrl, VITE_CHAT_TITLE: title }; const configScript = ` <script> window.__CHAT_THEME_CONFIG__ = Object.assign(window.__CHAT_THEME_CONFIG__ || {}, ${JSON.stringify(apiConfig)}); </script>`; return htmlContent.replace('</head>', `${configScript}\n</head>`); } static injectFullConfig(htmlContent, fullConfig) { const cleanConfig = Object.fromEntries(Object.entries(fullConfig).filter(([_, value]) => value !== undefined && value !== '')); // Base64 encode footnote for safe HTML injection if (cleanConfig.VITE_AGENT_MESSAGE_FOOTNOTE) { cleanConfig.VITE_AGENT_MESSAGE_FOOTNOTE = Buffer.from(cleanConfig.VITE_AGENT_MESSAGE_FOOTNOTE, 'utf8').toString('base64'); } if (cleanConfig.VITE_WELCOME_MESSAGE) { cleanConfig.VITE_WELCOME_MESSAGE = Buffer.from(cleanConfig.VITE_WELCOME_MESSAGE, 'utf8').toString('base64'); } // Break n8n internal caching const timestamp = Date.now(); const randomValue = Math.random().toString(36).substring(2, 15); cleanConfig.__N8N_CACHE_BUSTER__ = `${timestamp}-${randomValue}`; const configScript = ` <script> window.__CHAT_THEME_CONFIG__ = ${JSON.stringify(cleanConfig)}; window.__CONFIG_LOADED_AT__ = ${timestamp}; console.log('Config loaded at:', new Date(${timestamp})); </script>`; let modifiedHtml = htmlContent.replace('</head>', `${configScript}\n</head>`); const chatTitle = fullConfig.VITE_CHAT_TITLE; if (chatTitle) { modifiedHtml = modifiedHtml.replace(/<title>.*?<\/title>/, `<title>${chatTitle}</title>`); } const customFavicon = fullConfig.VITE_CUSTOM_FAVICON; if (customFavicon && customFavicon.trim() !== '') { modifiedHtml = modifiedHtml.replace(/<link[^>]*rel=['"](icon|shortcut icon)['"'][^>]*>/gi, ''); const faviconLink = `<link rel="icon" type="image/png" href="${customFavicon}">`; modifiedHtml = modifiedHtml.replace('</head>', ` ${faviconLink}\n</head>`); } return modifiedHtml; } } exports.RuntimeThemeInjector = RuntimeThemeInjector;