Skip to content

feat: Developer & CI Tooling & Bun -> Node, Hono -> Express#66

Open
MaximusHaximus wants to merge 39 commits intomasterfrom
use-node
Open

feat: Developer & CI Tooling & Bun -> Node, Hono -> Express#66
MaximusHaximus wants to merge 39 commits intomasterfrom
use-node

Conversation

@MaximusHaximus
Copy link
Contributor

@MaximusHaximus MaximusHaximus commented Jan 16, 2026

Migration to Node.js 24, Express v5, Zod validation & OpenAPI, test enhancements, dev tooling

This PR introduces a significant refactor and modernization of the Proof Generation API, moving from a Bun-based runtime with Hono to a strictly-typed Node.js 24 environment using Express v5. The project was in a state of flux on the dev branch where it had been generally ported to TS, but the process had not been completely finished (no test suite and no lint configuration, no dev entrypoints). In addition to proper developer tooling for linting, formatting code, and running a dev instance of the codebase using nodemon, a test suite has been defined and a new CI github action that will run integration tests on all PRs that target master.

🚀 Key Changes

1. Runtime & Framework Migration

  • Node.js 24 Migration: Replaced Bun with Node.js 24, leveraging native support for stripping TypeScript types to run .ts files directly without a build step.
  • Express v5 Integration: Replaced Hono with Express v5. All routes and middleware have been updated to the Express API.
  • Dependency Management: Replaced bun.lock with package-lock.json and standardized on npm.

2. Enhanced Infrastructure & Tooling

  • Strict Linting & Formatting: Implemented a robust ESLint flat configuration and Prettier setup tailored for standard dependencies.
  • Git Hooks: Added Husky with pre-commit (lint-staged, typecheck) and commit-msg (Conventional Commits) hooks to ensure code quality.
  • CI/CD Improvements: Updated GitHub Actions to use Node 24 and added a mandatory typecheck, lint, and test step to the CI pipeline.
  • Vitest: Test runner uses Vitest with parallel file execution, configured via vitest.config.ts.

3. Zod Request Validation

Replaced all hand-written validation helpers (validateV1Network, validateBurnTxAndEventSignature, validateZkEVMNetwork, validateNetworkIDAndDepositCount, isInteger) with a single src/schemas.ts file containing Zod schemas for every route. src/routes/utils.ts has been deleted.

Each schema wraps { params, query } so a single safeParse call covers both sources:

const result = BlockIncludedSchema.safeParse({ params: req.params, query: req.query });
if (!result.success) {
  return handleBadRequest({ res, errMsg: result.error.issues[0]?.message ?? 'Invalid request' });
}

All original error message strings are preserved exactly, including dynamic network names (e.g. Invalid network mainnet. Network can either be matic or amoy for PoS v1 routes), using Zod v4's error callback on enum schemas.

Coerced numeric query params (start, end, number, net_id, deposit_cnt) are now typed as number after parsing — no more parseInt() calls in handlers.

4. OpenAPI 3.0 Spec + Interactive Playground

Added @asteasolutions/zod-to-openapi and @scalar/express-api-reference. The request schemas serve double duty: runtime validation and OpenAPI spec generation.

  • GET /api/openapi.json — auto-generated OpenAPI 3.0.0 document listing all 6 endpoints, with servers: [{ url: '/api' }] so the playground resolves paths correctly.
  • GET /api/docs — Scalar interactive API playground with "try it out" support for all endpoints.

Both are mounted unconditionally (available in all environments including production).

5. Codebase Refactoring & Type Safety

  • Zod Environment Validation: Refactored src/env.ts to use @t3-oss/env-core and Zod. Environment variables (especially RPC URLs) are now strictly validated as JSON arrays at startup with descriptive error messages.
  • Named Exports: Eliminated export default across the entire src directory in favor of named exports for better discoverability and refactoring safety.
  • Import Standardization: All relative imports now include the .ts extension and directory imports have been eliminated to comply with ESM standards.
  • Inlined Controller Logic: Simplified the application architecture by moving controller logic directly into route handlers (src/routes/v1.ts and src/routes/zkEVM.ts), removing the src/controllers and src/middleware/validateParams.ts files.

6. Testing Improvements

  • 33 integration tests across 8 scoped test files (up from the original suite). Tests are isolated per domain: block inclusion, Merkle proofs, exit payloads (ERC-20, ERC-1155, all-exit-payloads), invalid arguments, invalid networks, and zkEVM.
  • Full error coverage: Every validation error path is now tested, including exact body.msg string assertions — not just status codes.
  • Vitest with parallel execution: Tests run in parallel via Vitest (fileParallelism: true), reducing total test time from ~50s to ~10.5s. CJS deps (@maticnetwork/maticjs) are inlined via server.deps.inline.
  • Dual-target test runner: All tests run against either the local in-process app (default) or a deployed instance via TEST_BASE_URL:
    TEST_BASE_URL=https://proof-generator.polygon.technology pnpm test
    
    All 33 tests pass against production, confirming no change in observable behaviour after the Zod refactor.
  • Stable payload anchors: Exit payload tests decode the raw hex payload and assert against immutable on-chain data (receipts root, log addresses, topics) rather than opaque hex strings — these assertions are permanently verifiable against block explorers.

7. Logging

  • Defined a Winston logger in this repo for now. Directory imports from @servercore aren't handled by base Node.js file resolution.
  • Added a PRETTY_LOGS env var for colorized local dev output.

