""" dev.py ====== This script acts as a local development orchestrator. Instead of recreating the frontend in Python, which would violate the "Don't Repeat Yourself" (DRY) principle and introduce massive technical debt, this script leverages the existing architecture. It performs three main actions sequentially: 1. Executes `roi.py` to fetch the latest market data and generate the frontend JSON files. 2. Executes the `bun run build` command to compile the TypeScript frontend into browser-ready JavaScript. 3. Spawns a local Python HTTP server pointing to the `www/` directory so you can view the changes in your browser. """ import os # Required for changing working directories and checking paths. import subprocess # Required for spawning external processes (like 'bun' and other python scripts). import sys # Required to grab the current Python executable path. import http.server # Required to run the local web server. import socketserver # Required to bind the HTTP handler to a specific port. def main() -> None: """ Main execution function for the local development server orchestrator. """ # ------------------------------------------------------------------------- # STEP 1: GENERATE BACKEND DATA # ------------------------------------------------------------------------- # We first need to ensure that the JSON data files that the frontend consumes # actually exist and are up to date. We do this by calling the existing `roi.py` script. print(">>> [1/3] Running roi.py to generate updated JSON data...") try: # sys.executable ensures we use the exact same Python interpreter currently running this script. # check=True ensures that if roi.py crashes, this script will also halt and raise a CalledProcessError. subprocess.run([sys.executable, "roi.py"], check=True) except subprocess.CalledProcessError as e: # If roi.py fails, we catch the error, print a helpful message, and exit the program gracefully # instead of spitting out a massive unhandled stack trace. sys.exit(f"!!! Error: Failed to execute roi.py. Process exited with code {e.returncode}") # ------------------------------------------------------------------------- # STEP 2: BUILD THE FRONTEND # ------------------------------------------------------------------------- # The frontend is written in TypeScript (inside the ts/ folder). Browsers cannot natively # execute TypeScript in the way this project is structured. As outlined in `package.json`, # 'bun' is used as the bundler to compile these files into the 'www/' directory. print(">>> [2/3] Building the TypeScript frontend using Bun...") try: # We invoke the 'build' script defined in package.json. # This corresponds to: "bun build ts/buy.ts ... --outdir www --target browser --sourcemap=external" subprocess.run(["bun", "run", "build"], check=True) except FileNotFoundError: # If 'bun' is not installed or not in the system's PATH, a FileNotFoundError is raised. # We must alert the user that this system dependency is missing. sys.exit("!!! Error: 'bun' command not found. Please ensure Bun is installed (https://bun.sh/) and in your PATH.") except subprocess.CalledProcessError as e: # Catch compilation errors in the TypeScript code itself. sys.exit(f"!!! Error: Frontend build failed. Bun exited with code {e.returncode}") # ------------------------------------------------------------------------- # STEP 3: SERVE THE FRONTEND LOCALLY # ------------------------------------------------------------------------- # We must serve the compiled files via an HTTP server because opening local HTML files # directly (via file:// protocol) often causes CORS (Cross-Origin Resource Sharing) errors # when the JavaScript attempts to fetch the local JSON files generated in Step 1. print(">>> [3/3] Starting local development server...") # Define the port we want to host the site on. 8000 is a standard web development port. PORT = 8000 # Define the directory we want to serve. The bun build step outputs to 'www'. WEB_DIR = "www" # We must ensure the 'www' directory exists before attempting to switch into it. if not os.path.isdir(WEB_DIR): sys.exit(f"!!! Error: Directory '{WEB_DIR}' does not exist. The build step may have failed silently.") # Change the current working directory to 'www'. This ensures the HTTP server roots itself here, # making the index.html inside 'www' the default page, and allowing relative path resolutions to work. os.chdir(WEB_DIR) # http.server.SimpleHTTPRequestHandler is a built-in handler that serves files from the current directory. Handler = http.server.SimpleHTTPRequestHandler # socketserver.TCPServer creates a TCP server that listens on the specified port and binds our handler to it. # We use a 'with' block to ensure the network socket is properly released and cleaned up when the server stops. with socketserver.TCPServer(("", PORT), Handler) as httpd: print(f">>> Serving at http://localhost:{PORT}") print(">>> Press Ctrl+C to stop the server.") try: # serve_forever() puts the script into an infinite loop, constantly listening for and fulfilling HTTP requests. httpd.serve_forever() except KeyboardInterrupt: # Catch the Ctrl+C command from the user to gracefully shut down the server. print("\n>>> Shutting down development server gracefully. Goodbye!") if __name__ == '__main__': # This standard Python idiom ensures that the main() function is only called if this script # is executed directly from the command line (e.g., `python dev.py`), rather than imported as a module. main()