"""Serve the working-copy dashboard locally with API calls proxied to the live server, so browser-side changes can be checked against real data before deploy. Usage: python scripts/dev_proxy.py [port]""" import http.server import sys import urllib.request from pathlib import Path UPSTREAM = "https://water.buildfor.life" STATIC = Path(__file__).resolve().parents[1] / "src" / "static" class Handler(http.server.BaseHTTPRequestHandler): def do_GET(self): if self.path == "/" or self.path.startswith("/?"): body = (STATIC / "dashboard.html").read_bytes() self._send(200, "text/html; charset=utf-8", body) return if self.path.startswith("/static/"): f = STATIC / self.path[len("/static/"):].split("?")[0] if f.is_file(): ctype = "application/json" if f.suffix in (".json", ".geojson") else "application/octet-stream" self._send(200, ctype, f.read_bytes()) return try: req = urllib.request.Request( UPSTREAM + self.path, headers={"User-Agent": "Mozilla/5.0 (dev_proxy; +https://buildfor.life)", "Accept": "application/json"}, ) with urllib.request.urlopen(req, timeout=60) as r: self._send(r.status, r.headers.get("Content-Type", "application/json"), r.read()) except urllib.error.HTTPError as e: self._send(e.code, "application/json", e.read()) def _send(self, code, ctype, body): self.send_response(code) self.send_header("Content-Type", ctype) self.send_header("Content-Length", str(len(body))) self.send_header("Cache-Control", "no-store") self.end_headers() self.wfile.write(body) def log_message(self, *a): pass if __name__ == "__main__": port = int(sys.argv[1]) if len(sys.argv) > 1 else 8765 print(f"http://localhost:{port}/ (API -> {UPSTREAM})") http.server.ThreadingHTTPServer(("127.0.0.1", port), Handler).serve_forever()