🛠 Technical Debt Addressed

  • Removed orphaned tsup.config.ts and legacy .eslintrc files.
  • Removed src/routes/utils.ts (isInteger) — fully superseded by Zod coercion.
  • Improved error handling in service layers with better type assertions.
  • Fixed several pre-existing TypeScript errors related to exactOptionalPropertyTypes and floating promises.
  • No build step required: the application runs using Node 24's native TypeScript type-stripping, so no transpilation is necessary.

🧪 Verification

  • Typecheck: pnpm run typecheck — 0 errors
  • Lint: pnpm run lint — 0 errors (pre-existing any warnings in service layer retained as warnings)
  • Tests (local): pnpm test — 33/33 passing
  • Tests (production): TEST_BASE_URL=https://proof-generator.polygon.technology pnpm test — 33/33 passing

…and formatting

- Appropriate tsconfig for node
- Removed bun.lock and bun dependencies
- Defined `engines`
- Removed tsup
- Define packages + types for test suite
- Add typecheck npm command
- Stub bin path to apiServer.ts for now
- Define a version 🎉
- Add .nvmrc for easy node selection
- Added prettier and eslint configurations
- Ran prettier --write and eslint --fix on entire codebase
- Commit message structure must match conventional commits
- Code linting and formatting is run pre-commit
- Typechecking is run pre-commit
…ased config from env, and resolve all remaining typecheck errors

- eslint rule `no-explicit-any` set to `warn` for now, will re-visit these in follow-up commit
- Let's try direct `.ts` file references, thanks modern node 🎉
…s to be co-located in the code where they are used

- They only had a single callsite each, so having them in `middleware` just fragmented the domain context across multiple files
… that dir; these are actually just route handlers
…core aren't OK with base NodeJS file resolution) and allow express app to be created but not started for integration tests and resolve maticJs default import issues

- Also refactored index.ts to allow creating a non-listening express app for integration testing
…f code

- Also added dotenvx for .env file loading and configured it to be used on `dev` mode
- Move :network glob pattern to individual router definitions
- Mocha uses dotenvx via `require` mocharc configuration
MaximusHaximus and others added 4 commits January 16, 2026 20:49
…ough parameter tampering

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@MaximusHaximus MaximusHaximus changed the title Use node feat: Bun -> Node, Hono -> Express, Add developer tooling Jan 16, 2026
@MaximusHaximus MaximusHaximus changed the title feat: Bun -> Node, Hono -> Express, Add developer tooling feat: Bun -> Node, Hono -> Express, Developer tooling Jan 16, 2026
@MaximusHaximus MaximusHaximus changed the title feat: Bun -> Node, Hono -> Express, Developer tooling feat: Bun -> Node, Hono -> Express, Developer & CI tooling Jan 16, 2026
@MaximusHaximus MaximusHaximus changed the title feat: Bun -> Node, Hono -> Express, Developer & CI tooling feat: Developer & CI tooling & Bun -> Node, Hono -> Express Jan 16, 2026
@MaximusHaximus MaximusHaximus changed the title feat: Developer & CI tooling & Bun -> Node, Hono -> Express feat: Developer & CI Tooling & Bun -> Node, Hono -> Express Jan 16, 2026
…n it comes to exit payloads

- Also use explicit imports and remove global types from tsconfig
- Added decode-exit-payload code with nice comment docs for how it works
- Added `get-receiopts-root` script to help people who need to make test cases in the future
…c, add OpenAPI-Zod and playground UI

- Added extensive error response tests to integration suite, allowed running the suite against production or local
- Tested all error cases and verified no change in behaviour.
…c, add OpenAPI-Zod and playground UI

- Added extensive error response tests to integration suite, allowed running the suite against production or local
- Tested all error cases and verified no change in behaviour.
Vitest uses Chai internally for its expect() API, so existing assertion
style is preserved. Key changes:
- Replace mocha/chai/chai-as-promised/type deps with vitest
- Delete .mocharc.json, add vitest.config.ts
- Update imports to use vitest's describe/it/expect/beforeAll/afterAll
- Convert function() syntax to arrow functions with timeout options
- Inline @maticnetwork/maticjs CJS deps in vitest config
- Enable file parallelism (test time 50s → 10.5s)
- Update CLAUDE.md testing references
Run eslint before prettier, use markdownlint-cli2 for markdown files
instead of prettier.
These scopes match the ESLint internalPattern in @polygonlabs/apps-team-lint
and should bypass pnpm's minimum release age check.
- Rename .prettierrc to .prettierrc.json
- Add .markdownlint-cli2.jsonc, markdownlint-cli2 dep, lint:md/format:md scripts
- Add *.md to .prettierignore
- Refactor tsconfig.json to extend @tsconfig/node24 + @tsconfig/node-ts
- Create tsconfig.build.json for build output
- ci.yaml: remove redundant push trigger
- Create src/test/helpers/test-env.ts, remove direct process.env reads
- Fix test assertions to use .property() / .nested.property()
- Remove .an() filler from zkevm.test.ts
- Fix markdown lint issues in README.md and docs/integration-testing-runbook.md
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: pnpm/action-setup@v4

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow Medium

Unpinned 3rd party Action 'CI' step
Uses Step
uses 'pnpm/action-setup' with ref 'v4', not a pinned commit hash
…nston

winston-transport is imported directly in src/logger.ts but was only
available as a transitive dependency via winston. pnpm's strict
node_modules layout does not hoist it in CI, causing TS2307.

@types/winston is a deprecated stub — winston ships its own types.
declaration: true in the base tsconfig causes TS2742 errors in CI
when running tsc --noEmit, because TypeScript still computes
declaration types and cannot name them from pnpm's nested paths.
These options are only needed for the build output.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 5, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

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.

1 participant