""" dev.py ====== This script acts as a local development orchestrator. 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()