@@ -2,7 +2,8 @@ import axios from 'axios'
22import clonedeep from 'lodash/cloneDeep'
33import Qs from 'qs'
44import { ConcurrencyQueue } from './concurrency-queue'
5- import { isHost } from './Util'
5+ import { isHost , normalizePlugins } from './Util'
6+ import { ERROR_MESSAGES } from './errorMessages'
67
78export default function contentstackHttpClient ( options ) {
89 const defaultConfig = {
@@ -11,7 +12,7 @@ export default function contentstackHttpClient (options) {
1112 logHandler : ( level , data ) => {
1213 if ( level === 'error' && data ) {
1314 const title = [ data . name , data . message ] . filter ( ( a ) => a ) . join ( ' - ' )
14- console . error ( `[error] ${ title } ` )
15+ console . error ( ERROR_MESSAGES . ERROR_WITH_TITLE ( title ) )
1516 return
1617 }
1718 console . log ( `[${ level } ] ${ data } ` )
@@ -109,6 +110,11 @@ export default function contentstackHttpClient (options) {
109110 const instance = axios . create ( axiosOptions )
110111 instance . httpClientParams = options
111112 instance . concurrencyQueue = new ConcurrencyQueue ( { axios : instance , config } )
113+
114+ // Normalize and store plugins
115+ const plugins = normalizePlugins ( config . plugins )
116+
117+ // Request interceptor for versioning strategy (must run first)
112118 instance . interceptors . request . use ( ( request ) => {
113119 if ( request . versioningStrategy && request . versioningStrategy === 'path' ) {
114120 request . baseURL = request . baseURL . replace ( '{api-version}' , version )
@@ -117,5 +123,117 @@ export default function contentstackHttpClient (options) {
117123 }
118124 return request
119125 } )
126+
127+ // Request interceptor for plugins (runs after versioning)
128+ if ( plugins . length > 0 ) {
129+ instance . interceptors . request . use (
130+ ( request ) => {
131+ // Run all onRequest hooks sequentially, using return values
132+ let currentRequest = request
133+ for ( const plugin of plugins ) {
134+ try {
135+ if ( typeof plugin . onRequest === 'function' ) {
136+ const result = plugin . onRequest ( currentRequest )
137+ // Use returned value if provided, otherwise use current request
138+ if ( result !== undefined ) {
139+ currentRequest = result
140+ }
141+ }
142+ } catch ( error ) {
143+ // Log error and continue with next plugin
144+ if ( config . logHandler ) {
145+ config . logHandler ( 'error' , {
146+ name : 'PluginError' ,
147+ message : `Error in plugin onRequest: ${ error . message } ` ,
148+ error : error
149+ } )
150+ }
151+ }
152+ }
153+ return currentRequest
154+ } ,
155+ ( error ) => {
156+ // Handle request errors - run plugins even on error
157+ let currentConfig = error . config
158+ for ( const plugin of plugins ) {
159+ try {
160+ if ( typeof plugin . onRequest === 'function' && currentConfig ) {
161+ const result = plugin . onRequest ( currentConfig )
162+ // Use returned value if provided, otherwise use current config
163+ if ( result !== undefined ) {
164+ currentConfig = result
165+ error . config = currentConfig
166+ }
167+ }
168+ } catch ( pluginError ) {
169+ if ( config . logHandler ) {
170+ config . logHandler ( 'error' , {
171+ name : 'PluginError' ,
172+ message : `Error in plugin onRequest (error handler): ${ pluginError . message } ` ,
173+ error : pluginError
174+ } )
175+ }
176+ }
177+ }
178+ return Promise . reject ( error )
179+ }
180+ )
181+
182+ // Response interceptor for plugins
183+ instance . interceptors . response . use (
184+ ( response ) => {
185+ // Run all onResponse hooks sequentially for successful responses
186+ // Use return values from plugins
187+ let currentResponse = response
188+ for ( const plugin of plugins ) {
189+ try {
190+ if ( typeof plugin . onResponse === 'function' ) {
191+ const result = plugin . onResponse ( currentResponse )
192+ // Use returned value if provided, otherwise use current response
193+ if ( result !== undefined ) {
194+ currentResponse = result
195+ }
196+ }
197+ } catch ( error ) {
198+ // Log error and continue with next plugin
199+ if ( config . logHandler ) {
200+ config . logHandler ( 'error' , {
201+ name : 'PluginError' ,
202+ message : `Error in plugin onResponse: ${ error . message } ` ,
203+ error : error
204+ } )
205+ }
206+ }
207+ }
208+ return currentResponse
209+ } ,
210+ ( error ) => {
211+ // Handle response errors - run plugins even on error
212+ // Pass the error object (which may contain error.response if server responded)
213+ let currentError = error
214+ for ( const plugin of plugins ) {
215+ try {
216+ if ( typeof plugin . onResponse === 'function' ) {
217+ const result = plugin . onResponse ( currentError )
218+ // Use returned value if provided, otherwise use current error
219+ if ( result !== undefined ) {
220+ currentError = result
221+ }
222+ }
223+ } catch ( pluginError ) {
224+ if ( config . logHandler ) {
225+ config . logHandler ( 'error' , {
226+ name : 'PluginError' ,
227+ message : `Error in plugin onResponse (error handler): ${ pluginError . message } ` ,
228+ error : pluginError
229+ } )
230+ }
231+ }
232+ }
233+ return Promise . reject ( currentError )
234+ }
235+ )
236+ }
237+
120238 return instance
121239}
0 commit comments