@@ -233,6 +233,48 @@ export namespace OpenPolicyAgent {
233233 get ( pretty ?: boolean ) : Promise < GetStatusResponse >
234234 }
235235
236+ export type OPAError = {
237+ readonly code : string ,
238+ readonly message : string ,
239+ readonly location : { file : string , row : number , col : number }
240+ readonly details : { line : string , idx : number }
241+ }
242+
243+ export class ClientError extends Error {
244+
245+
246+ constructor ( public readonly code : string , message : string , public readonly errors : OPAError [ ] , public readonly response : Response ) {
247+ super ( message ) ;
248+ }
249+
250+ toString ( ) {
251+ return JSON . stringify ( {
252+ code : this . code ,
253+ message : this . message ,
254+ errors : this . errors
255+ } )
256+ }
257+
258+ static async fromResponse ( response : Response ) {
259+ let code : string = 'unknown' ;
260+ let message = `OPA request failed: ${ response . status } ${ response . statusText } ` ;
261+ let errors : OPAError [ ] = [ ] ;
262+ try {
263+ const bodyText = await response . text ( ) ;
264+ if ( bodyText ) {
265+ const resp_body = JSON . parse ( bodyText ) ;
266+ if ( 'code' in resp_body && resp_body . code ) code = resp_body . code ;
267+ if ( 'message' in resp_body && resp_body . message ) message = resp_body . message ;
268+ if ( 'errors' in resp_body && resp_body . errors ) code = resp_body . errors ;
269+ }
270+ } catch {
271+ // Ignore
272+ }
273+ return new ClientError ( code , message , errors , response ) ; ;
274+ }
275+
276+ }
277+
236278 /**
237279 * A lightweight TypeScript client for the Open Policy Agent (OPA) REST API.
238280 * Uses the native `fetch` API and requires no external dependencies.
@@ -324,19 +366,7 @@ export namespace OpenPolicyAgent {
324366 } ) ;
325367
326368 if ( ! response . ok ) {
327- let message = `OPA request failed: ${ response . status } ${ response . statusText } ` ;
328- let cause : any ;
329- try {
330- const bodyText = await response . text ( ) ;
331- if ( bodyText ) {
332- cause = JSON . parse ( bodyText ) ;
333- if ( cause . message ) message += ` - ${ cause . message } ` ;
334- }
335- } catch {
336- // Ignore
337- }
338- // @ts -ignore
339- throw new Error ( message , { cause} ) ;
369+ throw await ClientError . fromResponse ( response ) ;
340370 }
341371
342372 const text = await response . text ( ) ;
0 commit comments