From 72e20b2243200b88425b4a3994c2ba19340deb12 Mon Sep 17 00:00:00 2001 From: "Marcus R. Brown" Date: Sun, 31 May 2026 00:16:51 -0700 Subject: [PATCH] fix(gateway): inline runtime into bundle to fix image crash-loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gateway bundle imported @fro-bot/runtime as an external specifier that resolved to its src/index.ts entry, which is absent from the runtime image — crash-looping on boot with ERR_MODULE_NOT_FOUND. Inline the runtime into the gateway bundle (matching the action tier), drop the now-dead runtime copy from the image, and add a CI smoke that builds and boots the image to catch packaging regressions. Fixes #707 --- .github/workflows/ci.yaml | 45 +++++++++++++++++++++++++++++++ deploy/gateway.Dockerfile | 2 -- packages/gateway/tsdown.config.ts | 4 +++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 80d97cb5..2ebb5b65 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -228,6 +228,51 @@ jobs: echo "OpenCode state files:" ls -lA ~/.local/state/opencode || true + gateway-smoke: + if: ${{ github.event_name == 'push' || needs.setup.outputs.should-build == 'true' }} + name: Gateway Image Smoke Test + needs: [setup] + permissions: + contents: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup Node.js and pnpm + uses: ./.github/actions/setup + - name: Build runtime + run: pnpm --filter @fro-bot/runtime build + - name: Build gateway + run: pnpm --filter @fro-bot/gateway build + - name: Assert no bare @fro-bot/runtime import in gateway bundle + run: | + if grep -q 'from "@fro-bot/runtime"' packages/gateway/dist/main.mjs; then + echo "REGRESSION: gateway dist has bare @fro-bot/runtime import" + exit 1 + fi + echo "OK: no bare @fro-bot/runtime import found in gateway bundle" + - name: Build gateway Docker image + run: docker build -f deploy/gateway.Dockerfile -t fro-bot-gateway:smoke . + - name: Smoke-test gateway image (assert config load, not module crash) + run: | + set +e + output="$(timeout 60s docker run --rm fro-bot-gateway:smoke 2>&1)" + status=$? + set -e + echo "--- docker run output ---" + echo "$output" + echo "--- exit status: $status ---" + if [ "$status" -eq 124 ]; then + echo "REGRESSION: gateway image hung on boot (timed out)" + exit 1 + fi + test "$status" -ne 0 + echo "$output" | grep -q "Missing required secret: DISCORD_TOKEN" + if echo "$output" | grep -q "ERR_MODULE_NOT_FOUND"; then + echo "REGRESSION: module resolution failed (ERR_MODULE_NOT_FOUND)" + exit 1 + fi + echo "OK: gateway reached config loading (DISCORD_TOKEN check), no module-resolution crash" + dependency-review: if: ${{ github.event_name == 'pull_request' }} name: Dependency Review diff --git a/deploy/gateway.Dockerfile b/deploy/gateway.Dockerfile index 6f6ecc14..74838397 100644 --- a/deploy/gateway.Dockerfile +++ b/deploy/gateway.Dockerfile @@ -31,8 +31,6 @@ WORKDIR /app # Copy production node_modules from build stage COPY --from=build /workspace/node_modules ./node_modules -COPY --from=build /workspace/packages/runtime/package.json ./packages/runtime/package.json -COPY --from=build /workspace/packages/runtime/dist/ ./packages/runtime/dist/ COPY --from=build /workspace/packages/gateway/package.json ./packages/gateway/package.json COPY --from=build /workspace/packages/gateway/dist/ ./packages/gateway/dist/ diff --git a/packages/gateway/tsdown.config.ts b/packages/gateway/tsdown.config.ts index 68cac3d0..c2dd2d7c 100644 --- a/packages/gateway/tsdown.config.ts +++ b/packages/gateway/tsdown.config.ts @@ -4,4 +4,8 @@ export default defineConfig({ entry: ['src/main.ts'], format: 'esm', outDir: 'dist', + noExternal: id => { + if (id === '@fro-bot/runtime' || id.startsWith('@fro-bot/runtime/')) return true + return false + }, })