#!/usr/bin/env bash # Build a per-module runtime image (novox/hq ADR 0052): the tool runtime carrying ONE module's # compiled code, which serves that module's tools and runs its events/provisioner under the module's # own scoped broker account. Generalises build-runtime-image.sh from the audit-logger to any module. # # build-module-runtime.sh # -> tags mesh-runtime-:development and saves it to set -euo pipefail MODULE="${1:?usage: build-module-runtime.sh }" OUT="${2:?usage: build-module-runtime.sh }" HERE="$(cd "$(dirname "$0")/.." && pwd)"; ROOT="$(cd "$HERE/.." && pwd)" MESH_TOOLS="${MESH_TOOLS:-$ROOT/mesh-tools}" MESH_SDK="${MESH_SDK:-$ROOT/mesh-sdk}" MESH_CATALOG="${MESH_CATALOG:-$ROOT/mesh-catalog}" MOD="$MESH_CATALOG/modules/$MODULE" TAG="${RUNTIME_TAG:-mesh-runtime-$MODULE:development}" BASE="${RUNTIME_BASE:-node:22-bookworm-slim}" [ -d "$MOD" ] || { echo "no module $MODULE at $MOD" >&2; exit 1; } ( cd "$MESH_SDK" && npm run build >/dev/null ) ( cd "$MESH_TOOLS" && npm run build >/dev/null ) # Compile whichever of the module's entrypoints exist. SRCS=(); for f in client.ts index.ts tools/index.ts provisioner/index.ts; do [ -f "$MOD/$f" ] && SRCS+=("$f"); done TSC="$MESH_SDK/node_modules/.bin/tsc"; ( cd "$MOD" && "$TSC" "${SRCS[@]}" --module NodeNext --moduleResolution NodeNext --target ES2022 --outDir dist >/dev/null ) STAGE="$(mktemp -d)"; trap 'rm -rf "$STAGE"' EXIT cp -r "$MESH_TOOLS/dist" "$STAGE/dist" cp -rL "$MESH_TOOLS/node_modules" "$STAGE/node_modules" mkdir -p "$STAGE/modules/$MODULE"; cp -r "$MOD/dist" "$STAGE/modules/$MODULE/dist" cp "$MESH_TOOLS/package.json" "$STAGE/package.json" # The entrypoints the runtime loads: tools, events and (a provider's) provisioner, whichever exist. ENTRIES=""; for e in tools/index.js index.js provisioner/index.js; do [ -f "$STAGE/modules/$MODULE/dist/$e" ] && ENTRIES="${ENTRIES:+$ENTRIES,}/app/modules/$MODULE/dist/$e" done # A module whose code drives a CLI needs that CLI in the image — postgres shells out to `psql`, minio # to `mc`. Everything else speaks a wire protocol or HTTP and needs nothing added. EXTRA="" case "$MODULE" in postgres) EXTRA='RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client && rm -rf /var/lib/apt/lists/*' ;; minio) EXTRA='COPY --from=minio/mc:latest /usr/bin/mc /usr/bin/mc' ;; esac cat > "$STAGE/Dockerfile" < $OUT"