#!/usr/bin/env bash # # Apply our patches + overlay onto the cloned upstream repos. # Fails loudly if a patch no longer applies (upstream moved). # set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" apply_patches() { local name="$1" dir="$2" [ -d "patches/$name" ] || return 0 echo "==> [$name] applying patches" for patch in patches/"$name"/*.patch; do [ -e "$patch" ] || continue echo " - $(basename "$patch")" git -C "$dir" apply --3way "$ROOT/$patch" done } apply_patches ui httptoolkit-ui apply_patches server httptoolkit-server # `src/config.d.ts` is a types-only module: tsc erases `import { HtkConfig } from # './config'` entirely, but bun's bundler resolves imports for real and fails # ("Could not resolve: ./config") because a .d.ts isn't a bundleable source file. # Promote it to a real .ts module so bun can resolve it - it holds only exported # interfaces, so it compiles down to nothing. Derived from upstream rather than # vendored, so it can't drift out of sync with the real type. promote_dts_to_ts() { local dts="$1" ts="${1%.d.ts}.ts" [ -f "$dts" ] || { echo "!! expected $dts to exist (upstream moved?)"; exit 1; } # Anything other than exported type declarations would need real runtime code: if grep -qE '^\s*(declare|import|export\s+(const|let|var|function|class|default))' "$dts"; then echo "!! $dts is no longer types-only - it needs a real runtime module now" exit 1 fi echo " - $dts -> $ts" mv "$dts" "$ts" } echo "==> [server] promoting types-only modules to real modules (for bun)" promote_dts_to_ts httptoolkit-server/src/config.d.ts # Upstream targets es2020 and never sets useDefineForClassFields, so tsc defaults # it to false: class field initialisers are emitted *inside* the constructor, # after parameter properties are assigned. Bun ignores that inferred default and # emits native ES class fields, which run BEFORE the constructor body - so any # class doing `constructor(private config: X)` plus a field initialiser that # reads `this.config` (e.g. ElectronInterceptor.certData) crashes with # "undefined is not an object". Set the flag explicitly to restore tsc semantics. # APP_ROOT is derived from __dirname, which in a compiled binary is a build-machine # path that doesn't exist for users. Everything hanging off it then breaks at # runtime - OVERRIDES_DIR most visibly ("Unable to access jarfile # .../overrides/java-agent.jar", "lstat .../overrides/webextension"), which takes # out JVM/terminal interception and the WebRTC webextension. Make it overridable so # htk-entry.ts can point it at the directory it extracts the embedded overrides to. echo "==> [server] making APP_ROOT overridable via HTK_APP_ROOT" APP_ROOT_LINE="export const APP_ROOT = path.join(__dirname, '..');" if grep -qF "$APP_ROOT_LINE" httptoolkit-server/src/constants.ts; then sed -i "s|$APP_ROOT_LINE|export const APP_ROOT = process.env.HTK_APP_ROOT \|\| path.join(__dirname, '..');|" \ httptoolkit-server/src/constants.ts elif grep -q 'HTK_APP_ROOT' httptoolkit-server/src/constants.ts; then echo " - already applied" else echo "!! APP_ROOT definition not found in constants.ts (upstream moved?)"; exit 1 fi echo "==> [server] pinning useDefineForClassFields=false (tsc semantics for bun)" jq '.compilerOptions.useDefineForClassFields = false' \ httptoolkit-server/tsconfig.json > httptoolkit-server/tsconfig.json.tmp mv httptoolkit-server/tsconfig.json.tmp httptoolkit-server/tsconfig.json echo "==> Copying overlay into httptoolkit-server" cp -v overlay/server/htk-entry.ts httptoolkit-server/htk-entry.ts cp -v overlay/server/src/htk-app.ts httptoolkit-server/src/htk-app.ts cp -v overlay/server/src/commands/app.ts httptoolkit-server/src/commands/app.ts echo "==> patch.sh complete."