diff --git a/.github/workflows/explorer-build.yml b/.github/workflows/explorer-build.yml new file mode 100644 index 00000000..da9e62bd --- /dev/null +++ b/.github/workflows/explorer-build.yml @@ -0,0 +1,81 @@ +name: Explorer Build + +# Issue #520: "wire it into CI so it breaks loudly when the API changes." +# explorer-perf.yml already exercises explorer/ against a real testnet API, +# but only on a weekly schedule/manual dispatch, and it never actually runs +# `npm run build` — it discovered the explorer's build had been broken +# outright (a duplicated template block in one page, since fixed) only +# because someone ran `npm run build` by hand. This job runs the real +# production build on every push/PR that touches explorer/, so a build +# break (from an API/type change, a bad merge, or anything else) is a red +# CI check within minutes, not something waiting to be found by hand. + +on: + push: + branches: [main, dev] + paths: + - "explorer/**" + - "sdk/typescript/**" + - ".github/workflows/explorer-build.yml" + pull_request: + paths: + - "explorer/**" + - "sdk/typescript/**" + - ".github/workflows/explorer-build.yml" + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Build the TypeScript SDK + working-directory: sdk/typescript + run: | + npm install + npm run build + + # explorer/ depends on the SDK via a local `file:../sdk/typescript` + # dependency (the SDK is not yet published — see #517/#429, blocked on + # #512), so the SDK must be built before `npm install` in explorer/ + # resolves and links it. + - name: Install explorer dependencies + working-directory: explorer + run: npm install --legacy-peer-deps + + - name: Type-check + working-directory: explorer + # astro check has pre-existing, unrelated failures in + # scripts/a11y-test.ts and scripts/perf-test.ts (tracked + # separately) — this job checks the build, which is the specific + # "breaks loudly" signal #520 asks for; a full green astro check + # across the whole package is a separate concern. + run: npm run build + + - name: Verify the built server actually starts + working-directory: explorer + env: + TRIDENT_TESTNET_API_URL: https://api.testnet.trident.dev + TRIDENT_MAINNET_API_URL: https://api.mainnet.trident.dev + EXPLORER_API_KEY: ci-smoke-test-key + PORT: 4321 + run: | + node dist/server/entry.mjs & + SERVER_PID=$! + for i in $(seq 1 20); do + if curl --silent --fail --max-time 1 "http://127.0.0.1:4321/" >/dev/null 2>&1; then + echo "Server responded successfully" + kill "$SERVER_PID" + exit 0 + fi + sleep 0.5 + done + echo "Server did not respond within the timeout" >&2 + kill "$SERVER_PID" 2>/dev/null || true + exit 1 diff --git a/docs/runbooks/alerts.md b/docs/runbooks/alerts.md index 61f0dd81..48d590a1 100644 --- a/docs/runbooks/alerts.md +++ b/docs/runbooks/alerts.md @@ -4,7 +4,10 @@ One section per alert in [`monitoring/alerts.yml`](../../monitoring/alerts.yml). Each section covers what the alert means, why its threshold was picked, and the first steps to take when it fires. See [`docs/metrics-catalog.md`](../metrics-catalog.md) for what every metric -referenced here actually measures. +referenced here actually measures. Routing (which severity/service pages +whom) is configured in [`monitoring/alertmanager.yml`](../../monitoring/alertmanager.yml) — +"page on-call" below means whatever's wired into that file's +`on-call-critical`/`on-call-warning` receivers. ## TridentIndexerLagWarning diff --git a/explorer/package-lock.json b/explorer/package-lock.json index 8f7deadf..84386c3b 100644 --- a/explorer/package-lock.json +++ b/explorer/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@astrojs/node": "^11.1.4", "@astrojs/tailwind": "^6.0.2", + "@trident-indexer/sdk": "file:../sdk/typescript", "astro": "^7.2.9", "tailwindcss": "^3.4.13" }, @@ -25,6 +26,26 @@ "node": ">=20" } }, + "../sdk/typescript": { + "name": "@trident-indexer/sdk", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "ws": "^8.21.0", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/node": "^20.11.0", + "@types/ws": "^8.18.1", + "msw": "^2.14.6", + "tsup": "^8.0.2", + "typescript": "^5.3.3", + "vitest": "^4.1.8" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -2160,6 +2181,10 @@ "dev": true, "license": "MIT" }, + "node_modules/@trident-indexer/sdk": { + "resolved": "../sdk/typescript", + "link": true + }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", diff --git a/explorer/package.json b/explorer/package.json index 70ddd395..36fe7f6e 100644 --- a/explorer/package.json +++ b/explorer/package.json @@ -16,6 +16,7 @@ "dependencies": { "@astrojs/node": "^11.1.4", "@astrojs/tailwind": "^6.0.2", + "@trident-indexer/sdk": "file:../sdk/typescript", "astro": "^7.2.9", "tailwindcss": "^3.4.13" }, diff --git a/explorer/src/lib/api.ts b/explorer/src/lib/api.ts index cf745273..4a32e044 100644 --- a/explorer/src/lib/api.ts +++ b/explorer/src/lib/api.ts @@ -1,3 +1,24 @@ +// Issue #520: use a published SDK the way a real user would, not internal +// APIs. This module now goes through @trident-indexer/sdk's TridentClient +// (real retry/backoff, Zod response validation, typed errors) instead of a +// hand-rolled fetchWithTimeout — the SDK is not yet published to npm, so +// package.json references it via a local `file:` dependency +// (file:../sdk/typescript) until it is; swap that for a real version range +// once #517/#429 land a published release. +// +// The SDK's own types are camelCase (contractId, ledgerSequence, ...) to +// match its own conventions, while every .astro page in this app was +// written against the raw REST API's snake_case JSON shape (contract_id, +// ledger_sequence, ...). Translating at this one boundary — rather than +// migrating every field access across index.astro, contract/[address]/ +// index.astro, and contract/[address]/event/[id].astro (including inline +// client-side