Summary
api/v1/ (Vercel serverless functions) and apps/api/ (Fastify server) both implement the same set of routes (vaults, positions, tx/deposit, tx/withdraw, tx/add-trustline, tx/submit) as separate handler files. They share the underlying @meridian/shared and @meridian/stellar-sdk-helpers packages, but the routing, request parsing, and response shaping is written and maintained twice.
Motivation
Every endpoint change has to be made in two places by hand, and nothing in the type system enforces that they stay in sync. A behavior fix applied to one (for example the CORS/rate-limit middleware) is not automatically applied to the other unless someone remembers to port it. This is a correctness risk, not just duplicated effort: the two layers can silently drift.
Proposed Solution
Extract the shared per-route logic (validation, calling into the SDK helpers, error shaping) into framework-agnostic functions in packages/shared or a new package, and have both the Vercel handlers and the Fastify routes call the same functions, differing only in the thin adapter layer that maps their respective request/response objects to the shared signature.
Scope
| Field |
Value |
| Area |
API |
| Protocol affected |
None |
| Network |
N/A |
| Breaking change? |
No |
Alternatives Considered
Leaving them separate and relying on code review to catch drift: this is the current state and has already produced inconsistencies between the two layers.
Acceptance Criteria
Summary
api/v1/(Vercel serverless functions) andapps/api/(Fastify server) both implement the same set of routes (vaults, positions, tx/deposit, tx/withdraw, tx/add-trustline, tx/submit) as separate handler files. They share the underlying@meridian/sharedand@meridian/stellar-sdk-helperspackages, but the routing, request parsing, and response shaping is written and maintained twice.Motivation
Every endpoint change has to be made in two places by hand, and nothing in the type system enforces that they stay in sync. A behavior fix applied to one (for example the CORS/rate-limit middleware) is not automatically applied to the other unless someone remembers to port it. This is a correctness risk, not just duplicated effort: the two layers can silently drift.
Proposed Solution
Extract the shared per-route logic (validation, calling into the SDK helpers, error shaping) into framework-agnostic functions in
packages/sharedor a new package, and have both the Vercel handlers and the Fastify routes call the same functions, differing only in the thin adapter layer that maps their respective request/response objects to the shared signature.Scope
Alternatives Considered
Leaving them separate and relying on code review to catch drift: this is the current state and has already produced inconsistencies between the two layers.
Acceptance Criteria
api/v1/andapps/api/pnpm lint && pnpm typecheck && pnpm testpass with no regressions