Skip to content

Conversation

@notrab
Copy link
Member

@notrab notrab commented Jan 19, 2026

Lite PR

Summary

  1. Added openapi:generate script to fetch and save OpenAPI spec from ENSApi
  2. Updated Mintlify docs to use production URL for live API docs, committed file for PR previews
  3. Added CI job to validate committed openapi.json stays in sync with production

Closes #1532
Closes #1475


Why

Production API docs were getting out of sync with deployed API, and there was no way to preview API doc changes in PRs.

This setup ensures:

  • Production docs always reflect the live API (via runtime URL)
  • PR previews show upcoming API changes (via committed file)
  • CI catches drift between committed spec and production

Testing

  • Ran pnpm --filter ensapi openapi:generate locally to verify spec generation
  • Verified Biome formatting works on generated output
  • CI workflow syntax validated

Notes for Reviewer (Optional)

  • Requires curl step inside the switch environment to trigger production build using the Mintlify API.
  • MINTLIFY_API_TOKEN secret and MINTLIFY_PROJECT_ID variable need added to to GitHub for the environment switch workflow
  • The hidden "Preview" page in docs is for internal use during PR reviews
  • CI check will fail on PRs where API changes haven't been reflected in the committed `openapi.json

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Copilot AI review requested due to automatic review settings January 19, 2026 13:32
@vercel
Copy link

vercel bot commented Jan 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Review Updated (UTC)
admin.ensnode.io Skipped Skipped Jan 28, 2026 3:58pm
ensnode.io Skipped Skipped Jan 28, 2026 3:58pm
ensrainbow.io Skipped Skipped Jan 28, 2026 3:58pm

@changeset-bot
Copy link

changeset-bot bot commented Jan 19, 2026

🦋 Changeset detected

Latest commit: 1a94122

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@docs/mintlify Patch
ensapi Patch
ensindexer Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
@ensnode/datasources Patch
@ensnode/ensrainbow-sdk Patch
@ensnode/ponder-metadata Patch
@ensnode/ensnode-schema Patch
@ensnode/ensnode-react Patch
@ensnode/ponder-subgraph Patch
@ensnode/ensnode-sdk Patch
@ensnode/shared-configs Patch
@docs/ensnode Patch
@docs/ensrainbow Patch
@namehash/ens-referrals Patch
@namehash/namehash-ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Jan 19, 2026

📝 Walkthrough

Walkthrough

Adds OpenAPI generation and validation: ENSApi can run in OPENAPI_GENERATE_MODE to serve /openapi.json; a CLI fetches/writes the spec; CI starts ENSApi, polls /openapi.json, compares generated vs committed spec and validates with Mintlify; docs gain a hidden preview page and README guidance.

Changes

