feat: add affiliate & auth routes to public-api, refactor affiliate-dashboard for prod#12200
Conversation
…ashboard for prod public-api: - Add missing affiliate routes: GET /affiliate/:address, POST /affiliate, PATCH /affiliate/:address, POST /affiliate/claim-code, GET /affiliate/swaps - Add SIWE auth routes: POST /auth/siwe/nonce, POST /auth/siwe/verify - Extract shared fetchSwapService helper (AbortController + 503/504 handling) - Add affiliateMutationLimiter (20 req/min) on mutation and auth routes - Add chainId filtering to GET /assets/count - Reorganize affiliate types by feature group with consistent naming (*RequestSchema/*ResponseSchema) - Complete OpenAPI response codes (400/404/429/500/503/504) across all route handlers affiliate-dashboard: - Replace Vite proxy with explicit VITE_API_URL for production compatibility - Switch from Dockerfile to Railpack for Railway deployment - Remove tsconfig.node.json (folded into main tsconfig) - Add .env.example with required env vars - Add early throw in main.tsx if VITE_API_URL not set in prod Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughExternalized affiliate-dashboard runtime config (VITE_API_URL, WalletConnect), removed the package Dockerfile and Vite proxy, updated TypeScript/Vite configs, added affiliate and SIWE endpoints and schemas in the public API, and introduced fetchSwapService to proxy upstream swap-service calls with timeout/error handling. Changes
Sequence DiagramsequenceDiagram
participant Client as Affiliate Dashboard
participant PublicAPI as Public API
participant SwapService as Swap Service
rect rgba(200,150,255,0.5)
Note over Client: Startup validation
Client->>Client: Read VITE_API_URL & VITE_WALLETCONNECT_PROJECT_ID
Client->>Client: Throw if missing
end
rect rgba(100,200,255,0.5)
Note over Client,PublicAPI: Affiliate create/claim/update
Client->>PublicAPI: POST/PATCH /v1/affiliate... (Authorization)
PublicAPI->>PublicAPI: Zod validate request
PublicAPI->>SwapService: Forward via fetchSwapService (timeout)
SwapService-->>PublicAPI: 2xx or error JSON/status
PublicAPI-->>Client: Forward status/body or mapped error
end
rect rgba(100,255,200,0.5)
Note over Client,PublicAPI: SIWE auth flow
Client->>PublicAPI: POST /v1/auth/siwe/nonce
PublicAPI->>SwapService: POST /v1/auth/siwe/nonce
SwapService-->>PublicAPI: { nonce }
PublicAPI-->>Client: { nonce }
Client->>PublicAPI: POST /v1/auth/siwe/verify {message,signature}
PublicAPI->>SwapService: POST /v1/auth/siwe/verify
SwapService-->>PublicAPI: { token,address } or error
PublicAPI-->>Client: Forward response
end
rect rgba(255,200,100,0.5)
Note over PublicAPI,SwapService: Error handling
SwapService-->>PublicAPI: Timeout/unavailable
PublicAPI->>PublicAPI: fetchSwapService returns null → respond 503/504
PublicAPI-->>Client: Error response
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/affiliate-dashboard/src/App.tsx (1)
227-237:⚠️ Potential issue | 🟡 MinorRead
errorfrom the new public-api failure payloads.These calls now hit
packages/public-api, and the handlers added in this PR serialize local failures as{ error, code }. Looking only atbody.messagecollapses useful 400/401/409 responses into a genericFailed (status).💡 Minimal fix
- const body = (await res.json()) as { message?: string } - throw new Error(body.message ?? `Failed (${String(res.status)})`) + const body = (await res.json()) as { error?: string; message?: string } + throw new Error(body.error ?? body.message ?? `Failed (${String(res.status)})`)Also applies to: 256-264, 285-293, 316-324
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/affiliate-dashboard/src/App.tsx` around lines 227 - 237, Update the fetch error handling in App.tsx to read the new failure payload shape used by public-api: when a response is not ok, parse the JSON and prefer body.error (falling back to body.message or a status-based message) when constructing the thrown Error; apply the same change for the other similar blocks where fetch responses are checked (the blocks around the other fetch calls shown in the diff, e.g., the sections currently using body.message at lines corresponding to the other POST/PUT handlers) so errors surface the serialized { error, code } message from the API.
🧹 Nitpick comments (4)
packages/public-api/src/routes/auth/types.ts (1)
17-23: Response schemas are defined but not validated at runtime.The
SiweVerifyResponseSchemaandSiweNonceResponseSchemaare registered for OpenAPI documentation, but persiweVerify.ts(line 63) andsiweNonce.ts(line 43), the upstream responses are passed through directly without validation. If the upstream service returns a different shape (e.g.,jwtinstead oftoken), the API contract is violated silently.Consider validating upstream responses before returning them:
const data = SiweVerifyResponseSchema.safeParse(await response.json()) if (!data.success) { // handle schema mismatch } res.status(200).json(data.data)This ensures the public API contract matches what clients actually receive.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/auth/types.ts` around lines 17 - 23, The registered response schemas SiweVerifyResponseSchema and SiweNonceResponseSchema are only for docs and not used at runtime; update the handlers in siweVerify.ts (handler around line 63) and siweNonce.ts (handler around line 43) to validate upstream responses using the corresponding schema.safeParse(await response.json()), and if validation fails, log the error and return an appropriate error response (e.g., 502 Bad Gateway or 500) rather than passing through the raw upstream body; on success return the parsed .data to guarantee the public API matches the documented shape.packages/public-api/src/routes/affiliate/updateAffiliate.ts (1)
71-74: Authorization header type may need handling for array case.
req.headers.authorizationcan bestring | string[] | undefinedin Express. The spread{ Authorization: req.headers.authorization }works when it's a string, but if it's an array (unusual for Authorization but possible), it would be passed as-is to fetch headers.🛡️ Optional fix for type safety
headers: { 'Content-Type': 'application/json', - ...(req.headers.authorization ? { Authorization: req.headers.authorization } : {}), + ...(req.headers.authorization && typeof req.headers.authorization === 'string' + ? { Authorization: req.headers.authorization } + : {}), },This is a minor edge case since
Authorizationheaders are virtually never arrays in practice.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/affiliate/updateAffiliate.ts` around lines 71 - 74, Normalize the Authorization header before spreading into the fetch headers: read req.headers.authorization in updateAffiliate handler, check Array.isArray(req.headers.authorization) and if so use the first element (or join with ',') to produce a string authHeader, then include Authorization: authHeader only when authHeader is truthy; update the headers construction that currently spreads { Authorization: req.headers.authorization } to use this normalized authHeader variable to avoid passing string[] to fetch.packages/public-api/src/routes/affiliate/types.ts (1)
56-57: Consider defining explicit schemas forsellAssetandbuyAsset.Using
z.unknown()bypasses validation entirely for these fields. If the asset structure is known and consistent, defining an explicit schema would:
- Catch upstream changes that break the expected contract
- Provide better TypeScript types for consumers
- Improve OpenAPI documentation
If the structure varies significantly, this is acceptable as-is.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/affiliate/types.ts` around lines 56 - 57, The current affiliate schema uses z.unknown() for sellAsset and buyAsset which skips validation; replace these with explicit Zod schemas (for example create and reference SellAssetSchema and BuyAssetSchema or a shared AssetSchema) and use them where sellAsset and buyAsset are defined so types and OpenAPI output are accurate; if multiple asset shapes exist, use z.union([...]) or z.discriminatedUnion(...) for the variants and update any exported TypeScript types derived from the schema (e.g., via z.infer) so consumers and docs reflect the real structure.packages/public-api/src/routes/affiliate/claimPartnerCode.ts (1)
51-59: Reject missingAuthorizationlocally.This route is documented as authenticated, but a missing header still burns an upstream request. A local 401 keeps the contract in public-api and avoids avoidable load on swap-service.
As per coding guidelines, "ALWAYS validate inputs before processing with clear validation error messages and use early returns for validation failures".💡 Minimal fix
if (!parseResult.success) { res.status(400).json({ error: 'Invalid request body', code: 'INVALID_REQUEST', details: parseResult.error.errors, } as ErrorResponse) return } + + if (!req.headers.authorization) { + res.status(401).json({ + error: 'Missing Authorization header', + code: 'UNAUTHORIZED', + } as ErrorResponse) + return + } const response = await fetchSwapService( res, `${SWAP_SERVICE_BASE_URL}/v1/affiliate/claim-code`, { method: 'POST', headers: { 'Content-Type': 'application/json', - ...(req.headers.authorization ? { Authorization: req.headers.authorization } : {}), + Authorization: req.headers.authorization, }, body: JSON.stringify(parseResult.data), }, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/affiliate/claimPartnerCode.ts` around lines 51 - 59, The route currently forwards requests to fetchSwapService even when Authorization is missing; update the handler in claimPartnerCode (in packages/public-api/src/routes/affiliate/claimPartnerCode.ts) to validate req.headers.authorization early and return a local 401 response with a clear validation message (e.g., "Authorization header required") before calling fetchSwapService or constructing the request to `${SWAP_SERVICE_BASE_URL}/v1/affiliate/claim-code`; keep the existing logic to forward the Authorization header when present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/affiliate-dashboard/src/App.tsx`:
- Line 136: The AFFILIATE_URL construction uses import.meta.env.VITE_API_URL
directly and can produce malformed URLs when VITE_API_URL is missing or has a
trailing slash; update the code that defines AFFILIATE_URL to first assert that
import.meta.env.VITE_API_URL is present (throw or fail-fast), normalize it by
removing any trailing slash (or use the URL constructor with new
URL('/v1/affiliate', base) to join paths safely), and then compose AFFILIATE_URL
from the normalized base so that AFFILIATE_URL is always a valid absolute URL;
reference the AFFILIATE_URL constant and import.meta.env.VITE_API_URL when
making the change.
---
Outside diff comments:
In `@packages/affiliate-dashboard/src/App.tsx`:
- Around line 227-237: Update the fetch error handling in App.tsx to read the
new failure payload shape used by public-api: when a response is not ok, parse
the JSON and prefer body.error (falling back to body.message or a status-based
message) when constructing the thrown Error; apply the same change for the other
similar blocks where fetch responses are checked (the blocks around the other
fetch calls shown in the diff, e.g., the sections currently using body.message
at lines corresponding to the other POST/PUT handlers) so errors surface the
serialized { error, code } message from the API.
---
Nitpick comments:
In `@packages/public-api/src/routes/affiliate/claimPartnerCode.ts`:
- Around line 51-59: The route currently forwards requests to fetchSwapService
even when Authorization is missing; update the handler in claimPartnerCode (in
packages/public-api/src/routes/affiliate/claimPartnerCode.ts) to validate
req.headers.authorization early and return a local 401 response with a clear
validation message (e.g., "Authorization header required") before calling
fetchSwapService or constructing the request to
`${SWAP_SERVICE_BASE_URL}/v1/affiliate/claim-code`; keep the existing logic to
forward the Authorization header when present.
In `@packages/public-api/src/routes/affiliate/types.ts`:
- Around line 56-57: The current affiliate schema uses z.unknown() for sellAsset
and buyAsset which skips validation; replace these with explicit Zod schemas
(for example create and reference SellAssetSchema and BuyAssetSchema or a shared
AssetSchema) and use them where sellAsset and buyAsset are defined so types and
OpenAPI output are accurate; if multiple asset shapes exist, use z.union([...])
or z.discriminatedUnion(...) for the variants and update any exported TypeScript
types derived from the schema (e.g., via z.infer) so consumers and docs reflect
the real structure.
In `@packages/public-api/src/routes/affiliate/updateAffiliate.ts`:
- Around line 71-74: Normalize the Authorization header before spreading into
the fetch headers: read req.headers.authorization in updateAffiliate handler,
check Array.isArray(req.headers.authorization) and if so use the first element
(or join with ',') to produce a string authHeader, then include Authorization:
authHeader only when authHeader is truthy; update the headers construction that
currently spreads { Authorization: req.headers.authorization } to use this
normalized authHeader variable to avoid passing string[] to fetch.
In `@packages/public-api/src/routes/auth/types.ts`:
- Around line 17-23: The registered response schemas SiweVerifyResponseSchema
and SiweNonceResponseSchema are only for docs and not used at runtime; update
the handlers in siweVerify.ts (handler around line 63) and siweNonce.ts (handler
around line 43) to validate upstream responses using the corresponding
schema.safeParse(await response.json()), and if validation fails, log the error
and return an appropriate error response (e.g., 502 Bad Gateway or 500) rather
than passing through the raw upstream body; on success return the parsed .data
to guarantee the public API matches the documented shape.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a57c1682-6d1d-4507-869e-793bc92867bd
📒 Files selected for processing (36)
packages/affiliate-dashboard/.env.examplepackages/affiliate-dashboard/Dockerfilepackages/affiliate-dashboard/package.jsonpackages/affiliate-dashboard/railway.jsonpackages/affiliate-dashboard/src/App.tsxpackages/affiliate-dashboard/src/hooks/useAffiliateConfig.tspackages/affiliate-dashboard/src/hooks/useAffiliateStats.tspackages/affiliate-dashboard/src/hooks/useAffiliateSwaps.tspackages/affiliate-dashboard/src/hooks/useSiweAuth.tspackages/affiliate-dashboard/src/main.tsxpackages/affiliate-dashboard/tsconfig.jsonpackages/affiliate-dashboard/tsconfig.node.jsonpackages/affiliate-dashboard/vite.config.tspackages/public-api/src/index.tspackages/public-api/src/lib/fetchSwapService.tspackages/public-api/src/middleware/rateLimit.tspackages/public-api/src/routes/affiliate/claimPartnerCode.tspackages/public-api/src/routes/affiliate/createAffiliate.tspackages/public-api/src/routes/affiliate/getAffiliate.tspackages/public-api/src/routes/affiliate/getAffiliateStats.tspackages/public-api/src/routes/affiliate/getAffiliateSwaps.tspackages/public-api/src/routes/affiliate/index.tspackages/public-api/src/routes/affiliate/types.tspackages/public-api/src/routes/affiliate/updateAffiliate.tspackages/public-api/src/routes/assets/getAssetById.tspackages/public-api/src/routes/assets/getAssetCount.tspackages/public-api/src/routes/assets/getAssets.tspackages/public-api/src/routes/auth/index.tspackages/public-api/src/routes/auth/siweNonce.tspackages/public-api/src/routes/auth/siweVerify.tspackages/public-api/src/routes/auth/types.tspackages/public-api/src/routes/chains/getChainCount.tspackages/public-api/src/routes/chains/getChains.tspackages/public-api/src/routes/quote/getQuote.tspackages/public-api/src/routes/rates/getRates.tspackages/public-api/src/routes/status/getSwapStatus.ts
💤 Files with no reviewable changes (2)
- packages/affiliate-dashboard/tsconfig.node.json
- packages/affiliate-dashboard/Dockerfile
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/public-api/src/routes/affiliate/getAffiliateStats.ts`:
- Line 36: The OpenAPI 400 response description in getAffiliateStats.ts is too
specific to address format while the handler uses safeParse(req.query) which can
fail for date filters and other params; update the 400 response description (the
entry keyed by 400 in the route definition) to a generic message such as
"Invalid request parameters" so it matches the runtime validation behavior
performed by safeParse(req.query).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 28a6c306-c923-4b46-9d7b-fd95e446322f
📒 Files selected for processing (3)
packages/public-api/src/index.tspackages/public-api/src/routes/affiliate/getAffiliateStats.tspackages/public-api/src/routes/status/getSwapStatus.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/public-api/src/routes/status/getSwapStatus.ts
- Validate upstream responses with Zod safeParse before returning to client - Replace `as Type` response casts with `satisfies` for compile-time enforcement - Reject missing Authorization header locally on authenticated routes - Validate env vars strictly: enum for feature flags, min(1) for rate limits, regex for PORT and DEFAULT_AFFILIATE_BPS - Use env directly instead of SWAP_SERVICE_BASE_URL re-export from config - Fix new URL() leading-slash bug in getAffiliateSwaps - Use AssetSchema from assets/types for affiliate swap item validation - Move AffiliateFeeResponseSchema to types.ts for consistency - Remove || 'demo' fallback for WalletConnect project ID Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…shboard
public-api returns { error, code } not { message }, so body.message was
always undefined and errors fell back to the generic "Failed (status)" string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
packages/public-api/src/routes/affiliate/getAffiliateStats.ts (1)
80-83: Add structured context to these error logs.Both branches log free-form strings, so production triage loses the affiliate address, upstream status, and route context. Please switch these to the service logger with structured fields.
As per coding guidelines, ALWAYS log errors for debugging using structured logging with relevant context and error metadata.
Also applies to: 99-103
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/affiliate/getAffiliateStats.ts` around lines 80 - 83, Replace the free-form console.error calls that log responseResult.error.errors with structured service logging: in the getAffiliateStats handler, call the service logger (e.g., serviceLogger.error) and pass a structured payload including affiliateAddress (the affiliateAddress variable), route or handler identifier (e.g., "getAffiliateStats"), upstreamStatus (from responseResult.status or response.status), and the full response/result object (responseResult) plus the error details, and use a short message like "Unexpected response shape from swap-service /swaps/affiliate-fees"; apply the same structured-logging change to the other branch that currently logs at lines 99-103 so both places use serviceLogger.error with the same fields for easier triage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/affiliate-dashboard/src/config/wagmi.ts`:
- Line 5: The code reads VITE_WALLETCONNECT_PROJECT_ID into the projectId
constant without validation; add a fail-fast check after the declaration of
projectId that throws a clear Error (or throws new Error("Missing
VITE_WALLETCONNECT_PROJECT_ID: please set env var
VITE_WALLETCONNECT_PROJECT_ID")) when projectId is falsy so downstream uses of
projectId (used to initialize WalletConnect in this module) never run with an
undefined value; reference the projectId constant to locate where to insert this
guard.
In `@packages/public-api/src/routes/affiliate/getAffiliateStats.ts`:
- Around line 78-88: The code calls await response.json() before running
AffiliateFeeResponseSchema.safeParse, so if the swap-service returns non-JSON
this throws out to the outer catch and becomes a 500; wrap the JSON parsing in a
small try/catch and treat JSON parse errors the same as schema failures: log the
parse error and respond with res.status(503).json({ error: 'Invalid response
from swap service', code: 'INVALID_RESPONSE' }) (the same flow used when
AffiliateFeeResponseSchema.safeParse fails). Apply the same change to the
duplicate parsing block around the code handling the other response (the block
referenced at lines ~98-103) so all malformed upstream bodies produce
503/INVALID_RESPONSE instead of 500.
In `@packages/public-api/src/routes/affiliate/types.ts`:
- Around line 100-106: The affiliate address fields are using plain strings
which weakens validation; update AffiliateFeeResponseSchema.affiliateAddress and
AffiliateStatsResponseSchema.address (and any other stat/address fields in these
schemas) to use the shared EVM_ADDRESS schema instead of z.string(); locate the
EVM_ADDRESS export and replace the z.string() usages in the
AffiliateFeeResponseSchema and AffiliateStatsResponseSchema definitions so the
fields validate as viem EVM addresses.
- Around line 33-38: The partnerCode field in CreateAffiliateRequestSchema
accepts empty or whitespace-only strings; update partnerCode to reject blank
values by applying trimming and a minimum-length constraint (e.g., use
z.string().trim().min(1).optional()) so whitespace/empty inputs fail validation
and return 400; apply the same change to the other affiliate-related request
schema in this file that also declares partnerCode so both schemas consistently
reject blank partner codes.
In `@packages/public-api/src/routes/status/getSwapStatus.ts`:
- Around line 30-35: The handler getSwapStatus currently swallows upstream
swap-service failures in its catch block (around the code handling lines 97-116)
and proceeds to return a 200 with stale local status; change that behavior so
when the upstream call to swap-service fails or times out the handler returns an
appropriate 5xx (use 504 for timeouts and 503 for other upstream errors) with a
clear error body, log the error details, and short-circuit the request instead
of returning the stale status; also update the OpenAPI responses object (the
response map near the top where 400/404/409/429/500 are defined) to include 503
and 504 descriptions so clients can see these new responses.
---
Nitpick comments:
In `@packages/public-api/src/routes/affiliate/getAffiliateStats.ts`:
- Around line 80-83: Replace the free-form console.error calls that log
responseResult.error.errors with structured service logging: in the
getAffiliateStats handler, call the service logger (e.g., serviceLogger.error)
and pass a structured payload including affiliateAddress (the affiliateAddress
variable), route or handler identifier (e.g., "getAffiliateStats"),
upstreamStatus (from responseResult.status or response.status), and the full
response/result object (responseResult) plus the error details, and use a short
message like "Unexpected response shape from swap-service
/swaps/affiliate-fees"; apply the same structured-logging change to the other
branch that currently logs at lines 99-103 so both places use
serviceLogger.error with the same fields for easier triage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 21a8a324-99a2-4b62-95d2-370a96897278
📒 Files selected for processing (21)
packages/affiliate-dashboard/src/App.tsxpackages/affiliate-dashboard/src/config/wagmi.tspackages/public-api/src/lib/fetchSwapService.tspackages/public-api/src/routes/affiliate/claimPartnerCode.tspackages/public-api/src/routes/affiliate/createAffiliate.tspackages/public-api/src/routes/affiliate/getAffiliate.tspackages/public-api/src/routes/affiliate/getAffiliateStats.tspackages/public-api/src/routes/affiliate/getAffiliateSwaps.tspackages/public-api/src/routes/affiliate/types.tspackages/public-api/src/routes/affiliate/updateAffiliate.tspackages/public-api/src/routes/assets/getAssetById.tspackages/public-api/src/routes/assets/getAssetCount.tspackages/public-api/src/routes/assets/getAssets.tspackages/public-api/src/routes/assets/types.tspackages/public-api/src/routes/auth/siweNonce.tspackages/public-api/src/routes/auth/siweVerify.tspackages/public-api/src/routes/chains/getChainCount.tspackages/public-api/src/routes/chains/getChains.tspackages/public-api/src/routes/quote/getQuote.tspackages/public-api/src/routes/rates/getRates.tspackages/public-api/src/routes/status/getSwapStatus.ts
✅ Files skipped from review due to trivial changes (1)
- packages/public-api/src/routes/chains/getChainCount.ts
🚧 Files skipped from review as they are similar to previous changes (14)
- packages/public-api/src/routes/chains/getChains.ts
- packages/public-api/src/routes/rates/getRates.ts
- packages/public-api/src/routes/assets/getAssetById.ts
- packages/affiliate-dashboard/src/App.tsx
- packages/public-api/src/routes/quote/getQuote.ts
- packages/public-api/src/routes/affiliate/getAffiliate.ts
- packages/public-api/src/lib/fetchSwapService.ts
- packages/public-api/src/routes/affiliate/claimPartnerCode.ts
- packages/public-api/src/routes/assets/getAssetCount.ts
- packages/public-api/src/routes/assets/getAssets.ts
- packages/public-api/src/routes/affiliate/createAffiliate.ts
- packages/public-api/src/routes/auth/siweVerify.ts
- packages/public-api/src/routes/affiliate/getAffiliateSwaps.ts
- packages/public-api/src/routes/affiliate/updateAffiliate.ts
…ashboard - Add .catch(() => null) to all upstream safeParse calls for non-JSON safety - Convert SwapServiceStatus type to SwapServiceStatusSchema for runtime validation - Refactor getSwapStatus: immutable store updates, mutable response object, fetchSwapService helper, 503/504 on upstream failures, early return after first registration, remove dead concurrent guard, require txHash to begin tracking - Use EVM_ADDRESS for AffiliateFeeResponseSchema.affiliateAddress and AffiliateStatsResponseSchema.address - Add .trim().min(1) to partnerCode fields in CreateAffiliate and ClaimPartnerCode - Add fail-fast guard for VITE_WALLETCONNECT_PROJECT_ID in wagmi.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/public-api/src/routes/status/types.ts (1)
15-15: Use the shared EVM address validator instead of a plain string.Line 15 accepts any string for
affiliateAddress. Reusing the existing EVM address schema here would keep validation consistent and prevent malformed addresses from propagating.♻️ Proposed refactor
import { z } from 'zod' import { registry } from '../../registry' +import { EVM_ADDRESS } from '../affiliate/types' @@ hasAffiliate: z.boolean(), affiliateBps: z.number().optional(), - affiliateAddress: z.string().optional(), + affiliateAddress: EVM_ADDRESS.optional(),As per coding guidelines: "ALWAYS validate inputs before processing with clear validation error messages and use early returns for validation failures."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/status/types.ts` at line 15, Replace the loose affiliateAddress: z.string().optional() schema with the shared EVM address validator: import the existing evm address schema (e.g., evmAddressSchema or the shared validator exported by your common schemas) and use evmAddressSchema.optional() for the affiliateAddress field in the status types definition so addresses are validated consistently; update the import at the top of the file to pull the shared validator and remove the plain z.string() usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/public-api/src/routes/status/types.ts`:
- Line 15: Replace the loose affiliateAddress: z.string().optional() schema with
the shared EVM address validator: import the existing evm address schema (e.g.,
evmAddressSchema or the shared validator exported by your common schemas) and
use evmAddressSchema.optional() for the affiliateAddress field in the status
types definition so addresses are validated consistently; update the import at
the top of the file to pull the shared validator and remove the plain z.string()
usage.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: eb46c212-0788-41bc-b52b-68c12f05842d
📒 Files selected for processing (12)
packages/affiliate-dashboard/src/config/wagmi.tspackages/public-api/src/routes/affiliate/claimPartnerCode.tspackages/public-api/src/routes/affiliate/createAffiliate.tspackages/public-api/src/routes/affiliate/getAffiliate.tspackages/public-api/src/routes/affiliate/getAffiliateStats.tspackages/public-api/src/routes/affiliate/getAffiliateSwaps.tspackages/public-api/src/routes/affiliate/types.tspackages/public-api/src/routes/affiliate/updateAffiliate.tspackages/public-api/src/routes/auth/siweNonce.tspackages/public-api/src/routes/auth/siweVerify.tspackages/public-api/src/routes/status/getSwapStatus.tspackages/public-api/src/routes/status/types.ts
✅ Files skipped from review due to trivial changes (1)
- packages/public-api/src/routes/affiliate/claimPartnerCode.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/affiliate-dashboard/src/config/wagmi.ts
- packages/public-api/src/routes/auth/siweNonce.ts
- packages/public-api/src/routes/affiliate/getAffiliateSwaps.ts
- packages/public-api/src/routes/status/getSwapStatus.ts
- packages/public-api/src/routes/affiliate/types.ts
- packages/public-api/src/routes/affiliate/updateAffiliate.ts
- packages/public-api/src/routes/affiliate/getAffiliateStats.ts
…schemas Move EVM_ADDRESS from affiliate/types to src/types so it can be shared across routes. Apply to affiliateAddress fields in SwapServiceStatusSchema and SwapStatusResponseSchema. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/public-api/src/routes/affiliate/types.ts (1)
27-42: Consider adding max constraint forbpsfield.The
bpsfield validatesmin(0)but has no upper bound. Basis points typically max at 10000 (100%). If the upstream service enforces this, you might want to fail-fast here.💡 Suggested validation
export const CreateAffiliateRequestSchema = z.object({ walletAddress: EVM_ADDRESS, receiveAddress: EVM_ADDRESS.optional(), partnerCode: z.string().trim().min(1, 'partnerCode must not be empty').optional(), - bps: z.number().int().min(0).optional(), + bps: z.number().int().min(0).max(10000, 'bps cannot exceed 10000 (100%)').optional(), }) export const UpdateAffiliateRequestSchema = z.object({ receiveAddress: EVM_ADDRESS.optional(), - bps: z.number().int().min(0).optional(), + bps: z.number().int().min(0).max(10000, 'bps cannot exceed 10000 (100%)').optional(), })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/routes/affiliate/types.ts` around lines 27 - 42, The bps field currently only enforces .min(0) which allows values >10000; update the zod validators for bps inside CreateAffiliateRequestSchema and UpdateAffiliateRequestSchema to also enforce an upper bound (e.g., .max(10000, 'bps must be <= 10000')) so basis-points cannot exceed 100% and will fail-fast before calling the upstream service.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/public-api/src/routes/affiliate/types.ts`:
- Around line 27-42: The bps field currently only enforces .min(0) which allows
values >10000; update the zod validators for bps inside
CreateAffiliateRequestSchema and UpdateAffiliateRequestSchema to also enforce an
upper bound (e.g., .max(10000, 'bps must be <= 10000')) so basis-points cannot
exceed 100% and will fail-fast before calling the upstream service.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ef8c19e-3a70-4623-b7be-cc2dbd14ea25
📒 Files selected for processing (3)
packages/public-api/src/routes/affiliate/types.tspackages/public-api/src/routes/status/types.tspackages/public-api/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/public-api/src/routes/status/types.ts
NeOMakinG
left a comment
There was a problem hiding this comment.
Stamping for the sake of progression as this is quite urgent considering we have a customer accepting to integrate the widget with the affiliate system
And this should be tested carefully in the dev environment for DX purposes
Summary
public-api
GET /affiliate/:address,POST /affiliate,PATCH /affiliate/:address,POST /affiliate/claim-code,GET /affiliate/swapsPOST /auth/siwe/nonce,POST /auth/siwe/verifyfetchSwapServicehelper to deduplicate AbortController + 503/504 error handling across all upstream fetch callsaffiliateMutationLimiter(20 req/min) applied to all mutation and auth routeschainIdfiltering toGET /assets/counttypes.tsby feature group with consistent*RequestSchema/*ResponseSchemanamingaffiliate-dashboard
VITE_API_URLenv var for production compatibilitytsconfig.node.jsonreference (folded into main tsconfig).env.examplewith required env varsmain.tsxifVITE_API_URLis not set in productionTest plan
GET /v1/affiliate/:addressreturns affiliate config from swap-servicePOST /v1/affiliatecreates affiliate (requires Authorization header)PATCH /v1/affiliate/:addressupdates affiliate (requires Authorization header)POST /v1/affiliate/claim-codeclaims partner code (requires Authorization header)GET /v1/affiliate/swapsreturns paginated swap historyPOST /v1/auth/siwe/noncereturns a noncePOST /v1/auth/siwe/verifyreturns JWT on valid signatureGET /v1/assets/count?chainId=eip155:1returns filtered countVITE_API_URL🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores