feat(variants): wire energy.worldmonitor.app subdomain (gaps #9-11) (#3394)

DNS (Cloudflare) and the Vercel domain are already provisioned by the
operator; this lands the matching code-side wiring so the variant
actually resolves and renders correctly.

Changes:

middleware.ts
- Add `'energy.worldmonitor.app': 'energy'` to VARIANT_HOST_MAP. This
  also auto-includes the host in ALLOWED_HOSTS via the spread on
  line 87.
- Add `energy` entry to VARIANT_OG with the Energy-Atlas-specific
  title + description from `src/config/variant-meta.ts:130-152`. OG
  image points at `https://energy.worldmonitor.app/favico/energy/og-image.png`,
  matching the per-variant convention used by tech / finance /
  commodity / happy.

vercel.json
- Add `https://energy.worldmonitor.app` to BOTH `frame-src` and
  `frame-ancestors` in the global Content-Security-Policy header.
  Without this, the variant subdomain would render but be blocked
  from being framed back into worldmonitor.app for any embedded
  flow (Slack/LinkedIn previews, future iframe widgets, etc.).
  This supersedes the CSP-only portion of PR #3359 (which mixed
  CSP with unrelated relay/military changes).

convex/payments/checkout.ts:108-117
- Add `https://energy.worldmonitor.app` to the checkout returnUrl
  allowlist. Without this, a PRO upgrade flow initiated from the
  energy subdomain would fail with "Invalid returnUrl" on Convex.

src-tauri/tauri.conf.json:32
- Add `https://energy.worldmonitor.app` to the Tauri desktop CSP
  frame-src so the desktop app can embed the variant the same way
  it embeds the other 4.

public/favico/energy/* (NEW, 7 files)
- Stub the per-variant favicon directory by copying the root-level
  WorldMonitor brand assets (android-chrome 192/512, apple-touch,
  favicon 16/32/ico, og-image). This keeps the launch unblocked
  on design assets — every referenced URL resolves with valid
  bytes from day one. Replace with energy-themed designs in a
  follow-up PR; the file paths are stable.

Other variant subdomains already on main (tech / finance / commodity /
happy) are unchanged. APP_HOSTS in src/services/runtime.ts already
admits any `*.worldmonitor.app` via `host.endsWith('.worldmonitor.app')`
on line 226, so no edit needed there.

Closes gaps §L #9, #10, #11 in
docs/internal/energy-atlas-registry-expansion.md.
This commit is contained in:
Elie Habib
2026-04-25 14:19:28 +04:00
committed by GitHub
parent 8f8213605f
commit 0500733541
11 changed files with 10 additions and 2 deletions

View File

@@ -113,6 +113,7 @@ async function _createCheckoutSession(
"https://finance.worldmonitor.app",
"https://commodity.worldmonitor.app",
"https://happy.worldmonitor.app",
"https://energy.worldmonitor.app",
new URL(siteUrl).origin,
]);
if (!allowedOrigins.has(parsedReturnUrl.origin)) {

View File

@@ -45,6 +45,7 @@ const VARIANT_HOST_MAP: Record<string, string> = {
'finance.worldmonitor.app': 'finance',
'commodity.worldmonitor.app': 'commodity',
'happy.worldmonitor.app': 'happy',
'energy.worldmonitor.app': 'energy',
};
// Source of truth: src/config/variant-meta.ts — keep in sync when variant metadata changes.
@@ -73,6 +74,12 @@ const VARIANT_OG: Record<string, { title: string; description: string; image: st
image: 'https://happy.worldmonitor.app/favico/happy/og-image.png',
url: 'https://happy.worldmonitor.app/',
},
energy: {
title: 'Energy Atlas - Real-Time Global Energy Intelligence Dashboard',
description: 'Real-time global energy atlas tracking oil and gas pipelines, storage facilities, chokepoints, fuel shortages, tanker flows, and disruption events worldwide.',
image: 'https://energy.worldmonitor.app/favico/energy/og-image.png',
url: 'https://energy.worldmonitor.app/',
},
};
const ALLOWED_HOSTS = new Set([

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -29,7 +29,7 @@
}
],
"security": {
"csp": "default-src 'self'; connect-src 'self' https: http://localhost:5173 http://127.0.0.1:* ws: wss: blob: data: https://abacus.worldmonitor.app; img-src 'self' data: blob: https:; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval' https://www.youtube.com https://abacus.worldmonitor.app https://*.clerk.accounts.dev; worker-src 'self' blob:; font-src 'self' data: https:; media-src 'self' data: blob: https: http://127.0.0.1:* http://localhost:*; frame-src 'self' http://127.0.0.1:* http://localhost:* https://worldmonitor.app https://tech.worldmonitor.app https://finance.worldmonitor.app https://commodity.worldmonitor.app https://happy.worldmonitor.app https://www.youtube.com https://www.youtube-nocookie.com https://webcams.windy.com https://*.clerk.accounts.dev;"
"csp": "default-src 'self'; connect-src 'self' https: http://localhost:5173 http://127.0.0.1:* ws: wss: blob: data: https://abacus.worldmonitor.app; img-src 'self' data: blob: https:; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval' https://www.youtube.com https://abacus.worldmonitor.app https://*.clerk.accounts.dev; worker-src 'self' blob:; font-src 'self' data: https:; media-src 'self' data: blob: https: http://127.0.0.1:* http://localhost:*; frame-src 'self' http://127.0.0.1:* http://localhost:* https://worldmonitor.app https://tech.worldmonitor.app https://finance.worldmonitor.app https://commodity.worldmonitor.app https://happy.worldmonitor.app https://energy.worldmonitor.app https://www.youtube.com https://www.youtube-nocookie.com https://webcams.windy.com https://*.clerk.accounts.dev;"
}
},
"bundle": {

View File

@@ -87,7 +87,7 @@
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=(self), accelerometer=(), autoplay=(self \"https://www.youtube.com\" \"https://www.youtube-nocookie.com\"), bluetooth=(), display-capture=(), encrypted-media=(self \"https://www.youtube.com\" \"https://www.youtube-nocookie.com\"), gyroscope=(), hid=(), idle-detection=(), magnetometer=(), midi=(), payment=(self \"https://checkout.dodopayments.com\" \"https://test.checkout.dodopayments.com\" \"https://pay.google.com\" \"https://hooks.stripe.com\" \"https://js.stripe.com\"), picture-in-picture=(self \"https://www.youtube.com\" \"https://www.youtube-nocookie.com\" \"https://challenges.cloudflare.com\"), screen-wake-lock=(), serial=(), usb=(), xr-spatial-tracking=(\"https://challenges.cloudflare.com\")" },
{ "key": "Content-Security-Policy", "value": "default-src 'self'; connect-src 'self' https: wss: blob: data: https://*.ingest.sentry.io https://*.ingest.us.sentry.io; img-src 'self' data: blob: https:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'sha256-LnMFPWZxTgVOr2VYwIh9mhQ3l/l3+a3SfNOLERnuHfY=' 'sha256-4Z2xtr1B9QQugoojE/nbpOViG+8l2B7CZVlKgC78AeQ=' 'sha256-903UI9my1I7mqHoiVeZSc56yd50YoRJTB2269QqL76w=' 'sha256-EytE6o1N8rwzpVFMrF+WvBZr2y5UhFLw79o1/4VqS0s=' 'wasm-unsafe-eval' https://www.youtube.com https://static.cloudflareinsights.com https://vercel.live https://challenges.cloudflare.com https://*.clerk.accounts.dev https://abacus.worldmonitor.app https://*.dodopayments.com https://js.stripe.com; worker-src 'self' blob:; font-src 'self' data: https:; media-src 'self' data: blob: https:; frame-src 'self' https://worldmonitor.app https://tech.worldmonitor.app https://finance.worldmonitor.app https://commodity.worldmonitor.app https://happy.worldmonitor.app https://www.youtube.com https://www.youtube-nocookie.com https://www.google.com https://webcams.windy.com https://challenges.cloudflare.com https://*.clerk.accounts.dev https://vercel.live https://*.vercel.app https://*.dodopayments.com https://pay.google.com https://hooks.stripe.com https://js.stripe.com; frame-ancestors 'self' https://www.worldmonitor.app https://tech.worldmonitor.app https://finance.worldmonitor.app https://commodity.worldmonitor.app https://happy.worldmonitor.app https://worldmonitor.app https://vercel.live https://*.vercel.app; base-uri 'self'; object-src 'none'; form-action 'self' https://api.worldmonitor.app" }
{ "key": "Content-Security-Policy", "value": "default-src 'self'; connect-src 'self' https: wss: blob: data: https://*.ingest.sentry.io https://*.ingest.us.sentry.io; img-src 'self' data: blob: https:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'sha256-LnMFPWZxTgVOr2VYwIh9mhQ3l/l3+a3SfNOLERnuHfY=' 'sha256-4Z2xtr1B9QQugoojE/nbpOViG+8l2B7CZVlKgC78AeQ=' 'sha256-903UI9my1I7mqHoiVeZSc56yd50YoRJTB2269QqL76w=' 'sha256-EytE6o1N8rwzpVFMrF+WvBZr2y5UhFLw79o1/4VqS0s=' 'wasm-unsafe-eval' https://www.youtube.com https://static.cloudflareinsights.com https://vercel.live https://challenges.cloudflare.com https://*.clerk.accounts.dev https://abacus.worldmonitor.app https://*.dodopayments.com https://js.stripe.com; worker-src 'self' blob:; font-src 'self' data: https:; media-src 'self' data: blob: https:; frame-src 'self' https://worldmonitor.app https://tech.worldmonitor.app https://finance.worldmonitor.app https://commodity.worldmonitor.app https://happy.worldmonitor.app https://energy.worldmonitor.app https://www.youtube.com https://www.youtube-nocookie.com https://www.google.com https://webcams.windy.com https://challenges.cloudflare.com https://*.clerk.accounts.dev https://vercel.live https://*.vercel.app https://*.dodopayments.com https://pay.google.com https://hooks.stripe.com https://js.stripe.com; frame-ancestors 'self' https://www.worldmonitor.app https://tech.worldmonitor.app https://finance.worldmonitor.app https://commodity.worldmonitor.app https://happy.worldmonitor.app https://energy.worldmonitor.app https://worldmonitor.app https://vercel.live https://*.vercel.app; base-uri 'self'; object-src 'none'; form-action 'self' https://api.worldmonitor.app" }
]
},
{