Files
claudetools/projects/dataforth-dos/tools/preview-proxy.py
Mike Swanson c2335e859d dataforth/testdatadb UI: fix cert fit (transform-scale) + publish-state chips
- fitCert: replace the flaky CSS `zoom` (Firefox support is recent/inconsistent)
  with transform:scale() measured against the widest line (+ right margin and
  font-load retries) so the cert always scales to fit the inspector with no
  horizontal clip. Validated live on a narrow 5B cert (0.74x) and a wide DSCA45
  cert (0.55x) against the real AD2 dataset.
- inspector Web field -> Published (green) / Not published (amber) chips.
- widen default inspector 480 -> 500px.
- tools/preview-proxy.py: serve the prototype AND reverse-proxy /api to the live
  AD2 server so the cert iframe is same-origin during preview — styleCert/fitCert
  read iframe.contentDocument, which silently no-ops when the iframe is loaded
  cross-origin straight from AD2 (why the fit looked broken in earlier previews).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 12:50:44 -07:00

55 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""
Same-origin preview proxy for the testdatadb front-end.
Serves the static prototype from ROOT and reverse-proxies /api/* to the live
AD2 testdatadb server, so the app AND the cert iframe share one origin
(http://127.0.0.1:PORT). That lets the same-origin-only cert styling/fit logic
(styleCert/fitCert read iframe.contentDocument) actually run during preview —
which it can't when the iframe is loaded cross-origin straight from AD2.
Usage: python preview-proxy.py <port> <root-dir> [target]
"""
import http.server, socketserver, urllib.request, urllib.error, os, sys
PORT = int(sys.argv[1])
ROOT = os.path.abspath(sys.argv[2]) if len(sys.argv) > 2 else "."
TARGET = sys.argv[3] if len(sys.argv) > 3 else "http://192.168.0.6:3000"
class H(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/api/"):
try:
with urllib.request.urlopen(TARGET + self.path, timeout=30) as r:
body = r.read(); ct = r.headers.get("Content-Type", "application/octet-stream")
self._send(200, ct, body)
except urllib.error.HTTPError as e:
self._send(e.code, "application/json", e.read())
except Exception as e:
self._send(502, "text/plain", str(e).encode())
else:
p = self.path.split("?")[0]
p = "/index.html" if p == "/" else p
fp = os.path.join(ROOT, p.lstrip("/"))
if os.path.isfile(fp):
ct = "text/html; charset=utf-8" if fp.endswith(".html") else "application/octet-stream"
self._send(200, ct, open(fp, "rb").read())
else:
self._send(404, "text/plain", b"not found")
def _send(self, code, ct, body):
self.send_response(code)
self.send_header("Content-Type", ct)
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
class S(socketserver.ThreadingTCPServer):
allow_reuse_address = True
print(f"preview proxy: http://127.0.0.1:{PORT} root={ROOT} -> {TARGET}")
S(("127.0.0.1", PORT), H).serve_forever()