Implement wiring hardening, runtime API config, smoke tests, and build scripts

This commit is contained in:
Ryan Lancaster
2026-03-17 12:58:43 -04:00
parent a3949c32ee
commit ca46302aff
19 changed files with 2358 additions and 77 deletions

View File

@@ -4,8 +4,18 @@ const fs = require('fs')
const isDev = process.env.NODE_ENV !== 'production'
const devUrl = 'http://localhost:5173'
const API_URL_KEY = 'runtime_api_url'
const DEFAULT_API_URL = process.env.VITE_API_URL || 'http://localhost:4000/api'
let mainWindow
function normalizeApiUrl(value) {
if (!value || typeof value !== 'string') return null
const trimmed = value.trim().replace(/\/+$/, '')
if (!trimmed) return null
if (!/^https?:\/\//i.test(trimmed)) return null
return /\/api$/i.test(trimmed) ? trimmed : `${trimmed}/api`
}
function getStoragePath() {
return path.join(app.getPath('userData'), 'storage.json')
}
@@ -31,9 +41,11 @@ function writeStorage(obj) {
}
}
ipcMain.handle('storage-get', () => {
ipcMain.handle('storage-get', (event, key) => {
const s = readStorage()
return s
if (!key) return s
if (!(key in s)) return null
return { value: s[key] }
})
ipcMain.handle('storage-set', (event, key, value) => {
@@ -50,7 +62,20 @@ ipcMain.handle('storage-remove', (event, key) => {
return true
})
ipcMain.handle('get-api-url', () => process.env.VITE_API_URL || 'http://localhost:4000/api')
ipcMain.handle('get-api-url', () => {
const s = readStorage()
return normalizeApiUrl(s[API_URL_KEY]) || normalizeApiUrl(DEFAULT_API_URL) || 'http://localhost:4000/api'
})
ipcMain.handle('set-api-url', (event, value) => {
const next = normalizeApiUrl(value)
if (!next) throw new Error('API URL must be a valid http(s) URL')
const s = readStorage()
s[API_URL_KEY] = next
writeStorage(s)
return next
})
function createWindow() {
mainWindow = new BrowserWindow({

View File

@@ -1,7 +1,8 @@
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('ENV', {
API_URL: process.env.VITE_API_URL || 'http://localhost:4000/api'
API_URL: process.env.VITE_API_URL || 'http://localhost:4000/api',
API_KEY: process.env.WRITE_API_KEY || process.env.VITE_WRITE_API_KEY || ''
})
contextBridge.exposeInMainWorld('app', {
@@ -10,5 +11,13 @@ contextBridge.exposeInMainWorld('app', {
set: (key, value) => ipcRenderer.invoke('storage-set', key, value),
remove: (key) => ipcRenderer.invoke('storage-remove', key)
},
getAPIUrl: () => ipcRenderer.invoke('get-api-url')
getAPIUrl: () => ipcRenderer.invoke('get-api-url'),
setAPIUrl: (url) => ipcRenderer.invoke('set-api-url', url)
})
// Backward-compatible alias used by the React app persistence wrapper.
contextBridge.exposeInMainWorld('storage', {
get: (key) => ipcRenderer.invoke('storage-get', key),
set: (key, value) => ipcRenderer.invoke('storage-set', key, value),
remove: (key) => ipcRenderer.invoke('storage-remove', key)
})