From b2e2f22fa84ea0155d7b2cd8302e57533d589501 Mon Sep 17 00:00:00 2001 From: Time Date: Sun, 18 Oct 2026 05:14:07 +0000 Subject: [PATCH] card #95: update ventures/mdecks/tools/whop-check.sh --- ventures/mdecks/tools/whop-check.sh | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 ventures/mdecks/tools/whop-check.sh diff --git a/ventures/mdecks/tools/whop-check.sh b/ventures/mdecks/tools/whop-check.sh new file mode 100644 index 0000000..628d4d8 --- /dev/null +++ b/ventures/mdecks/tools/whop-check.sh @@ -0,0 +1,80 @@ +#!/bin/sh +# Checks the Whop build: builds it, verifies the checksum, unzips it, serves it the way a static host does +# (real files and directory index.html first, 404.html for anything else) and requests the view paths. +# +# ventures/mdecks/tools/whop-check.sh +set -eu + +here=$(cd "$(dirname "$0")" && pwd) +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT + +"$here/whop-build.sh" "$work/out" +(cd "$work/out" && sha256sum -c mdeck-whop.zip.sha256) +python3 -c 'import sys, zipfile; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])' "$work/out/mdeck-whop.zip" "$work/site" + +SITE="$work/site" python3 - <<'PY' +import http.server, os, threading, urllib.request, urllib.error + +site = os.environ["SITE"] + +class Static(http.server.SimpleHTTPRequestHandler): + def __init__(self, *a, **k): + super().__init__(*a, directory=site, **k) + def send_head(self): + path = self.translate_path(self.path) + if os.path.isdir(path) and not os.path.isfile(os.path.join(path, "index.html")): + path = None + if path is None or not (os.path.isdir(path) or os.path.isfile(path)): + self.path = "/404.html" + self.send_response_only(404) # replaced below + return self._fallback() + return super().send_head() + def _fallback(self): + body = open(os.path.join(site, "404.html"), "rb").read() + self.wfile.write(b"") # status line already sent by send_response_only + self.send_header("Content-Type", "text/html") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + import io + return io.BytesIO(body) + def log_message(self, *a): + pass + +srv = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Static) +threading.Thread(target=srv.serve_forever, daemon=True).start() +base = "http://127.0.0.1:%d" % srv.server_port + +def get(path): + try: + r = urllib.request.urlopen(base + path) + return r.status, r.read().decode() + except urllib.error.HTTPError as e: + return e.code, e.read().decode() + +failed = 0 +for path in ["/experiences/abc", "/experiences/abc/", "/experiences/a/b/c", "/dashboard/xyz", "/dashboard/xyz/", + "/experiences/", "/dashboard/", "/experiences", "/dashboard"]: + status, body = get(path) + ok = 'id="src"' in body and 'src="/app.js"' in body and 'src="/whop.js"' in body + print("%-22s %s serves the app: %s" % (path, status, "yes" if ok else "NO")) + failed += not ok + +for path, needle in [("/app.js", 'fetch("/SKILL.md")'), ("/whop.js", "data-view"), ("/SKILL.md", "mdeck")]: + status, body = get(path) + ok = status == 200 and needle in body + print("%-22s %s asset ok: %s" % (path, status, "yes" if ok else "NO")) + failed += not ok + +status, body = get("/experiences/abc") +for gone in ("Get early access", "Pricing", "early-note"): + if gone in body: + print("public-page content left in the app: " + gone) + failed += 1 +if 'id="agent"' not in body: + print("agent button missing") + failed += 1 + +raise SystemExit(1 if failed else 0) +PY +echo "whop build ok"