mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
fix: registration via direct Convex call + compact WM tab layout
- Sidecar calls Convex HTTP API directly (Vercel Attack Challenge Mode blocks server-side proxy). CONVEX_URL read from env, not hardcoded. - Rust injects CONVEX_URL into sidecar via option_env! (CI) / env var (dev) - GitHub Actions passes CONVEX_URL secret to all 4 build steps - Tighten WM tab CSS spacing so all content fits in one viewport
This commit is contained in:
4
.github/workflows/build-desktop.yml
vendored
4
.github/workflows/build-desktop.yml
vendored
@@ -192,6 +192,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VITE_VARIANT: full
|
||||
VITE_DESKTOP_RUNTIME: '1'
|
||||
CONVEX_URL: ${{ secrets.CONVEX_URL }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }}
|
||||
@@ -215,6 +216,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VITE_VARIANT: full
|
||||
VITE_DESKTOP_RUNTIME: '1'
|
||||
CONVEX_URL: ${{ secrets.CONVEX_URL }}
|
||||
with:
|
||||
tagName: v__VERSION__
|
||||
releaseName: 'World Monitor v__VERSION__'
|
||||
@@ -232,6 +234,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VITE_VARIANT: tech
|
||||
VITE_DESKTOP_RUNTIME: '1'
|
||||
CONVEX_URL: ${{ secrets.CONVEX_URL }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }}
|
||||
@@ -256,6 +259,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VITE_VARIANT: tech
|
||||
VITE_DESKTOP_RUNTIME: '1'
|
||||
CONVEX_URL: ${{ secrets.CONVEX_URL }}
|
||||
with:
|
||||
tagName: v__VERSION__-tech
|
||||
releaseName: 'Tech Monitor v__VERSION__'
|
||||
|
||||
@@ -796,8 +796,12 @@ async function dispatch(requestUrl, req, routes, context) {
|
||||
}
|
||||
return json({ verboseMode });
|
||||
}
|
||||
// Registration proxy — forward to cloud (bypasses Vercel bot protection)
|
||||
// Registration — call Convex directly (Vercel Attack Challenge Mode blocks server-side)
|
||||
if (requestUrl.pathname === '/api/register-interest' && req.method === 'POST') {
|
||||
const convexUrl = process.env.CONVEX_URL;
|
||||
if (!convexUrl) {
|
||||
return json({ error: 'Registration service not configured' }, 503);
|
||||
}
|
||||
try {
|
||||
const body = await new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
@@ -805,21 +809,29 @@ async function dispatch(requestUrl, req, routes, context) {
|
||||
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
||||
req.on('error', reject);
|
||||
});
|
||||
const response = await fetchWithTimeout('https://worldmonitor.app/api/register-interest', {
|
||||
const parsed = JSON.parse(body);
|
||||
const email = parsed.email;
|
||||
if (!email || typeof email !== 'string' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
return json({ error: 'Invalid email address' }, 400);
|
||||
}
|
||||
const response = await fetchWithTimeout(`${convexUrl}/api/mutation`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Origin': 'https://worldmonitor.app',
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
},
|
||||
body,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
path: 'registerInterest:register',
|
||||
args: { email, source: parsed.source || 'desktop', appVersion: parsed.appVersion || 'unknown' },
|
||||
format: 'json',
|
||||
}),
|
||||
}, 15000);
|
||||
const responseBody = await response.text();
|
||||
return new Response(responseBody || '{}', {
|
||||
status: response.status,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
let result;
|
||||
try { result = JSON.parse(responseBody); } catch { result = { status: 'registered' }; }
|
||||
if (result.status === 'error') {
|
||||
return json({ error: result.errorMessage || 'Registration failed' }, 500);
|
||||
}
|
||||
return json(result.value || result);
|
||||
} catch (e) {
|
||||
logVerbose(`[register-interest] error: ${e.message}`);
|
||||
return json({ error: 'Registration service unreachable' }, 502);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,6 +733,13 @@ fn start_local_api(app: &AppHandle) -> Result<(), String> {
|
||||
}
|
||||
append_desktop_log(app, "INFO", &format!("injected {secret_count} keychain secrets into sidecar env"));
|
||||
|
||||
// Inject build-time secrets (CI) with runtime env fallback (dev)
|
||||
if let Some(url) = option_env!("CONVEX_URL") {
|
||||
cmd.env("CONVEX_URL", url);
|
||||
} else if let Ok(url) = std::env::var("CONVEX_URL") {
|
||||
cmd.env("CONVEX_URL", url);
|
||||
}
|
||||
|
||||
let child = cmd
|
||||
.spawn()
|
||||
.map_err(|e| format!("Failed to launch local API: {e}"))?;
|
||||
|
||||
@@ -605,28 +605,27 @@ tr.diag-err td { color: var(--settings-red); }
|
||||
/* Hero banner */
|
||||
.wm-hero {
|
||||
text-align: center;
|
||||
padding: 28px 24px;
|
||||
margin-bottom: 28px;
|
||||
padding: 18px 20px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid rgba(52, 211, 153, 0.15);
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(180deg, rgba(52, 211, 153, 0.04) 0%, transparent 100%);
|
||||
}
|
||||
|
||||
.wm-hero-title {
|
||||
margin: 0 0 12px;
|
||||
font-size: 24px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: var(--settings-text);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.wm-hero-desc {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: var(--settings-text-secondary);
|
||||
line-height: 1.6;
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
font-size: 13px;
|
||||
color: var(--settings-text-secondary);
|
||||
line-height: 1.5;
|
||||
max-width: 480px;
|
||||
}
|
||||
|
||||
/* OR divider */
|
||||
@@ -634,7 +633,7 @@ tr.diag-err td { color: var(--settings-red); }
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin: 24px 0;
|
||||
margin: 14px 0;
|
||||
color: var(--settings-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
@@ -650,43 +649,43 @@ tr.diag-err td { color: var(--settings-red); }
|
||||
|
||||
/* BYOK footer */
|
||||
.wm-byok {
|
||||
margin-top: 28px;
|
||||
padding: 16px 20px;
|
||||
margin-top: 14px;
|
||||
padding: 12px 16px;
|
||||
background: var(--settings-surface);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--settings-border);
|
||||
}
|
||||
|
||||
.wm-byok-title {
|
||||
margin: 0 0 4px;
|
||||
font-size: 14px;
|
||||
margin: 0 0 2px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--settings-text);
|
||||
}
|
||||
|
||||
.wm-byok-desc {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
color: var(--settings-text-secondary);
|
||||
line-height: 1.5;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.wm-section {
|
||||
margin-bottom: 24px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.wm-section-title {
|
||||
margin: 0 0 4px;
|
||||
font-size: 15px;
|
||||
margin: 0 0 2px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--settings-text);
|
||||
}
|
||||
|
||||
.wm-section-desc {
|
||||
margin: 0 0 12px;
|
||||
font-size: 13px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
color: var(--settings-text-secondary);
|
||||
line-height: 1.5;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.wm-key-row {
|
||||
|
||||
Reference in New Issue
Block a user