Cohort / File(s) Summary
CI / Workflows
​.github/workflows/test_ci.yml, ​.github/workflows/deploy_switch_ensnode_environment.yml
New openapi-sync-check job that starts ENSApi with OPENAPI_GENERATE_MODE, polls /openapi.json, generates/compares spec and runs Mintlify validation; added Mintlify rebuild trigger and failure notification step.
OpenAPI generator CLI
docs/docs.ensnode.io/scripts/generate-openapi.ts, docs/docs.ensnode.io/package.json
New generate-openapi.ts CLI (invoked via openapi:generate) that fetches /openapi.json, validates structure, writes docs/docs.ensnode.io/openapi.json, and runs Biome formatting; includes robust timeout/error handling.
Docs content & config
docs/docs.ensnode.io/docs.json, docs/docs.ensnode.io/ensapi/preview.mdx, docs/docs.ensnode.io/README.md, docs/docs.ensnode.io/openapi.json*
API Reference switched to production openapi URL; added hidden "Preview" group referencing local openapi.json, new preview MDX page, and README guidance about generation, CI, and Mintlify behavior.
ENSApi config & env
apps/ensapi/src/config/config.schema.ts, apps/ensapi/src/config/openapi-mock-config.ts, apps/ensapi/src/config/environment.ts, apps/ensapi/.env.local.example
Introduced OPENAPI_GENERATE_MODE, added buildOpenApiMockConfig and early-return in config loader so ENSApi can boot with a mock config serving /openapi.json without external services; documented example env entries.
Changesets & workspace
.changeset/bright-waves-flow.md, .changeset/gentle-clouds-dance.md, pnpm-workspace.yaml
Added changesets describing docs/OpenAPI additions and minor workspace catalog edits (ordering/quoting); no runtime behavior changes beyond docs and CI.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant ENS as ENSApi (OPENAPI_GENERATE_MODE)
    participant Gen as generate-openapi.ts
    participant Repo as Repo (docs/openapi.json)
    participant Mint as Mintlify API

    GH->>ENS: start ENSApi with OPENAPI_GENERATE_MODE=true
    activate ENS
    ENS->>ENS: load mock config, expose /openapi.json
    GH->>Gen: run readiness loop (poll /openapi.json)
    loop poll until ready or timeout
        Gen->>ENS: GET /openapi.json
    end
    Gen->>Gen: validate JSON, format, write `docs/docs.ensnode.io/openapi.json`
    Gen->>Repo: update generated spec file
    GH->>GH: diff generated spec vs committed `docs/docs.ensnode.io/openapi.json`
    alt specs match
        GH->>Mint: submit spec for Mintlify validation
        Mint-->>GH: validation result
    else specs differ
        GH->>GH: fail job and emit remediation guidance
    end
    deactivate ENS
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Linked issues this PR could address

  • #1532 — Adds Mintlify validation/preview checks and a docs preview path, supporting Mintlify preview environments for PRs.
  • #1475 — Implements automated OpenAPI generation, previewing, and validation to help keep ENSApi documentation accurate.

Poem

🐰 I hopped to a server late at night,

Mocked a world so the schema shone bright,
I fetched and formatted each path in sight,
CI checked the branch, Mintlify took flight —
Docs now blossom where APIs alight.

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'openapi spec / docs poc' is vague and uses non-descriptive terms like 'poc' without clarifying what is being accomplished. Use a more specific title that describes the main change, such as 'Add OpenAPI spec generation and Mintlify preview support' or 'Implement automatic OpenAPI spec sync and PR preview documentation'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description follows the template structure with clear Summary, Why, Testing, Notes, and Checklist sections addressing the key changes and rationale.
Linked Issues check ✅ Passed All PR changes directly address the linked issues: #1532 (Mintlify preview environments on PRs) and #1475 (ENSApi docs), with spec generation, PR preview setup, and CI validation implemented.
Out of Scope Changes check ✅ Passed All changes are in scope: adding the openapi:generate script, updating Mintlify docs config, adding CI validation job, and supporting infrastructure changes are all directly related to the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch openapi-spec-generator

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds OpenAPI specification generation and documentation capabilities to the ENSNode project. It introduces a script to fetch and save the OpenAPI spec from a running ENSApi instance, integrates it with Mintlify documentation, and adds CI checks to ensure the spec stays in sync with production.

Changes:

  • Added a 5,106-line OpenAPI specification file documenting all ENSApi endpoints
  • Created a generation script to fetch and update the spec from a running instance
  • Configured Mintlify docs to reference both production and local OpenAPI specs
  • Added CI workflow to validate spec synchronization on the main branch

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
docs/docs.ensnode.io/openapi.json Complete OpenAPI 3.1.0 specification documenting all ENSApi endpoints including resolution, meta, explore, and ENSAwards APIs
apps/ensapi/scripts/generate-openapi.ts TypeScript script to fetch OpenAPI spec from running instance and save to docs directory
apps/ensapi/package.json Added npm script openapi:generate to run the generation script
docs/docs.ensnode.io/docs.json Updated configuration to reference production API spec and added hidden preview section for local spec
.github/workflows/test_ci.yml Added CI job to verify OpenAPI spec stays in sync with production on main branch

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @.github/workflows/test_ci.yml:
- Around line 51-55: The openapi-sync-check job currently only runs when
github.ref == 'refs/heads/main', which lets PRs merge with out-of-sync specs;
update the condition on the openapi-sync-check job (the if: line) to also run
for pull requests (e.g., include github.event_name == 'pull_request' or
github.head_ref checks) and mark it non-blocking for PRs by using
continue-on-error: true (or alternatively remove the if entirely and rely on
branch protection or add contributor documentation). Target the job named
openapi-sync-check and the existing if: github.ref == 'refs/heads/main'
condition when making the change.

