Part 1 of 3 — splits PR #451 into reviewable, dependency-ordered pieces. This is the foundation; #469 and #470 stack on top.
Goal
Introduce zod input validation as a feature, starting at the JSON-RPC boundary (POST /). Reject malformed params with a proper JSON-RPC error before any business logic runs. Also closes Sentry STAMP-4F (TypeError: i?.toLowerCase is not a function from non-string params reaching mapOriginalInput).
Scope (this issue only)
- Add
zod dependency (package.json, yarn.lock).
- New
src/helpers/validation.ts:
lookupAddressesSchema — non-empty array of valid EVM (0x+40 hex) or Starknet (0x+64 hex) addresses, capped at 50.
resolveNamesSchema — non-empty array of handles, capped at 5.
lookupDomainsSchema — single EVM address string.
getOwnerSchema — single handle string.
formatZodError(error) — short human-readable issue summary.
- Plain string output — do NOT add
.brand() yet (that lands in the brand layer, Part 3).
src/helpers/utils.ts: add rpcInvalidParams helper returning JSON-RPC -32602 / HTTP 400 with the zod summary in data. Do not add an unused message param to rpcError (dead configurability).
src/api.ts: validate params at each of the 4 method entry points before calling the resolver; remove the now-redundant Array.isArray(params) check.
- Tests (
test/e2e/api.test.ts): malformed params return -32602/400 for nested array, bad string, wrong type, empty array, over-cap — per method.
Acceptance criteria
- Valid requests byte-for-byte unchanged (HTTP 200, same body).
- Malformed JSON-RPC params → HTTP 400, JSON-RPC code
-32602, readable data.
yarn lint, yarn typecheck, yarn build pass.
- New e2e cases pass.
Out of scope (later parts)
Note
Handle regex must require non-empty labels on both sides of the dot — reject ., a., .b. Do not copy PR #451's loose /^[^\s]*\.[^\s]*$/.
Part 1 of 3 — splits PR #451 into reviewable, dependency-ordered pieces. This is the foundation; #469 and #470 stack on top.
Goal
Introduce zod input validation as a feature, starting at the JSON-RPC boundary (
POST /). Reject malformed params with a proper JSON-RPC error before any business logic runs. Also closes Sentry STAMP-4F (TypeError: i?.toLowerCase is not a functionfrom non-string params reachingmapOriginalInput).Scope (this issue only)
zoddependency (package.json,yarn.lock).src/helpers/validation.ts:lookupAddressesSchema— non-empty array of valid EVM (0x+40 hex) or Starknet (0x+64 hex) addresses, capped at 50.resolveNamesSchema— non-empty array of handles, capped at 5.lookupDomainsSchema— single EVM address string.getOwnerSchema— single handle string.formatZodError(error)— short human-readable issue summary..brand()yet (that lands in the brand layer, Part 3).src/helpers/utils.ts: addrpcInvalidParamshelper returning JSON-RPC-32602/ HTTP 400 with the zod summary indata. Do not add an unusedmessageparam torpcError(dead configurability).src/api.ts: validate params at each of the 4 method entry points before calling the resolver; remove the now-redundantArray.isArray(params)check.test/e2e/api.test.ts): malformed params return-32602/400 for nested array, bad string, wrong type, empty array, over-cap — per method.Acceptance criteria
-32602, readabledata.yarn lint,yarn typecheck,yarn buildpass.Out of scope (later parts)
GET /:type/:id,parseQuery) validation → Part 2 (Add zod validation — Part 2: avatar/REST route boundary #469).Note
Handle regex must require non-empty labels on both sides of the dot — reject
.,a.,.b. Do not copy PR #451's loose/^[^\s]*\.[^\s]*$/.