11import type fastify from 'fastify' ;
22import * as uuid from 'uuid' ;
33
4- import { errors , HTTPMethod , logger , router } from '@powersync/lib-services-framework' ;
4+ import {
5+ ErrorCode ,
6+ errors ,
7+ HTTPMethod ,
8+ logger ,
9+ RouteNotFound ,
10+ router ,
11+ ServiceError
12+ } from '@powersync/lib-services-framework' ;
513import { Context , ContextProvider , RequestEndpoint , RequestEndpointHandlerPayload } from './router.js' ;
14+ import { FastifyReply } from 'fastify' ;
615
716export type FastifyEndpoint < I , O , C > = RequestEndpoint < I , O , C > & {
817 parse ?: boolean ;
@@ -69,23 +78,11 @@ export function registerFastifyRoutes(
6978 const serviceError = errors . asServiceError ( ex ) ;
7079 requestLogger . error ( `Request failed` , serviceError ) ;
7180
72- response = new router . RouterResponse ( {
73- status : serviceError . errorData . status || 500 ,
74- headers : {
75- 'Content-Type' : 'application/json'
76- } ,
77- data : {
78- error : serviceError . errorData
79- }
80- } ) ;
81+ response = serviceErrorToResponse ( serviceError ) ;
8182 }
8283
83- Object . keys ( response . headers ) . forEach ( ( key ) => {
84- reply . header ( key , response . headers [ key ] ) ;
85- } ) ;
86- reply . status ( response . status ) ;
8784 try {
88- await reply . send ( response . data ) ;
85+ await respond ( reply , response ) ;
8986 } finally {
9087 await response . afterSend ?.( { clientClosed : request . socket . closed } ) ;
9188 requestLogger . info ( `${ e . method } ${ request . url } ` , {
@@ -106,3 +103,32 @@ export function registerFastifyRoutes(
106103 } ) ;
107104 }
108105}
106+
107+ /**
108+ * Registers a custom not-found handler to ensure 404 error responses have the same schema as other service errors.
109+ */
110+ export function registerFastifyNotFoundHandler ( app : fastify . FastifyInstance ) {
111+ app . setNotFoundHandler ( async ( request , reply ) => {
112+ await respond ( reply , serviceErrorToResponse ( new RouteNotFound ( request . originalUrl , request . method ) ) ) ;
113+ } ) ;
114+ }
115+
116+ function serviceErrorToResponse ( error : ServiceError ) : router . RouterResponse {
117+ return new router . RouterResponse ( {
118+ status : error . errorData . status || 500 ,
119+ headers : {
120+ 'Content-Type' : 'application/json'
121+ } ,
122+ data : {
123+ error : error . errorData
124+ }
125+ } ) ;
126+ }
127+
128+ async function respond ( reply : FastifyReply , response : router . RouterResponse ) {
129+ Object . keys ( response . headers ) . forEach ( ( key ) => {
130+ reply . header ( key , response . headers [ key ] ) ;
131+ } ) ;
132+ reply . status ( response . status ) ;
133+ await reply . send ( response . data ) ;
134+ }
0 commit comments