In `@apps/ensapi/scripts/generate-openapi.ts`:
- Around line 23-24: ensapiUrl may end with a trailing slash causing openapiUrl
to become "//openapi.json"; normalize ensapiUrl before composing openapiUrl (the
variables to change are ensapiUrl and openapiUrl in generate-openapi.ts) by
trimming any trailing '/' from ensapiUrl (or using a URL-safe join) so
openapiUrl is built as `${normalizedEnsapiUrl}/openapi.json` even when
ENSAPI_URL or process.argv[2] includes a trailing slash; ensure
DEFAULT_ENSAPI_URL remains fallback and normalization runs after selecting the
value.
- Line 12: Update the header comment string that reads "Writes openapi.json to
the docs directory for Mintilify" and correct the product name typo to
"Mintlify" so the comment reads "Writes openapi.json to the docs directory for
Mintlify"; locate this exact comment text in generate-openapi.ts and make the
single-word change.
- Around line 28-33: Add a timeout to the fetch in generate-openapi.ts by
creating an AbortSignal via AbortSignal.timeout(ms) and passing it as the signal
option to the fetch(openapiUrl) call; handle the abort case by catching the
thrown error (check for AbortError or error.name === 'AbortError') and log a
clear timeout message before exiting, and ensure the existing non-ok response
handling remains unchanged.

