From 7957e6d50fdcc168f502e7d57b61b2d77701d2aa Mon Sep 17 00:00:00 2001 From: GuavaPopper Date: Fri, 5 Jun 2026 13:30:05 +0700 Subject: [PATCH 1/5] Aktifkan fallback proxy paralel publikasi:failover --- groups/RODA/.env | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 groups/RODA/.env diff --git a/groups/RODA/.env b/groups/RODA/.env new file mode 100644 index 0000000..b5545e4 --- /dev/null +++ b/groups/RODA/.env @@ -0,0 +1,4 @@ +DASHBOARD_TARGET_URL=https://dashboard.informatika.untan.ac.id/index.php?penelitian +DASHBOARD_PROXY_1=https://api.codetabs.com/v1/proxy?quest={{url}} +DASHBOARD_PROXY_2=https://api.allorigins.win/get?url={{url}}&ts={{ts}} +DASHBOARD_PROXY_3=https://thingproxy.freeboard.io/fetch/{{rawUrl}} \ No newline at end of file From f5dfb68bccbd37581e67603f51b9e425db9c8c95 Mon Sep 17 00:00:00 2001 From: GuavaPopper Date: Fri, 5 Jun 2026 17:04:04 +0700 Subject: [PATCH 2/5] Use RODA server for dashboard proxy --- groups/RODA/index.html | 6 +++--- groups/RODA/server.js | 31 ++++++++++++++++++++++--------- package.json | 4 +++- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/groups/RODA/index.html b/groups/RODA/index.html index 71a8e09..05b5752 100644 --- a/groups/RODA/index.html +++ b/groups/RODA/index.html @@ -76,6 +76,7 @@ window.APP_CONFIG = window.APP_CONFIG || { debugLogs: false, dashboardRuntimeFetch: 'always', + dashboardApiUrl: 'api/dashboard', dashboardTargetUrl: 'https://dashboard.informatika.untan.ac.id/index.php?penelitian', dashboardProxyTemplates: [ 'https://api.codetabs.com/v1/proxy?quest={{url}}', @@ -1677,14 +1678,13 @@ } const targetUrl = window.APP_CONFIG?.dashboardTargetUrl?.trim(); + const dashboardApiUrl = window.APP_CONFIG?.dashboardApiUrl?.trim(); const proxyTemplates = Array.isArray(window.APP_CONFIG?.dashboardProxyTemplates) ? window.APP_CONFIG.dashboardProxyTemplates.filter(Boolean) : []; - // Endpoint server.js hanya ada saat development lokal. - const proxyServers = shouldUseLocalDashboardProxy() ? [() => '/api/dashboard'] : []; + const proxyServers = dashboardApiUrl ? [() => dashboardApiUrl] : []; - // Deployment static memakai proxy publik karena tidak menjalankan server.js. if (targetUrl) { proxyTemplates.forEach((template) => { proxyServers.push((url) => template diff --git a/groups/RODA/server.js b/groups/RODA/server.js index 42dd119..2bf9d4e 100644 --- a/groups/RODA/server.js +++ b/groups/RODA/server.js @@ -7,8 +7,10 @@ const ROOT_DIR = __dirname; const PARENT_DIR = path.join(__dirname, '..', '..'); const INDEX_PATH = path.join(ROOT_DIR, 'index.html'); const ENV_PATH = path.join(ROOT_DIR, '.env'); -const HOST = '127.0.0.1'; +const HOST = process.env.HOST || '127.0.0.1'; const PORT = Number(process.env.PORT || 3000); +const DEFAULT_DASHBOARD_TARGET_URL = 'https://dashboard.informatika.untan.ac.id/index.php?penelitian'; +const RODA_PATH_PREFIX = '/groups/RODA'; function logServerError(scope, error, extra = {}) { console.error(`[${scope}]`, error && error.stack ? error.stack : error, extra); @@ -62,7 +64,10 @@ function getAppConfig() { ].filter(Boolean); return { - dashboardTargetUrl: env.DASHBOARD_TARGET_URL || '', + debugLogs: env.DEBUG_LOGS === 'true', + dashboardRuntimeFetch: env.DASHBOARD_RUNTIME_FETCH || 'always', + dashboardApiUrl: env.DASHBOARD_API_URL || 'api/dashboard', + dashboardTargetUrl: env.DASHBOARD_TARGET_URL || DEFAULT_DASHBOARD_TARGET_URL, dashboardProxyTemplates }; } @@ -113,10 +118,6 @@ function validateAppConfig(config) { errors.push('DASHBOARD_TARGET_URL belum diisi.'); } - if (!Array.isArray(config.dashboardProxyTemplates) || !config.dashboardProxyTemplates.length) { - errors.push('Minimal satu DASHBOARD_PROXY_* harus diisi.'); - } - return errors; } @@ -195,17 +196,29 @@ function sendNotFound(res) { res.end('Not found'); } +function getRodaStaticPathname(pathname) { + if (pathname === RODA_PATH_PREFIX || pathname === `${RODA_PATH_PREFIX}/` || pathname === `${RODA_PATH_PREFIX}/index.html`) { + return '/index.html'; + } + + if (pathname.startsWith(`${RODA_PATH_PREFIX}/`)) { + return pathname.slice(RODA_PATH_PREFIX.length); + } + + return pathname; +} + const server = http.createServer((req, res) => { try { const requestUrl = new URL(req.url, `http://${req.headers.host}`); const pathname = requestUrl.pathname; - if (pathname === '/' || pathname === '/index.html') { + if (pathname === '/' || pathname === '/index.html' || pathname === RODA_PATH_PREFIX || pathname === `${RODA_PATH_PREFIX}/` || pathname === `${RODA_PATH_PREFIX}/index.html`) { sendHtml(res); return; } - if (pathname === '/api/dashboard') { + if (pathname === '/api/dashboard' || pathname === `${RODA_PATH_PREFIX}/api/dashboard`) { fetchDashboardHtml() .then(({ html, cached }) => { res.writeHead(200, { @@ -237,7 +250,7 @@ const server = http.createServer((req, res) => { } // Serve static files from ROOT_DIR - const filepath = path.join(ROOT_DIR, pathname); + const filepath = path.join(ROOT_DIR, getRodaStaticPathname(pathname)); const normalizedPath = path.normalize(filepath); // Security check: ensure the requested file is within ROOT_DIR diff --git a/package.json b/package.json index b0c5938..b8879f2 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "type": "module", "description": "Student-safe static page assignment kit for Informatika UNTAN", "scripts": { - "dev": "vite", + "dev": "node groups/RODA/server.js", + "dev:vite": "vite", + "dev:roda": "node groups/RODA/server.js", "build": "vite build", "test:tapops": "node --test groups/Tapops/tests/*.test.mjs", "preview": "vite preview" From e18641ff52dc242d05271b3fb58929b21d72f60e Mon Sep 17 00:00:00 2001 From: GuavaPopper Date: Fri, 5 Jun 2026 17:55:51 +0700 Subject: [PATCH 3/5] fix: run RODA with Vite dev --- groups/RODA/package-lock.json | 13 ----- groups/RODA/package.json | 15 +----- package.json | 2 +- scripts/dev-runner.js | 94 +++++++++++++++++++++++++++++++++++ scripts/dev.js | 3 ++ vite.config.js | 71 ++++++-------------------- 6 files changed, 116 insertions(+), 82 deletions(-) delete mode 100644 groups/RODA/package-lock.json create mode 100644 scripts/dev-runner.js create mode 100644 scripts/dev.js diff --git a/groups/RODA/package-lock.json b/groups/RODA/package-lock.json deleted file mode 100644 index 2155203..0000000 --- a/groups/RODA/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "roda", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "roda", - "version": "1.0.0", - "license": "ISC" - } - } -} diff --git a/groups/RODA/package.json b/groups/RODA/package.json index b0606c6..5bbefff 100644 --- a/groups/RODA/package.json +++ b/groups/RODA/package.json @@ -1,14 +1,3 @@ { - "name": "roda", - "version": "1.0.0", - "description": "Project website untuk menampilkan sorotan dan prestasi karya mahasiswa program studi Informatika Universitas Tanjungpura.", - "main": "server.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "node server.js", - "dev": "node server.js" - }, - "keywords": [], - "author": "", - "license": "ISC" -} \ No newline at end of file + "type": "commonjs" +} diff --git a/package.json b/package.json index b8879f2..4c0e3a0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "description": "Student-safe static page assignment kit for Informatika UNTAN", "scripts": { - "dev": "node groups/RODA/server.js", + "dev": "node scripts/dev.js", "dev:vite": "vite", "dev:roda": "node groups/RODA/server.js", "build": "vite build", diff --git a/scripts/dev-runner.js b/scripts/dev-runner.js new file mode 100644 index 0000000..4a85906 --- /dev/null +++ b/scripts/dev-runner.js @@ -0,0 +1,94 @@ +import { spawn } from 'node:child_process'; + +export function createDevProcessSpecs({ + nodeCommand = process.execPath, + env = process.env, +} = {}) { + return { + roda: { + command: nodeCommand, + args: ['groups/RODA/server.js'], + options: { + env: { + ...env, + HOST: env.RODA_HOST || '127.0.0.1', + PORT: env.RODA_PORT || '3000', + }, + stdio: ['ignore', 'ignore', 'pipe'], + }, + }, + vite: { + command: nodeCommand, + args: ['node_modules/vite/bin/vite.js'], + options: { + env: { ...env }, + stdio: 'inherit', + }, + }, + }; +} + +export function startDevServers({ + spawnProcess = spawn, + specs = createDevProcessSpecs(), +} = {}) { + const roda = spawnProcess(specs.roda.command, specs.roda.args, specs.roda.options); + const vite = spawnProcess(specs.vite.command, specs.vite.args, specs.vite.options); + let shuttingDown = false; + let rodaErrorOutput = ''; + + roda.stderr?.on('data', (chunk) => { + const message = String(chunk); + rodaErrorOutput += message; + if (!message.includes('EADDRINUSE')) { + process.stderr.write(`[roda] ${message}`); + } + }); + + function stopChildren() { + shuttingDown = true; + if (!roda.killed) { + roda.kill(); + } + if (!vite.killed) { + vite.kill(); + } + } + + vite.on('exit', (code, signal) => { + shuttingDown = true; + if (!roda.killed) { + roda.kill(); + } + + if (signal) { + process.exitCode = 1; + return; + } + + process.exitCode = code ?? 0; + }); + + roda.on('exit', (code, signal) => { + if (shuttingDown) { + return; + } + + if (rodaErrorOutput.includes('EADDRINUSE')) { + process.stderr.write('[roda] Port 3000 is already in use; continuing with the existing RODA server.\n'); + return; + } + + const reason = signal ? `signal ${signal}` : `exit code ${code}`; + process.stderr.write(`[roda] server stopped unexpectedly (${reason})\n`); + if (!vite.killed) { + vite.kill(); + } + process.exitCode = code || 1; + }); + + process.once('SIGINT', stopChildren); + process.once('SIGTERM', stopChildren); + + return { roda, vite }; +} diff --git a/scripts/dev.js b/scripts/dev.js new file mode 100644 index 0000000..73df19f --- /dev/null +++ b/scripts/dev.js @@ -0,0 +1,3 @@ +import { startDevServers } from './dev-runner.js'; + +startDevServers(); diff --git a/vite.config.js b/vite.config.js index f076183..941ca2a 100644 --- a/vite.config.js +++ b/vite.config.js @@ -10,9 +10,11 @@ const rodaDashboardCacheTtlMs = 5 * 60 * 1000; const dashboardRequestHeaders = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36', }; +const rodaHost = process.env.RODA_HOST || '127.0.0.1'; +const rodaPort = process.env.RODA_PORT || '3000'; +const rodaTarget = `http://${rodaHost}:${rodaPort}`; let rodaDashboardHtmlCache; -let rodaDashboardDevCache = { html: '', timestamp: 0 }; function collectHtmlInputs(dir) { const inputs = {}; @@ -124,61 +126,20 @@ function embedRodaDashboardData() { }; } -function serveRodaDashboardApi() { - return { - name: 'serve-roda-dashboard-api', - configureServer(server) { - server.middlewares.use(async (req, res, next) => { - const requestUrl = new URL(req.url || '/', 'http://localhost'); - if (requestUrl.pathname !== '/api/dashboard') { - next(); - return; - } - - if (req.method !== 'GET' && req.method !== 'HEAD') { - res.writeHead(405, { 'Content-Type': 'text/plain; charset=utf-8' }); - res.end('METHOD_NOT_ALLOWED'); - return; - } - - const now = Date.now(); - try { - let html = rodaDashboardDevCache.html; - let cacheStatus = 'HIT'; - - if (!html || (now - rodaDashboardDevCache.timestamp) >= rodaDashboardCacheTtlMs) { - html = await requestRodaDashboardHtml(); - rodaDashboardDevCache = { html, timestamp: Date.now() }; - cacheStatus = 'MISS'; - } - - res.writeHead(200, { - 'Content-Type': 'text/html; charset=utf-8', - 'X-Cache': cacheStatus, - }); - res.end(req.method === 'HEAD' ? '' : html); - } catch (error) { - if (rodaDashboardDevCache.html) { - res.writeHead(200, { - 'Content-Type': 'text/html; charset=utf-8', - 'X-Cache': 'STALE', - }); - res.end(req.method === 'HEAD' ? '' : rodaDashboardDevCache.html); - return; - } - - const message = error instanceof Error ? error.message : String(error); - console.warn(`[roda-dashboard] Dev dashboard fetch failed: ${message}`); - res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' }); - res.end('DASHBOARD_FETCH_FAILED'); - } - }); - }, - }; -} - export default defineConfig({ - plugins: [serveRodaDashboardApi(), embedRodaDashboardData(), copyStaticAssets()], + plugins: [embedRodaDashboardData(), copyStaticAssets()], + server: { + proxy: { + '/groups/RODA/api/dashboard': { + target: rodaTarget, + changeOrigin: true, + }, + '/api/dashboard': { + target: rodaTarget, + changeOrigin: true, + }, + }, + }, build: { rollupOptions: { input: collectHtmlInputs(root), From 3d2f0b23adf67f0d3f96c0c7be47236db379d5d5 Mon Sep 17 00:00:00 2001 From: GuavaPopper Date: Fri, 5 Jun 2026 18:57:23 +0700 Subject: [PATCH 4/5] refactor: Perbaiki Proxy Pipeline dan simplify dashboard configuration --- groups/RODA/.env | 4 -- groups/RODA/index.html | 65 +++++++++----------------------- groups/RODA/server.js | 85 +++--------------------------------------- 3 files changed, 24 insertions(+), 130 deletions(-) delete mode 100644 groups/RODA/.env diff --git a/groups/RODA/.env b/groups/RODA/.env deleted file mode 100644 index b5545e4..0000000 --- a/groups/RODA/.env +++ /dev/null @@ -1,4 +0,0 @@ -DASHBOARD_TARGET_URL=https://dashboard.informatika.untan.ac.id/index.php?penelitian -DASHBOARD_PROXY_1=https://api.codetabs.com/v1/proxy?quest={{url}} -DASHBOARD_PROXY_2=https://api.allorigins.win/get?url={{url}}&ts={{ts}} -DASHBOARD_PROXY_3=https://thingproxy.freeboard.io/fetch/{{rawUrl}} \ No newline at end of file diff --git a/groups/RODA/index.html b/groups/RODA/index.html index 05b5752..70bbaf5 100644 --- a/groups/RODA/index.html +++ b/groups/RODA/index.html @@ -77,12 +77,6 @@ debugLogs: false, dashboardRuntimeFetch: 'always', dashboardApiUrl: 'api/dashboard', - dashboardTargetUrl: 'https://dashboard.informatika.untan.ac.id/index.php?penelitian', - dashboardProxyTemplates: [ - 'https://api.codetabs.com/v1/proxy?quest={{url}}', - 'https://api.allorigins.win/get?url={{url}}&ts={{ts}}', - 'https://thingproxy.freeboard.io/fetch/{{rawUrl}}' - ] }; @@ -1662,56 +1656,33 @@ } let lastError = null; + + if (isDashboardRuntimeFetchAllowed()) { + const dashboardApiUrl = window.APP_CONFIG?.dashboardApiUrl?.trim(); + + if (dashboardApiUrl) { + try { + const rows = await fetchProxyRows(dashboardApiUrl); + applyDashboardRows(rows); + return; + } catch (error) { + lastError = error; + } + } + } + + // Fallback ke data yang di-embed saat build jika runtime fetch gagal atau dinonaktifkan const embeddedHtml = readEmbeddedDashboardHtml(); if (embeddedHtml) { try { applyDashboardRows(parseDashboardRows(embeddedHtml)); return; } catch (error) { - lastError = error; + lastError = lastError || error; } } - if (!isDashboardRuntimeFetchAllowed()) { - renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(lastError || new Error('DASHBOARD_RUNTIME_FETCH_DISABLED')), 'Coba Lagi', 'fetchDashboardData()'); - return; - } - - const targetUrl = window.APP_CONFIG?.dashboardTargetUrl?.trim(); - const dashboardApiUrl = window.APP_CONFIG?.dashboardApiUrl?.trim(); - const proxyTemplates = Array.isArray(window.APP_CONFIG?.dashboardProxyTemplates) - ? window.APP_CONFIG.dashboardProxyTemplates.filter(Boolean) - : []; - - const proxyServers = dashboardApiUrl ? [() => dashboardApiUrl] : []; - - if (targetUrl) { - proxyTemplates.forEach((template) => { - proxyServers.push((url) => template - .replaceAll('{{url}}', encodeURIComponent(url)) - .replaceAll('{{rawUrl}}', url) - .replaceAll('{{ts}}', String(Date.now()))); - }); - } - - if (!proxyServers.length) { - renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(new Error('DASHBOARD_PROXY_NOT_CONFIGURED')), 'Coba Lagi', 'fetchDashboardData()'); - return; - } - - try { - const proxyUrls = proxyServers.map((getProxyUrl) => getProxyUrl(targetUrl)); - const rows = await Promise.any(proxyUrls.map((proxyUrl) => fetchProxyRows(proxyUrl))); - applyDashboardRows(rows); - return; - } catch (error) { - lastError = error instanceof AggregateError && error.errors?.length - ? error.errors[error.errors.length - 1] - : error; - } - - // Jika semua proxy gagal - renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(lastError), 'Coba Lagi', 'fetchDashboardData()'); + renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(lastError || new Error('DASHBOARD_RUNTIME_FETCH_DISABLED')), 'Coba Lagi', 'fetchDashboardData()'); } diff --git a/groups/RODA/server.js b/groups/RODA/server.js index 2bf9d4e..626f615 100644 --- a/groups/RODA/server.js +++ b/groups/RODA/server.js @@ -6,69 +6,21 @@ const { URL } = require('url'); const ROOT_DIR = __dirname; const PARENT_DIR = path.join(__dirname, '..', '..'); const INDEX_PATH = path.join(ROOT_DIR, 'index.html'); -const ENV_PATH = path.join(ROOT_DIR, '.env'); const HOST = process.env.HOST || '127.0.0.1'; const PORT = Number(process.env.PORT || 3000); -const DEFAULT_DASHBOARD_TARGET_URL = 'https://dashboard.informatika.untan.ac.id/index.php?penelitian'; +const DASHBOARD_TARGET_URL = 'https://dashboard.informatika.untan.ac.id/index.php?penelitian'; const RODA_PATH_PREFIX = '/groups/RODA'; function logServerError(scope, error, extra = {}) { console.error(`[${scope}]`, error && error.stack ? error.stack : error, extra); } -function parseEnvFile(filePath) { - if (!fs.existsSync(filePath)) { - return {}; - } - - const env = {}; - const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/); - - for (const rawLine of lines) { - const line = rawLine.trim(); - if (!line || line.startsWith('#')) { - continue; - } - - const separatorIndex = line.indexOf('='); - if (separatorIndex === -1) { - continue; - } - - const key = line.slice(0, separatorIndex).trim(); - let value = line.slice(separatorIndex + 1).trim(); - - if ( - (value.startsWith('"') && value.endsWith('"')) || - (value.startsWith("'") && value.endsWith("'")) - ) { - value = value.slice(1, -1); - } - - env[key] = value; - } - - return env; -} - function getAppConfig() { - const env = { - ...parseEnvFile(ENV_PATH), - ...process.env - }; - - const dashboardProxyTemplates = [ - env.DASHBOARD_PROXY_1, - env.DASHBOARD_PROXY_2, - env.DASHBOARD_PROXY_3 - ].filter(Boolean); - return { - debugLogs: env.DEBUG_LOGS === 'true', - dashboardRuntimeFetch: env.DASHBOARD_RUNTIME_FETCH || 'always', - dashboardApiUrl: env.DASHBOARD_API_URL || 'api/dashboard', - dashboardTargetUrl: env.DASHBOARD_TARGET_URL || DEFAULT_DASHBOARD_TARGET_URL, - dashboardProxyTemplates + debugLogs: false, + dashboardRuntimeFetch: 'always', + dashboardApiUrl: 'api/dashboard', + dashboardTargetUrl: DASHBOARD_TARGET_URL, }; } @@ -76,10 +28,6 @@ const DASHBOARD_CACHE_TTL_MS = 5 * 60 * 1000; let dashboardCache = { html: null, timestamp: 0 }; async function fetchDashboardHtml() { - const targetUrl = getAppConfig().dashboardTargetUrl; - if (!targetUrl) { - throw new Error('DASHBOARD_TARGET_URL kosong'); - } const now = Date.now(); if (dashboardCache.html && (now - dashboardCache.timestamp) < DASHBOARD_CACHE_TTL_MS) { @@ -89,7 +37,7 @@ async function fetchDashboardHtml() { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 12000); try { - const response = await fetch(targetUrl, { + const response = await fetch(DASHBOARD_TARGET_URL, { signal: controller.signal, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36' @@ -111,35 +59,14 @@ async function fetchDashboardHtml() { } } -function validateAppConfig(config) { - const errors = []; - - if (!config.dashboardTargetUrl) { - errors.push('DASHBOARD_TARGET_URL belum diisi.'); - } - - return errors; -} - function injectConfig(html) { const configScript = ``; - const defaultConfigScript = ''; - - if (html.includes(defaultConfigScript)) { - return html.replace(defaultConfigScript, configScript); - } - return html.replace('', ` ${configScript}\n`); } function sendHtml(res) { try { const html = fs.readFileSync(INDEX_PATH, 'utf8'); - const configErrors = validateAppConfig(getAppConfig()); - if (configErrors.length) { - logServerError('config', new Error('Invalid app config'), { configErrors }); - } - const withConfig = injectConfig(html); res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(withConfig); From 00611a921b78691b1f08d558101daef3df0708eb Mon Sep 17 00:00:00 2001 From: GuavaPopper Date: Fri, 5 Jun 2026 20:16:53 +0700 Subject: [PATCH 5/5] feat(RODA): data riset kini real-time via proxy Netlify --- groups/RODA/index.html | 2 +- groups/RODA/server.js | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/groups/RODA/index.html b/groups/RODA/index.html index 70bbaf5..5e38f45 100644 --- a/groups/RODA/index.html +++ b/groups/RODA/index.html @@ -76,7 +76,7 @@ window.APP_CONFIG = window.APP_CONFIG || { debugLogs: false, dashboardRuntimeFetch: 'always', - dashboardApiUrl: 'api/dashboard', + dashboardApiUrl: 'https://proxykbk.netlify.app/.netlify/functions/dashboard', }; diff --git a/groups/RODA/server.js b/groups/RODA/server.js index 626f615..73dfe38 100644 --- a/groups/RODA/server.js +++ b/groups/RODA/server.js @@ -146,17 +146,30 @@ const server = http.createServer((req, res) => { } if (pathname === '/api/dashboard' || pathname === `${RODA_PATH_PREFIX}/api/dashboard`) { + if (req.method === 'OPTIONS') { + res.writeHead(204, { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET', + }); + res.end(); + return; + } + fetchDashboardHtml() .then(({ html, cached }) => { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', - 'X-Cache': cached + 'Access-Control-Allow-Origin': '*', + 'X-Cache': cached, }); res.end(html); }) .catch((error) => { logServerError('api-dashboard', error); - res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' }); + res.writeHead(502, { + 'Content-Type': 'text/plain; charset=utf-8', + 'Access-Control-Allow-Origin': '*', + }); res.end('DASHBOARD_FETCH_FAILED'); }); return;