Feat/paid api docs smoke tests health stats - #424
Merged
Emmy123222 merged 5 commits intoSep 3, 2026
Merged
Conversation
.github/workflows/ci.yml carried unresolved conflict markers committed to main in 7804e9c, which made the file invalid YAML. GitHub Actions could not parse it, so none of the CI jobs ran at all — including any job a branch protection rule might require. Resolve by keeping both sides: the real coverage-gate steps (npm ci plus threshold verification) replace the placeholder echo, and the supply-chain SBOM and vulnerability job is retained.
The README and DocsPage covered /search only, while /images and /news were served by Express and proxied by the MCP tools with no public documentation of their parameters, limits, 402 challenge, paid response, or result fields. Document both in the README — per-route count bounds and freshness enums, an error table, the 402 challenge, paid response bodies, and ImageResult/NewsResult field tables — and in DocsPage, with curl examples that URL-encode queries via --data-urlencode rather than inlining them. Record explicitly that /images and /news are Express and MCP only, with no Vercel serverless equivalent. Documenting the limits required making them true. Emmy123222#188 added src/lib/paramValidation.ts and a full test matrix but never wired the contract into a route, so /images and /news silently clamped count (count=999 became 10) instead of rejecting it, and the README already described rejection that did not happen. Wire the shared contract in as middleware registered ahead of the x402 middleware, so an invalid count or freshness is refused with 400 without consulting the payment adapter or issuing a payment challenge — on Express and on Vercel /api/search alike. Verified against the running server: /images?q=x&count=999 now returns 400 "count must be between 1 and 10" rather than a 402. Also correct the payment headers shown in the DocsPage flow. The middleware emits the challenge on PAYMENT-REQUIRED, not X-Payment-Required, and takes the signed payload on PAYMENT-SIGNATURE, with X-PAYMENT retained for x402 v1 clients.
Pull requests validated nothing about an actual deployment. Serverless routing, CORS, environment wiring, static assets, and the SPA rewrite only exist once Vercel has built a preview, so unit tests cannot see them and a routing or CORS regression reached main unnoticed. Add scripts/smoke.mjs, a 12-check suite covering those, plus the shape of the x402 402 challenge: scheme exact, a stellar network, an integer stroop amount rather than a decimal dollar figure, a Soroban C... asset rather than USDC:ISSUER, and a G... payTo. That last check is the one a bad deploy silently breaks. The suite is non-secret by construction: no repository secrets, no Vercel token, no wallet, no signing material, and it never settles a payment, so a run costs 0 USDC. It is dependency-free plain ESM, so CI runs it straight from a checkout without npm ci. Add .github/workflows/preview-smoke.yml, triggered by the deployment_status event Vercel's GitHub integration emits, so no Vercel token is needed. Failures name the exact endpoint three ways: a ::error:: annotation per failed endpoint, a job-summary report carrying filtered headers and a truncated body, and an uploaded artifact. Add vercel.json, which did not exist, defining the serverless routing, SPA rewrites, and CORS headers the suite validates. Response artifacts are header-filtered before they are written: authorization, set-cookie, x-api-key, and the payment headers are never captured, and bodies are truncated to 2 KB.
Closes Emmy123222#226 The serverless health schema omitted totalQueries, totalUsdcSettled, avgLatencyMs and uptime while the browser coalesced them away (data.totalQueries ?? 0), so a Vercel deployment rendered "0 queries, $0.00 settled, 0ms" beside a pulsing green SERVER ONLINE indicator. None of that was a measurement; it was missing data presented as fact. The MCP get_search_stats tool fared worse — it called stats.totalQueries.toLocaleString() on the absent field, threw a TypeError, and surfaced it to the user as a misleading "Failed to fetch server stats". Durable serverless counters are not reachable without external storage, and an in-memory counter in a function that scales to zero would describe one warm instance rather than the deployment. So take the other option and declare the gap. src/lib/serverHealth.ts holds one contract shared by all four runtimes: Express declares statsSupported true, the Vercel handler declares the four fields unsupported with a reason, and omits them rather than reporting zeros. Consumers now read through resolveStat(), which keeps a measured zero distinct from an unmeasured field. StatsGrid renders unmeasured metrics as n/a — dimmed, without the pulsing dot that signals a live reading, with the reason on hover and in screen-reader text, and one panel-level note — while a freshly started Express server still shows a genuine 0, because having served no queries is a real measurement. MCP prints "not reported" plus a single reason line instead of throwing. The preview smoke suite now fails a deployment that omits the counters without declaring them, that claims support but omits the values, or that leaves a stale value on a field declared unsupported. Additive and backward compatible: no existing field changed type or meaning, and resolveStat tolerates deployments predating the contract by trusting present values and reporting absent ones as undeclared rather than as zero. Reporting only — the paid routes and their verified x402 settlement semantics are untouched.
The documented tree predated the server helpers, serverless routes, UI components, tests and workflow files now in the repo, and listed components at paths they no longer occupy. Rebuild it from the actual file listing, and mark which code is shared versus runtime-specific: everything under src/lib is imported by the browser bundle, the Express server, the Vercel functions and the MCP server alike, so a change there has to keep all four aligned, while server/, api/ and mcp-server/ are each one runtime's implementation. Add a table mapping every test suite to the runtime it covers, so the Express, Vercel, browser and MCP boundaries are visible from the tree rather than inferred from filenames.
|
@nonso7 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@nonso7 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #225
Closes #226
Closes #227
Closes #228