diff --git a/Makefile b/Makefile index ff26154..c601a92 100644 --- a/Makefile +++ b/Makefile @@ -59,17 +59,30 @@ RATE_LIMITED_ENVS := paseo dev-test # Default env when none is passed on the command line. ENV ?= paseo +# When this repo is checked out as truapi/hosts/dotli, local make builds should +# consume the checked-out TrUAPI packages instead of the temporary npm aliases. +TRUAPI_REPO ?= $(abspath ../..) +TRUAPI_LOCAL_PACKAGE := $(TRUAPI_REPO)/js/packages/truapi/package.json +TRUAPI_HOST_LOCAL_PACKAGE := $(TRUAPI_REPO)/js/packages/truapi-host/package.json + # Packages required on a fresh Ubuntu 22.04+ box. The brotli module is split # across two packages on noble (filter + static) and both ship a drop-in in # /etc/nginx/modules-enabled/ so they auto-load. curl and ca-certificates # back certbot's API calls. APT_PACKAGES := nginx libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static certbot python3-certbot-dns-cloudflare rsync ufw curl ca-certificates -.PHONY: build provision provision-prereqs provision-firewall provision-cloudflare-creds provision-cert provision-renewal deploy ci-deploy deploy-nginx render-nginx _require-env _require-env-name +.PHONY: build link-truapi-local provision provision-prereqs provision-firewall provision-cloudflare-creds provision-cert provision-renewal deploy ci-deploy deploy-nginx render-nginx _require-env _require-env-name -build: +build: link-truapi-local bun run build +link-truapi-local: + @if [ -f "$(TRUAPI_LOCAL_PACKAGE)" ] && [ -f "$(TRUAPI_HOST_LOCAL_PACKAGE)" ]; then \ + TRUAPI_REPO="$(TRUAPI_REPO)" bun run link:truapi; \ + else \ + echo "No local TrUAPI checkout found at $(TRUAPI_REPO); using package manager dependencies."; \ + fi + # ==================================================================== # Fresh-server provisioning. Idempotent; safe to re-run. # diff --git a/README.md b/README.md index 2ee0da8..74f7d6f 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,26 @@ bun install bun run preview # Build + serve both apps on localhost:5173 ``` +The TrUAPI packages are installed from temporary npm aliases while the Rust core +port is in review. To iterate against a local truapi checkout instead, run: + +```bash +bun run link:truapi +``` + +When dotli is not checked out under `truapi/hosts/dotli`, point the script at +the truapi repo: + +```bash +TRUAPI_REPO=/path/to/truapi bun run link:truapi +``` + +Return to the package versions recorded in `bun.lock` with: + +```bash +bun run unlink:truapi +``` + Local development uses wildcard subdomains: - `host-playground.localhost:5173` — resolves `host-playground.dot` via the host diff --git a/package.json b/package.json index 8947506..3f36ad7 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "format:check": "prettier --check \"**/*.{ts,tsx,md}\"", "typecheck": "turbo run typecheck", "set-version": "bun scripts/set-version.ts", + "link:truapi": "bun scripts/link-truapi-local.ts", + "unlink:truapi": "bun scripts/unlink-truapi-local.ts", "clean": "find . -type d \\( -name node_modules -o -name dist \\) -prune -exec rm -rf {} +" }, "devDependencies": { diff --git a/scripts/link-truapi-local.ts b/scripts/link-truapi-local.ts new file mode 100644 index 0000000..e9681ff --- /dev/null +++ b/scripts/link-truapi-local.ts @@ -0,0 +1,60 @@ +import { spawnSync } from "node:child_process"; +import { existsSync, readFileSync, rmSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const dotliRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const truapiRoot = resolve( + process.env.TRUAPI_REPO ?? resolve(dotliRoot, "../.."), +); + +const packages = [ + { + name: "@parity/truapi", + path: resolve(truapiRoot, "js/packages/truapi"), + }, + { + name: "@parity/truapi-host", + path: resolve(truapiRoot, "js/packages/truapi-host"), + }, +]; + +function run(args: string[], cwd: string): void { + const result = spawnSync("bun", args, { cwd, stdio: "inherit" }); + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +function assertPackage(expectedName: string, path: string): void { + const packageJsonPath = resolve(path, "package.json"); + if (!existsSync(packageJsonPath)) { + throw new Error( + `Cannot find ${expectedName} at ${path}. Set TRUAPI_REPO=/path/to/truapi if dotli is not inside the truapi checkout.`, + ); + } + + const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { + name?: string; + }; + if (packageJson.name !== expectedName) { + throw new Error( + `Expected ${packageJsonPath} to be ${expectedName}, got ${packageJson.name ?? ""}.`, + ); + } +} + +for (const pkg of packages) { + assertPackage(pkg.name, pkg.path); + run(["link"], pkg.path); +} + +const packageNames = packages.map((pkg) => pkg.name); +run(["link", ...packageNames], dotliRoot); + +for (const name of ["truapi", "truapi-host"]) { + rmSync(resolve(dotliRoot, "packages/ui/node_modules/@parity", name), { + force: true, + recursive: true, + }); +} diff --git a/scripts/unlink-truapi-local.ts b/scripts/unlink-truapi-local.ts new file mode 100644 index 0000000..618126f --- /dev/null +++ b/scripts/unlink-truapi-local.ts @@ -0,0 +1,25 @@ +import { spawnSync } from "node:child_process"; +import { rmSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const dotliRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const packageNames = ["truapi", "truapi-host"]; +const installRoots = [ + resolve(dotliRoot, "node_modules/@parity"), + resolve(dotliRoot, "packages/ui/node_modules/@parity"), +]; + +for (const root of installRoots) { + for (const name of packageNames) { + rmSync(resolve(root, name), { force: true, recursive: true }); + } +} + +const result = spawnSync("bun", ["install", "--force"], { + cwd: dotliRoot, + stdio: "inherit", +}); +if (result.status !== 0) { + process.exit(result.status ?? 1); +}