In `@docs/docs.ensnode.io/docs.json`:
- Around line 29-34: The docs.json "Preview" group references a non-existent
page "ensapi/preview"; fix by either adding a new page file named preview.mdx
under the docs/docs.ensnode.io/ensapi/ folder (so the path matches
"ensapi/preview") or remove the entire Preview group entry (the object with
"group": "Preview", "pages": ["ensapi/preview"], "openapi": "./openapi.json",
"hidden": true) from docs.json; update whichever you choose and ensure the
"pages" array references only existing MDX/MD files.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/test_ci.yml:
- Around line 58-70: The CI step runs the openapi:generate npm script which
currently relies on a hardcoded production default; make the behavior explicit
by passing the production URL via the ENSAPI_URL env in the workflow step or by
updating the openapi:generate script to accept an ENSAPI_URL argument and
default it to https://api.alpha.ensnode.io; update the step that invokes
openapi:generate to export ENSAPI_URL or call the script with the URL so the
action is explicit and maintainable.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@vercel vercel bot temporarily deployed to Preview – ensrainbow.io January 20, 2026 16:01 Inactive
ensHolidayAwardsStart: DateStringToUnixTimestampSchema.default(ENS_HOLIDAY_AWARDS_START_DATE),
ensHolidayAwardsEnd: DateStringToUnixTimestampSchema.default(ENS_HOLIDAY_AWARDS_END_DATE),
})
const BaseEnsApiConfigSchema = z.object({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't suspect this causes any pushback, but let me know if so.

* @throws Error with formatted validation messages if environment parsing fails
*/
export async function buildConfigFromEnvironment(env: EnsApiEnvironment): Promise<EnsApiConfig> {
if (env.OPENAPI_GENERATE_MODE === "true") {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OPENAPI_GENERATE_MODE ENV is more explicit now about what it does/enables.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/test_ci.yml:
- Around line 58-118: The ENSApi background process PID (ENSAPI_PID) is only
kept in-step and can leak; persist the PID (e.g. echo $ENSAPI_PID > ensapi.pid)
right after starting ENSApi in the "Start ENSApi..." step and then add a final
workflow step named like "Stop ENSApi" with if: always() that reads the PID
(ENSAPI_PID=$(cat ensapi.pid) || true), kills it (kill $ENSAPI_PID 2>/dev/null
|| true) and waits (wait $ENSAPI_PID 2>/dev/null || true); you can still keep
the in-step cleanup() function for early exits, but ensure the always() step
runs after "Validate OpenAPI spec with Mintlify" to guarantee the server is
stopped regardless of test outcome.

Comment on lines +58 to +118
- name: Start ENSApi in OpenAPI generate mode
run: |
OPENAPI_GENERATE_MODE=true pnpm --filter ensapi start &
ENSAPI_PID=$!

# Cleanup function to ensure background process is stopped
cleanup() {
echo "Stopping ENSApi (PID: $ENSAPI_PID)..."
kill $ENSAPI_PID 2>/dev/null || true
wait $ENSAPI_PID 2>/dev/null || true
}

# Wait for server to be ready
SERVER_READY=false
for i in {1..30}; do
# Use --fail to treat non-2xx/3xx responses as failures
if curl --fail --silent --max-time 5 http://localhost:4334/openapi.json > /dev/null 2>&1; then
echo "✅ ENSApi is ready and responding with valid OpenAPI spec"
SERVER_READY=true
break
fi
# Check if the background process is still running
if ! kill -0 $ENSAPI_PID 2>/dev/null; then
echo "❌ ENSApi process exited unexpectedly"
echo "The server process (PID: $ENSAPI_PID) is no longer running."
exit 1
fi
echo "Waiting for ENSApi to start... ($i/30)"
sleep 1
done

if [ "$SERVER_READY" != "true" ]; then
echo "❌ ENSApi failed to start within 30 seconds"
echo "The server did not respond to requests at http://localhost:4334/openapi.json"
cleanup
exit 1
fi

- name: Generate OpenAPI spec from local build
working-directory: docs/docs.ensnode.io
run: pnpm openapi:generate http://localhost:4334

- name: Verify OpenAPI spec matches committed version
run: |
if git diff --quiet docs/docs.ensnode.io/openapi.json; then
echo "✅ OpenAPI spec is in sync with codebase"
else
echo "❌ OpenAPI spec is out of sync"
echo ""
echo "The committed openapi.json differs from what ENSApi generates:"
echo ""
git diff --color docs/docs.ensnode.io/openapi.json
echo ""
echo "To fix: OPENAPI_GENERATE_MODE=true pnpm --filter ensapi start"
echo "Then: pnpm --filter @docs/mintlify openapi:generate http://localhost:4334"
echo "Then commit the updated openapi.json."
exit 1
fi

- name: Validate OpenAPI spec with Mintlify
run: pnpm dlx mintlify openapi-check docs/docs.ensnode.io/openapi.json
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Ensure ENSApi is stopped after the spec checks complete.

The background process can remain running for the rest of the job. Persist the PID and add an always() cleanup step to avoid stray processes or port conflicts.

♻️ Proposed update
       - name: Start ENSApi in OpenAPI generate mode
         run: |
           OPENAPI_GENERATE_MODE=true pnpm --filter ensapi start &
           ENSAPI_PID=$!
+          echo "ENSAPI_PID=$ENSAPI_PID" >> "$GITHUB_ENV"
@@
       - name: Validate OpenAPI spec with Mintlify
         run: pnpm dlx mintlify openapi-check docs/docs.ensnode.io/openapi.json
+
+      - name: Stop ENSApi
+        if: always()
+        run: |
+          if [ -n "${ENSAPI_PID:-}" ]; then
+            echo "Stopping ENSApi (PID: $ENSAPI_PID)..."
+            kill "$ENSAPI_PID" 2>/dev/null || true
+            wait "$ENSAPI_PID" 2>/dev/null || true
+          fi
🤖 Prompt for AI Agents
In @.github/workflows/test_ci.yml around lines 58 - 118, The ENSApi background
process PID (ENSAPI_PID) is only kept in-step and can leak; persist the PID
(e.g. echo $ENSAPI_PID > ensapi.pid) right after starting ENSApi in the "Start
ENSApi..." step and then add a final workflow step named like "Stop ENSApi" with
if: always() that reads the PID (ENSAPI_PID=$(cat ensapi.pid) || true), kills it
(kill $ENSAPI_PID 2>/dev/null || true) and waits (wait $ENSAPI_PID 2>/dev/null
|| true); you can still keep the in-step cleanup() function for early exits, but
ensure the always() step runs after "Validate OpenAPI spec with Mintlify" to
guarantee the server is stopped regardless of test outcome.

Copilot AI review requested due to automatic review settings January 28, 2026 13:44
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io January 28, 2026 13:44 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io January 28, 2026 13:44 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io January 28, 2026 13:44 Inactive
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@vercel vercel bot temporarily deployed to Preview – ensnode.io January 28, 2026 13:53 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io January 28, 2026 13:53 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io January 28, 2026 13:53 Inactive
Comment on lines +58 to +94
- name: Start ENSApi in OpenAPI generate mode
run: |
OPENAPI_GENERATE_MODE=true pnpm --filter ensapi start &
ENSAPI_PID=$!

# Cleanup function to ensure background process is stopped
cleanup() {
echo "Stopping ENSApi (PID: $ENSAPI_PID)..."
kill $ENSAPI_PID 2>/dev/null || true
wait $ENSAPI_PID 2>/dev/null || true
}

# Wait for server to be ready
SERVER_READY=false
for i in {1..30}; do
# Use --fail to treat non-2xx/3xx responses as failures
if curl --fail --silent --max-time 5 http://localhost:4334/openapi.json > /dev/null 2>&1; then
echo "✅ ENSApi is ready and responding with valid OpenAPI spec"
SERVER_READY=true
break
fi
# Check if the background process is still running
if ! kill -0 $ENSAPI_PID 2>/dev/null; then
echo "❌ ENSApi process exited unexpectedly"
echo "The server process (PID: $ENSAPI_PID) is no longer running."
exit 1
fi
echo "Waiting for ENSApi to start... ($i/30)"
sleep 1
done

if [ "$SERVER_READY" != "true" ]; then
echo "❌ ENSApi failed to start within 30 seconds"
echo "The server did not respond to requests at http://localhost:4334/openapi.json"
cleanup
exit 1
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ENSApi background process is never properly stopped in the "Start ENSApi in OpenAPI generate mode" step, causing it to remain running during subsequent steps and only being killed when the job completes.

View Details
📝 Patch Details
diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml
index 43eb5092..a082153f 100644
--- a/.github/workflows/test_ci.yml
+++ b/.github/workflows/test_ci.yml
@@ -66,6 +66,7 @@ jobs:
             kill $ENSAPI_PID 2>/dev/null || true
             wait $ENSAPI_PID 2>/dev/null || true
           }
+          trap cleanup EXIT
 
           # Wait for server to be ready
           SERVER_READY=false

Analysis

ENSApi background process never properly cleaned up in test_ci.yml

What fails: The "Start ENSApi in OpenAPI generate mode" step in .github/workflows/test_ci.yml spawns a background ENSApi process that is never stopped when the server starts successfully. The process continues running through subsequent workflow steps (Generate OpenAPI spec, Verify OpenAPI spec, Validate OpenAPI spec) until the entire job completes.

How to reproduce: The issue manifests in any GitHub Actions run of the openapi-sync-check job:

  1. The step Start ENSApi in OpenAPI generate mode runs (lines 58-94)
  2. ENSApi starts successfully and responds to the curl healthcheck
  3. The step completes without calling the cleanup() function
  4. The background ENSApi process continues running through subsequent steps

What happens vs expected behavior:

According to Fleet's GitHub Actions guide: "Background processes do not exit at the end of the step — They keep running until the whole job completes."

The current code only calls cleanup() on the error path (line 92). When the server starts successfully, the script simply completes without invoking cleanup. The cleanup() function definition (lines 64-68) is never registered as an exit trap, so it never executes on successful completion.

This causes the ENSApi process to consume system resources and remain running through subsequent workflow steps unnecessarily.

Root cause: The cleanup function was defined but never registered with trap cleanup EXIT. In bash, functions must be explicitly registered with trap to execute automatically on script exit. Without this registration, the function is only called when explicitly invoked by name.

Fix applied: Added trap cleanup EXIT immediately after the cleanup function definition (line 69). This ensures the cleanup function is automatically invoked when the script exits, whether through success, error, or interruption, following bash exit trap best practices.

Copilot AI review requested due to automatic review settings January 28, 2026 15:46
@vercel vercel bot temporarily deployed to Preview – ensnode.io January 28, 2026 15:46 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io January 28, 2026 15:46 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io January 28, 2026 15:46 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/ensapi/src/config/config.schema.ts`:
- Around line 88-91: The OPENAPI_GENERATE_MODE early return bypasses the
surrounding try/catch so parse errors from
EnsApiConfigSchema.parse(buildOpenApiMockConfig(env.PORT)) are not handled
consistently; move the entire OPENAPI_GENERATE_MODE branch into the existing try
block (or replace the early return with setting the config variable inside try
and returning after try) so that any thrown errors during buildOpenApiMockConfig
or EnsApiConfigSchema.parse are caught and handled by the same catch/exit logic.
- Line 29: The import of buildOpenApiMockConfig in config.schema.ts refers to a
missing module; either add a new module exporting buildOpenApiMockConfig or
remove its import and usages. To fix, create
apps/ensapi/src/config/openapi-mock-config.ts and export a
buildOpenApiMockConfig function that returns the expected config shape used by
config.schema.ts (match any callers in config.schema.ts), or if the mock config
is not required, delete the import line and remove or replace any
calls/references to buildOpenApiMockConfig in config.schema.ts (ensure any
dependent configuration logic still validates). Make sure the exported symbol
name is exactly buildOpenApiMockConfig and its signature matches how
config.schema.ts consumes it.


import { ENSApi_DEFAULT_PORT } from "@/config/defaults";
import type { EnsApiEnvironment } from "@/config/environment";
import { buildOpenApiMockConfig } from "@/config/openapi-mock-config";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate the file and verify path alias resolution.
fd -a "openapi-mock-config" .

Repository: namehash/ensnode

Length of output: 42


🏁 Script executed:

rg -n "paths" tsconfig*.json --type json -A 5

Repository: namehash/ensnode

Length of output: 114


🏁 Script executed:

# Check if the file exists in the apps/ensapi/src/config directory
ls -la apps/ensapi/src/config/ | grep -i openapi

Repository: namehash/ensnode

Length of output: 42


🏁 Script executed:

# Also check what files are actually in the config directory
find apps/ensapi/src/config -type f -name "*.ts" -o -name "*.js" | head -20

Repository: namehash/ensnode

Length of output: 320


🏁 Script executed:

# Find tsconfig files
find . -name "tsconfig.json" -o -name "tsconfig*.json" | head -10

Repository: namehash/ensnode

Length of output: 400


🏁 Script executed:

# Read the actual import at line 29 of config.schema.ts
head -35 apps/ensapi/src/config/config.schema.ts | tail -10

Repository: namehash/ensnode

Length of output: 487


🏁 Script executed:

# Check the entire import section of config.schema.ts
head -50 apps/ensapi/src/config/config.schema.ts

Repository: namehash/ensnode

Length of output: 1647


🏁 Script executed:

# Search for any openapi-related files in the entire repo
find . -type f -name "*openapi*"

Repository: namehash/ensnode

Length of output: 146


🏁 Script executed:

# Check the @ path alias in tsconfig.json
cat apps/ensapi/tsconfig.json | jq '.compilerOptions.paths' 2>/dev/null || grep -A 2 '"paths"' apps/ensapi/tsconfig.json

Repository: namehash/ensnode

Length of output: 92


🏁 Script executed:

# Search for buildOpenApiMockConfig function definition
rg "buildOpenApiMockConfig" --type ts --type js

Repository: namehash/ensnode

Length of output: 281


🏁 Script executed:

# Check if file might be in a different location or under construction
rg "openapi.*mock" --type ts --type js -i

Repository: namehash/ensnode

Length of output: 399


🏁 Script executed:

# Check what's currently exported from the config/index.ts
cat apps/ensapi/src/config/index.ts

Repository: namehash/ensnode

Length of output: 191


Missing module: @/config/openapi-mock-config file does not exist.

The file apps/ensapi/src/config/openapi-mock-config.ts is referenced in the import statement at line 29 but does not exist in the repository. The buildOpenApiMockConfig function is called in this file but has no implementation. Create the missing module or remove the import and usage.

🧰 Tools
🪛 GitHub Actions: Test: CI

[error] 29-29: apps/ensapi typecheck: Cannot find module '@/config/openapi-mock-config' or its corresponding type declarations. (TS2307)

🪛 GitHub Check: Unit Tests

[failure] 29-29: src/config/config.schema.test.ts
Error: Cannot find package '@/config/openapi-mock-config' imported from '/home/runner/_work/ensnode/ensnode/apps/ensapi/src/config/config.schema.ts'
❯ src/config/config.schema.ts:29:1
❯ src/config/config.schema.test.ts:16:1

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'ERR_MODULE_NOT_FOUND' }

🤖 Prompt for AI Agents
In `@apps/ensapi/src/config/config.schema.ts` at line 29, The import of
buildOpenApiMockConfig in config.schema.ts refers to a missing module; either
add a new module exporting buildOpenApiMockConfig or remove its import and
usages. To fix, create apps/ensapi/src/config/openapi-mock-config.ts and export
a buildOpenApiMockConfig function that returns the expected config shape used by
config.schema.ts (match any callers in config.schema.ts), or if the mock config
is not required, delete the import line and remove or replace any
calls/references to buildOpenApiMockConfig in config.schema.ts (ensure any
dependent configuration logic still validates). Make sure the exported symbol
name is exactly buildOpenApiMockConfig and its signature matches how
config.schema.ts consumes it.

Comment on lines +88 to +91
if (env.OPENAPI_GENERATE_MODE === "true") {
logger.info("OPENAPI_GENERATE_MODE enabled - using minimal mock config");
return EnsApiConfigSchema.parse(buildOpenApiMockConfig(env.PORT));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep OPENAPI_GENERATE_MODE errors consistent with the main path.

This early return bypasses the try/catch, so parse errors won’t be prettified or handled with the existing exit behavior. Wrap the OPENAPI_GENERATE_MODE branch inside the try block for consistent failure handling.

🔧 Proposed fix
-export async function buildConfigFromEnvironment(env: EnsApiEnvironment): Promise<EnsApiConfig> {
-  if (env.OPENAPI_GENERATE_MODE === "true") {
-    logger.info("OPENAPI_GENERATE_MODE enabled - using minimal mock config");
-    return EnsApiConfigSchema.parse(buildOpenApiMockConfig(env.PORT));
-  }
-
-  try {
+export async function buildConfigFromEnvironment(env: EnsApiEnvironment): Promise<EnsApiConfig> {
+  try {
+    if (env.OPENAPI_GENERATE_MODE === "true") {
+      logger.info("OPENAPI_GENERATE_MODE enabled - using minimal mock config");
+      return EnsApiConfigSchema.parse(buildOpenApiMockConfig(env.PORT));
+    }
+
     const ensIndexerUrl = EnsIndexerUrlSchema.parse(env.ENSINDEXER_URL);
🤖 Prompt for AI Agents
In `@apps/ensapi/src/config/config.schema.ts` around lines 88 - 91, The
OPENAPI_GENERATE_MODE early return bypasses the surrounding try/catch so parse
errors from EnsApiConfigSchema.parse(buildOpenApiMockConfig(env.PORT)) are not
handled consistently; move the entire OPENAPI_GENERATE_MODE branch into the
existing try block (or replace the early return with setting the config variable
inside try and returning after try) so that any thrown errors during
buildOpenApiMockConfig or EnsApiConfigSchema.parse are caught and handled by the
same catch/exit logic.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


import { ENSApi_DEFAULT_PORT } from "@/config/defaults";
import type { EnsApiEnvironment } from "@/config/environment";
import { buildOpenApiMockConfig } from "@/config/openapi-mock-config";
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import statement references a module @/config/openapi-mock-config that does not exist in the codebase. This will cause a runtime error when OPENAPI_GENERATE_MODE is set to "true". The function buildOpenApiMockConfig must be implemented for the OpenAPI generation feature to work.

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +94
execFileSync("pnpm", ["biome", "format", "--write", OUTPUT_PATH], {
stdio: "inherit",
});
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The biome formatting command should handle potential errors gracefully. If biome fails (e.g., due to formatting issues or command not found), the script will crash but the OpenAPI spec will have already been written. Consider wrapping the execFileSync call in a try-catch block to handle biome failures gracefully and provide helpful error messages.

Suggested change
execFileSync("pnpm", ["biome", "format", "--write", OUTPUT_PATH], {
stdio: "inherit",
});
try {
execFileSync("pnpm", ["biome", "format", "--write", OUTPUT_PATH], {
stdio: "inherit",
});
} catch (error) {
console.error("Error: Failed to format openapi.json with Biome.");
if (error instanceof Error) {
const err = error as NodeJS.ErrnoException;
if (err.code === "ENOENT") {
console.error("It looks like 'pnpm' or 'biome' is not installed or not available on your PATH.");
} else if (err.message) {
console.error(err.message);
}
}
process.exit(1);
}

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +14
'@adraffy/ens-normalize': 1.11.1
'@astrojs/react': ^4.4.1
'@astrojs/tailwind': ^6.0.2
'@namehash/namekit-react': 0.12.0
'@ponder/client': 0.16.1
'@ponder/utils': 0.2.16
'@testing-library/react': ^16.3.0
'@types/node': 24.10.9
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quote style in the catalog section has been changed from double quotes to single quotes. While this is functionally equivalent in YAML, it creates unnecessary formatting churn and should be reverted unless there's a specific reason for the change. The more significant issue is that this change is unrelated to the PR's stated purpose (OpenAPI spec documentation) and should be in a separate commit or PR focused on formatting.

Suggested change
'@adraffy/ens-normalize': 1.11.1
'@astrojs/react': ^4.4.1
'@astrojs/tailwind': ^6.0.2
'@namehash/namekit-react': 0.12.0
'@ponder/client': 0.16.1
'@ponder/utils': 0.2.16
'@testing-library/react': ^16.3.0
'@types/node': 24.10.9
"@adraffy/ens-normalize": 1.11.1
"@astrojs/react": ^4.4.1
"@astrojs/tailwind": ^6.0.2
"@namehash/namekit-react": 0.12.0
"@ponder/client": 0.16.1
"@ponder/utils": 0.2.16
"@testing-library/react": ^16.3.0
"@types/node": 24.10.9

Copilot uses AI. Check for mistakes.
@vercel vercel bot temporarily deployed to Preview – ensnode.io January 28, 2026 15:58 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io January 28, 2026 15:58 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io January 28, 2026 15:58 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate Mintlify Preview Environments on PRs Epic: ENSApi Docs

3 participants