@kubb/plugin-axios 5.5.4 → 5.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/templates/axios.ts +64 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-axios",
3
- "version": "5.5.4",
3
+ "version": "5.5.5",
4
4
  "description": "Generate a slim, type-safe HTTP client with Kubb based on axios.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -65,7 +65,7 @@
65
65
  "registry": "https://registry.npmjs.org/"
66
66
  },
67
67
  "dependencies": {
68
- "@kubb/plugin-ts": "^5.0.4",
68
+ "@kubb/plugin-ts": "^5.0.5",
69
69
  "@kubb/plugin-zod": "^5.4.3"
70
70
  },
71
71
  "devDependencies": {
@@ -414,6 +414,7 @@ function serializeUrl({
414
414
 
415
415
  /**
416
416
  * Wraps an axios interceptor registration behind the shared `use` / `eject` / `update` API, mapping a stable external id onto axios's own so `update` can swap a handler in place.
417
+ * `detach` / `attach` move every registered handler to another instance, keeping the external ids.
417
418
  */
418
419
  function createInterceptorChannel<T, TRequest, TResponse>(
419
420
  register: (fn: InterceptorFn<T, TRequest, TResponse>) => number,
@@ -421,9 +422,16 @@ function createInterceptorChannel<T, TRequest, TResponse>(
421
422
  getRequestConfig: (value: T) => RequestConfig<unknown, TRequest, TResponse> | undefined,
422
423
  getContextId: (value: T) => number | undefined,
423
424
  setContextId: (value: T, id: number | undefined) => void,
424
- ): InterceptorChannel<T, TRequest, TResponse> {
425
+ nextSeq?: () => number,
426
+ ): InterceptorChannel<T, TRequest, TResponse> & {
427
+ detach: () => void
428
+ attach: () => void
429
+ getEntries: () => Array<{ seq: number; attach: () => void }>
430
+ } {
425
431
  const ids = new Map<number, number>()
432
+ const handlers = new Map<number, { fn: InterceptorFn<T, TRequest, TResponse>; seq: number }>()
426
433
  let counter = 0
434
+ const getSeq = nextSeq ?? (() => ++counter)
427
435
  const registerWithContext = (fn: InterceptorFn<T, TRequest, TResponse>) =>
428
436
  register(async (value) => {
429
437
  const contextId = getContextId(value)
@@ -435,6 +443,8 @@ function createInterceptorChannel<T, TRequest, TResponse>(
435
443
  return {
436
444
  use(fn) {
437
445
  const id = ++counter
446
+ const seq = getSeq()
447
+ handlers.set(id, { fn, seq })
438
448
  ids.set(id, registerWithContext(fn))
439
449
  return id
440
450
  },
@@ -443,12 +453,30 @@ function createInterceptorChannel<T, TRequest, TResponse>(
443
453
  if (nativeId === undefined) return
444
454
  ejectNative(nativeId)
445
455
  ids.delete(id)
456
+ handlers.delete(id)
446
457
  },
447
458
  update(id, fn) {
448
459
  const nativeId = ids.get(id)
449
- if (nativeId !== undefined) ejectNative(nativeId)
460
+ if (nativeId === undefined) return
461
+ ejectNative(nativeId)
462
+ const seq = getSeq()
463
+ handlers.set(id, { fn, seq })
450
464
  ids.set(id, registerWithContext(fn))
451
465
  },
466
+ detach() {
467
+ for (const nativeId of ids.values()) ejectNative(nativeId)
468
+ ids.clear()
469
+ },
470
+ attach() {
471
+ const sorted = Array.from(handlers.entries()).sort((a, b) => a[1].seq - b[1].seq)
472
+ for (const [id, entry] of sorted) ids.set(id, registerWithContext(entry.fn))
473
+ },
474
+ getEntries() {
475
+ return Array.from(handlers.entries()).map(([id, entry]) => ({
476
+ seq: entry.seq,
477
+ attach: () => ids.set(id, registerWithContext(entry.fn)),
478
+ }))
479
+ },
452
480
  }
453
481
  }
454
482
 
@@ -696,7 +724,8 @@ async function settleResponse<TRequest, TResponse>({
696
724
  */
697
725
  export function createClientCore<TRequest = AxiosRequestConfig, TResponse = AxiosResponse>(options: ClientConfig = {}): ClientInstance<TRequest, TResponse> {
698
726
  let config: ClientConfig = { ...options }
699
- const instance = config.transport ?? axios.create()
727
+ const baseInstance = config.transport ?? axios.create()
728
+ let instance = baseInstance
700
729
  const requestContexts = new Map<number, RequestConfig<unknown, TRequest, TResponse>>()
701
730
  let requestContextId = 0
702
731
  const getContextId = (value: AxiosRequestConfig | AxiosResponse | AxiosError) => {
@@ -717,34 +746,48 @@ export function createClientCore<TRequest = AxiosRequestConfig, TResponse = Axio
717
746
  else contextualConfig.__kubbRequestContext = id
718
747
  }
719
748
 
720
- const requestManager = instance.interceptors.request
721
- const responseManager = instance.interceptors.response
722
- const interceptors: Interceptors<TRequest, TResponse> = {
749
+ let sequenceCounter = 0
750
+ const nextSeq = () => ++sequenceCounter
751
+
752
+ // Read at call time so the channels follow a transport swapped in through setConfig.
753
+ const channels = {
723
754
  request: createInterceptorChannel<InternalAxiosRequestConfig, TRequest, TResponse>(
724
- (fn) => requestManager.use(fn),
725
- (id) => requestManager.eject(id),
755
+ (fn) => instance.interceptors.request.use(fn),
756
+ (id) => instance.interceptors.request.eject(id),
726
757
  getRequestConfig,
727
758
  getContextId,
728
759
  setContextId,
760
+ nextSeq,
729
761
  ),
730
762
  response: createInterceptorChannel<AxiosResponse, TRequest, TResponse>(
731
- (fn) => responseManager.use(fn),
732
- (id) => responseManager.eject(id),
763
+ (fn) => instance.interceptors.response.use(fn),
764
+ (id) => instance.interceptors.response.eject(id),
733
765
  getRequestConfig,
734
766
  getContextId,
735
767
  setContextId,
768
+ nextSeq,
736
769
  ),
737
770
  error: createInterceptorChannel<AxiosError, TRequest, TResponse>(
738
- (fn) => responseManager.use(undefined, (error: unknown) => Promise.resolve(fn(error as AxiosError)).then(() => Promise.reject(error))),
739
- (id) => responseManager.eject(id),
771
+ (fn) =>
772
+ instance.interceptors.response.use(undefined, (error: unknown) =>
773
+ Promise.resolve(fn(error as AxiosError)).then((result) => Promise.reject(result ?? error)),
774
+ ),
775
+ (id) => instance.interceptors.response.eject(id),
740
776
  getRequestConfig,
741
777
  getContextId,
742
778
  setContextId,
779
+ nextSeq,
743
780
  ),
744
781
  }
782
+ const channelList = [channels.request, channels.response, channels.error]
783
+ const interceptors: Interceptors<TRequest, TResponse> = {
784
+ request: { use: channels.request.use, eject: channels.request.eject, update: channels.request.update },
785
+ response: { use: channels.response.use, eject: channels.response.eject, update: channels.response.update },
786
+ error: { use: channels.error.use, eject: channels.error.eject, update: channels.error.update },
787
+ }
745
788
 
746
789
  const client = (async <TBody = unknown>(requestConfig: RequestConfig<TBody, TRequest, TResponse>): Promise<CallResult<TRequest, TResponse>> => {
747
- const activeInstance = requestConfig.transport ?? config.transport ?? instance
790
+ const activeInstance = requestConfig.transport ?? instance
748
791
  const { axiosConfig, codecs, throwOnError } = await resolveRequest({ config, requestConfig })
749
792
  const contextId = ++requestContextId
750
793
  requestContexts.set(contextId, requestConfig)
@@ -788,6 +831,14 @@ export function createClientCore<TRequest = AxiosRequestConfig, TResponse = Axio
788
831
  client.getConfig = () => config
789
832
  client.setConfig = (next) => {
790
833
  config = { ...config, ...next, headers: { ...serializeHeaders(config.headers), ...serializeHeaders(next.headers) } }
834
+ const nextInstance = config.transport ?? baseInstance
835
+ if (nextInstance !== instance) {
836
+ for (const channel of channelList) channel.detach()
837
+ instance = nextInstance
838
+ channels.request.attach()
839
+ const responseEntries = [...channels.response.getEntries(), ...channels.error.getEntries()].sort((a, b) => a.seq - b.seq)
840
+ for (const entry of responseEntries) entry.attach()
841
+ }
791
842
  return config
792
843
  }
793
844
  client.getUrl = (requestConfig) => {