@conduit-client/service-fetch-network 3.5.0 → 3.6.2

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.
@@ -6,11 +6,13 @@ export type IFetchService = FetchService;
6
6
  export type FetchServiceDescriptor = ServiceDescriptor<IFetchService, 'fetch', '1.0'>;
7
7
  export type NamedFetchService<Name extends string = 'fetch'> = NamedService<Name, IFetchService>;
8
8
  export type RequestInterceptor<Context = any> = (fetchArgs: FetchParameters, context?: Context) => PromiseLike<FetchParameters>;
9
+ export type RetryInterceptor<Context = any> = (fetchArgs: FetchParameters, retryService?: RetryService<Response>, context?: Context) => PromiseLike<Response>;
9
10
  export type ResponseInterceptor<Context = any> = (response: Response, context?: Context) => PromiseLike<Response>;
10
11
  export type FinallyInterceptor<Context = any> = (context?: Context) => PromiseLike<void> | void;
11
12
  export type Interceptors<Context = any> = {
12
13
  createContext?: () => Context;
13
14
  request?: RequestInterceptor<Context>[];
15
+ retry?: RetryInterceptor<Context>;
14
16
  response?: ResponseInterceptor<Context>[];
15
17
  finally?: FinallyInterceptor<Context>[];
16
18
  };
package/dist/v1/index.js CHANGED
@@ -4,7 +4,12 @@
4
4
  * For full license text, see the LICENSE.txt file
5
5
  */
6
6
  import { resolvedPromiseLike } from "@conduit-client/utils";
7
- function buildServiceDescriptor(interceptors = { request: [], response: [], finally: [] }, retryService) {
7
+ function buildServiceDescriptor(interceptors = {
8
+ request: [],
9
+ retry: void 0,
10
+ response: [],
11
+ finally: []
12
+ }, retryService) {
8
13
  return {
9
14
  type: "fetch",
10
15
  version: "1.0",
@@ -13,6 +18,7 @@ function buildServiceDescriptor(interceptors = { request: [], response: [], fina
13
18
  const context = (_a = interceptors.createContext) == null ? void 0 : _a.call(interceptors);
14
19
  const {
15
20
  request: requestInterceptors = [],
21
+ retry: retryInterceptor = void 0,
16
22
  response: responseInterceptors = [],
17
23
  finally: finallyInterceptors = []
18
24
  } = interceptors;
@@ -21,10 +27,14 @@ function buildServiceDescriptor(interceptors = { request: [], response: [], fina
21
27
  resolvedPromiseLike(args)
22
28
  );
23
29
  return Promise.resolve(pending).then((args2) => {
24
- if (retryService) {
25
- return retryService.applyRetry(() => fetch(...args2));
30
+ if (retryInterceptor) {
31
+ return retryInterceptor(args2, retryService, context);
32
+ } else {
33
+ if (retryService) {
34
+ return retryService.applyRetry(() => fetch(...args2));
35
+ }
36
+ return fetch(...args2);
26
37
  }
27
- return fetch(...args2);
28
38
  }).then((response) => {
29
39
  return responseInterceptors.reduce(
30
40
  (previousPromise, interceptor) => previousPromise.then((response2) => interceptor(response2, context)),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/v1/fetch.ts","../../src/v1/utils.ts","../../src/v1/jwt-interceptor.ts","../../src/v1/mock-fetch.ts"],"sourcesContent":["import {\n resolvedPromiseLike,\n type NamedService,\n type ServiceDescriptor,\n} from '@conduit-client/utils';\nimport { RetryService } from '@conduit-client/service-retry/v1';\n\nexport type FetchParameters = Parameters<typeof fetch>;\nexport type FetchService = (...args: FetchParameters) => PromiseLike<Response>;\nexport type IFetchService = FetchService;\nexport type FetchServiceDescriptor = ServiceDescriptor<IFetchService, 'fetch', '1.0'>;\nexport type NamedFetchService<Name extends string = 'fetch'> = NamedService<Name, IFetchService>;\nexport type RequestInterceptor<Context = any> = (\n fetchArgs: FetchParameters,\n context?: Context\n) => PromiseLike<FetchParameters>;\nexport type ResponseInterceptor<Context = any> = (\n response: Response,\n context?: Context\n) => PromiseLike<Response>;\nexport type FinallyInterceptor<Context = any> = (context?: Context) => PromiseLike<void> | void;\nexport type Interceptors<Context = any> = {\n createContext?: () => Context;\n request?: RequestInterceptor<Context>[];\n response?: ResponseInterceptor<Context>[];\n finally?: FinallyInterceptor<Context>[];\n};\nexport function buildServiceDescriptor<Context = any>(\n interceptors: Interceptors<Context> = { request: [], response: [], finally: [] },\n retryService?: RetryService<Response>\n): FetchServiceDescriptor {\n return {\n type: 'fetch',\n version: '1.0',\n service: function (...args: FetchParameters) {\n // Create context per request if factory is provided\n const context = interceptors.createContext?.();\n\n const {\n request: requestInterceptors = [],\n response: responseInterceptors = [],\n finally: finallyInterceptors = [],\n } = interceptors;\n\n const pending = requestInterceptors.reduce(\n (previousPromise, interceptor) =>\n previousPromise.then((args) => interceptor(args, context)),\n resolvedPromiseLike(args)\n );\n\n return Promise.resolve(pending)\n .then((args) => {\n if (retryService) {\n return retryService.applyRetry(() => fetch(...args));\n }\n return fetch(...args);\n })\n .then((response) => {\n // Success path - run response interceptors\n return responseInterceptors.reduce(\n (previousPromise, interceptor) =>\n previousPromise.then((response) => interceptor(response, context)),\n resolvedPromiseLike(response)\n );\n })\n .finally(() => {\n // Always run finally interceptors for cleanup\n if (finallyInterceptors.length > 0) {\n // Run all finally interceptors sequentially\n return finallyInterceptors.reduce(\n (previousPromise, interceptor) =>\n previousPromise.then(() => interceptor(context)),\n Promise.resolve()\n );\n }\n });\n },\n };\n}\n","import { FetchParameters } from './fetch';\n\n/**\n * Generic utility function to set any header value in fetch parameters\n * @param headerName - The name of the header to set\n * @param headerValue - The value to set for the header\n * @param fetchParams - The fetch parameters [resource, options]\n * @param options - Additional options\n * @param options.throwOnExisting - If true, throws an error when the header already exists\n * @param options.errorMessage - Custom error message to use when header exists\n * @returns Modified fetch parameters with the header set\n */\nexport function setHeader<T extends string = string>(\n headerName: T,\n headerValue: string,\n [resource, options = {}]: FetchParameters,\n {\n throwOnExisting = false,\n errorMessage = `Unexpected ${headerName} header encountered`,\n }: {\n throwOnExisting?: boolean;\n errorMessage?: string;\n } = {}\n): FetchParameters {\n let hasHeaderBeenSet = false;\n\n // Handle Request instance with Headers\n if (resource instanceof Request && !options?.headers) {\n if (throwOnExisting && resource.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n resource.headers.set(headerName, headerValue);\n hasHeaderBeenSet = true;\n }\n\n // Handle options with Headers instance\n if (options?.headers instanceof Headers) {\n if (throwOnExisting && options.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n options.headers.set(headerName, headerValue);\n } else {\n // Handle options with plain object headers\n if (\n throwOnExisting &&\n options?.headers &&\n Reflect.has(options.headers as any, headerName)\n ) {\n throw new Error(errorMessage);\n }\n // Add the header if it hasn't been set on Request\n if (!hasHeaderBeenSet) {\n options.headers = {\n ...options?.headers,\n [headerName]: headerValue,\n };\n }\n }\n\n return [resource, options];\n}\n","import { resolvedPromiseLike } from '@conduit-client/utils';\nimport type { JwtManager, JwtToken } from '@conduit-client/jwt-manager';\nimport type { FetchParameters } from './fetch';\nimport { setHeader } from './utils';\n\nconst UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE =\n 'Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor';\n\n/**\n * Sets the Authorization header with a JWT token using the generic setHeader utility\n * @param token - The JWT token to set in the Authorization header\n * @param fetchParams - The fetch parameters [resource, options]\n * @returns Modified fetch parameters with the Authorization header set\n */\nexport function setHeaderAuthorization<T, E>(\n { token }: JwtToken<T, E>,\n fetchParams: FetchParameters\n): FetchParameters {\n const authorizationValue = `Bearer ${token}`;\n\n return setHeader('Authorization', authorizationValue, fetchParams, {\n throwOnExisting: true,\n errorMessage: UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE,\n });\n}\n\nexport type JwtRequestModifier = (extraInfo: any, fetchArgs: FetchParameters) => FetchParameters;\n\nexport function buildJwtRequestHeaderInterceptor<ExtraInfo>(\n jwtManager: JwtManager<unknown, ExtraInfo>,\n jwtRequestModifier: JwtRequestModifier = (_e, fetchArgs) => fetchArgs\n) {\n return (args: FetchParameters) => {\n return resolvedPromiseLike(jwtManager.getJwt()).then((token) => {\n const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);\n return token.extraInfo\n ? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization)\n : fetchArgsWithRequestHeaderAuthorization;\n });\n };\n}\n","import { type FetchService } from './fetch';\nimport type { ServiceDescriptor } from '@conduit-client/utils';\n\n// AbortError class that matches the standard AbortError\nclass AbortError extends Error {\n name = 'AbortError';\n constructor(message = 'This operation was aborted') {\n super(message);\n }\n}\n\nexport type MockResponse = {\n status?: number;\n statusText?: string;\n ok?: boolean;\n body?: any;\n delay?: number; // Delay in milliseconds to simulate network latency\n};\n\nexport type MockFetchService = {\n readonly requests: Array<Parameters<FetchService>>;\n readonly availableResponses: number;\n queueResponses: (...newResponses: Array<any>) => void;\n reset: () => void;\n readonly responsesUsed: number;\n} & ((...args: any[]) => Promise<any>);\n\nexport function buildMockFetchService(\n initialResponses: Array<any> = []\n): ServiceDescriptor<MockFetchService, 'fetch', '1.0'> {\n let responses: Array<any> = [...initialResponses];\n\n const networkAdapter = (...args: any[]) => {\n // Capture the full fetch parameters for more realistic testing\n const [url, fetchOptions = {}] = args;\n\n networkAdapter.requests.push(args);\n\n // Immediate abort detection - check if signal is already aborted\n if (fetchOptions.signal?.aborted) {\n return Promise.reject(new AbortError());\n }\n\n const result = responses.shift();\n if (result === undefined) {\n throw new Error('No more mock responses queued');\n }\n networkAdapter.availableResponses = responses.length;\n networkAdapter.responsesUsed++;\n\n if (result instanceof Error) {\n return Promise.reject(result);\n }\n\n // Simulate request delay if specified\n const delay = (result as MockResponse).delay || 0;\n\n // Create a promise that handles both delay simulation and runtime abort\n return new Promise((resolve, reject) => {\n let abortHandler: (() => void) | null = null;\n\n // Set up abort listener for runtime abort detection\n if (fetchOptions.signal) {\n abortHandler = () => {\n reject(new AbortError());\n };\n fetchOptions.signal.addEventListener('abort', abortHandler);\n }\n\n const completeRequest = () => {\n // Clean up abort listener\n if (abortHandler && fetchOptions.signal) {\n fetchOptions.signal.removeEventListener('abort', abortHandler);\n }\n\n // Check one more time if aborted during delay\n if (fetchOptions.signal?.aborted) {\n reject(new AbortError());\n return;\n }\n\n // Return successful response\n resolve({\n ok: result.ok !== undefined ? result.ok : true,\n statusText: result.statusText !== undefined ? result.statusText : 'ok',\n status: result.status !== undefined ? result.status : 200,\n json: () => Promise.resolve(result.body),\n } as Response);\n };\n\n if (delay > 0) {\n setTimeout(completeRequest, delay);\n } else {\n // Always use async behavior to maintain existing test expectations\n // Even without delay, tests expect async behavior for wire adapters\n setTimeout(completeRequest, 0);\n }\n });\n };\n\n networkAdapter.requests = [] as Array<any>;\n networkAdapter.availableResponses = responses.length;\n\n networkAdapter.queueResponses = (newResponses: Array<any>) => {\n responses = responses.concat(newResponses);\n networkAdapter.availableResponses = responses.length;\n };\n\n networkAdapter.fetch = (args: any) => networkAdapter(args);\n\n networkAdapter.reset = () => {\n networkAdapter.requests = [];\n responses = [];\n networkAdapter.availableResponses = 0;\n networkAdapter.responsesUsed = 0;\n };\n\n networkAdapter.responsesUsed = 0;\n return {\n type: 'fetch',\n version: '1.0',\n service: networkAdapter as MockFetchService,\n };\n}\n"],"names":["args","response","_a"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/v1/fetch.ts","../../src/v1/utils.ts","../../src/v1/jwt-interceptor.ts","../../src/v1/mock-fetch.ts"],"sourcesContent":["import {\n resolvedPromiseLike,\n type NamedService,\n type ServiceDescriptor,\n} from '@conduit-client/utils';\nimport { RetryService } from '@conduit-client/service-retry/v1';\n\nexport type FetchParameters = Parameters<typeof fetch>;\nexport type FetchService = (...args: FetchParameters) => PromiseLike<Response>;\nexport type IFetchService = FetchService;\nexport type FetchServiceDescriptor = ServiceDescriptor<IFetchService, 'fetch', '1.0'>;\nexport type NamedFetchService<Name extends string = 'fetch'> = NamedService<Name, IFetchService>;\nexport type RequestInterceptor<Context = any> = (\n fetchArgs: FetchParameters,\n context?: Context\n) => PromiseLike<FetchParameters>;\nexport type RetryInterceptor<Context = any> = (\n fetchArgs: FetchParameters,\n retryService?: RetryService<Response>,\n context?: Context\n) => PromiseLike<Response>;\nexport type ResponseInterceptor<Context = any> = (\n response: Response,\n context?: Context\n) => PromiseLike<Response>;\nexport type FinallyInterceptor<Context = any> = (context?: Context) => PromiseLike<void> | void;\nexport type Interceptors<Context = any> = {\n createContext?: () => Context;\n request?: RequestInterceptor<Context>[];\n retry?: RetryInterceptor<Context>;\n response?: ResponseInterceptor<Context>[];\n finally?: FinallyInterceptor<Context>[];\n};\nexport function buildServiceDescriptor<Context = any>(\n interceptors: Interceptors<Context> = {\n request: [],\n retry: undefined,\n response: [],\n finally: [],\n },\n retryService?: RetryService<Response>\n): FetchServiceDescriptor {\n return {\n type: 'fetch',\n version: '1.0',\n service: function (...args: FetchParameters) {\n // Create context per request if factory is provided\n const context = interceptors.createContext?.();\n\n const {\n request: requestInterceptors = [],\n retry: retryInterceptor = undefined,\n response: responseInterceptors = [],\n finally: finallyInterceptors = [],\n } = interceptors;\n\n const pending = requestInterceptors.reduce(\n (previousPromise, interceptor) =>\n previousPromise.then((args) => interceptor(args, context)),\n resolvedPromiseLike(args)\n );\n\n return Promise.resolve(pending)\n .then((args) => {\n if (retryInterceptor) {\n return retryInterceptor(args, retryService, context);\n } else {\n // default retry logic\n if (retryService) {\n return retryService.applyRetry(() => fetch(...args));\n }\n return fetch(...args);\n }\n })\n .then((response) => {\n // Success path - run response interceptors\n return responseInterceptors.reduce(\n (previousPromise, interceptor) =>\n previousPromise.then((response) => interceptor(response, context)),\n resolvedPromiseLike(response)\n );\n })\n .finally(() => {\n // Always run finally interceptors for cleanup\n if (finallyInterceptors.length > 0) {\n // Run all finally interceptors sequentially\n return finallyInterceptors.reduce(\n (previousPromise, interceptor) =>\n previousPromise.then(() => interceptor(context)),\n Promise.resolve()\n );\n }\n });\n },\n };\n}\n","import { FetchParameters } from './fetch';\n\n/**\n * Generic utility function to set any header value in fetch parameters\n * @param headerName - The name of the header to set\n * @param headerValue - The value to set for the header\n * @param fetchParams - The fetch parameters [resource, options]\n * @param options - Additional options\n * @param options.throwOnExisting - If true, throws an error when the header already exists\n * @param options.errorMessage - Custom error message to use when header exists\n * @returns Modified fetch parameters with the header set\n */\nexport function setHeader<T extends string = string>(\n headerName: T,\n headerValue: string,\n [resource, options = {}]: FetchParameters,\n {\n throwOnExisting = false,\n errorMessage = `Unexpected ${headerName} header encountered`,\n }: {\n throwOnExisting?: boolean;\n errorMessage?: string;\n } = {}\n): FetchParameters {\n let hasHeaderBeenSet = false;\n\n // Handle Request instance with Headers\n if (resource instanceof Request && !options?.headers) {\n if (throwOnExisting && resource.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n resource.headers.set(headerName, headerValue);\n hasHeaderBeenSet = true;\n }\n\n // Handle options with Headers instance\n if (options?.headers instanceof Headers) {\n if (throwOnExisting && options.headers.has(headerName)) {\n throw new Error(errorMessage);\n }\n options.headers.set(headerName, headerValue);\n } else {\n // Handle options with plain object headers\n if (\n throwOnExisting &&\n options?.headers &&\n Reflect.has(options.headers as any, headerName)\n ) {\n throw new Error(errorMessage);\n }\n // Add the header if it hasn't been set on Request\n if (!hasHeaderBeenSet) {\n options.headers = {\n ...options?.headers,\n [headerName]: headerValue,\n };\n }\n }\n\n return [resource, options];\n}\n","import { resolvedPromiseLike } from '@conduit-client/utils';\nimport type { JwtManager, JwtToken } from '@conduit-client/jwt-manager';\nimport type { FetchParameters } from './fetch';\nimport { setHeader } from './utils';\n\nconst UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE =\n 'Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor';\n\n/**\n * Sets the Authorization header with a JWT token using the generic setHeader utility\n * @param token - The JWT token to set in the Authorization header\n * @param fetchParams - The fetch parameters [resource, options]\n * @returns Modified fetch parameters with the Authorization header set\n */\nexport function setHeaderAuthorization<T, E>(\n { token }: JwtToken<T, E>,\n fetchParams: FetchParameters\n): FetchParameters {\n const authorizationValue = `Bearer ${token}`;\n\n return setHeader('Authorization', authorizationValue, fetchParams, {\n throwOnExisting: true,\n errorMessage: UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE,\n });\n}\n\nexport type JwtRequestModifier = (extraInfo: any, fetchArgs: FetchParameters) => FetchParameters;\n\nexport function buildJwtRequestHeaderInterceptor<ExtraInfo>(\n jwtManager: JwtManager<unknown, ExtraInfo>,\n jwtRequestModifier: JwtRequestModifier = (_e, fetchArgs) => fetchArgs\n) {\n return (args: FetchParameters) => {\n return resolvedPromiseLike(jwtManager.getJwt()).then((token) => {\n const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);\n return token.extraInfo\n ? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization)\n : fetchArgsWithRequestHeaderAuthorization;\n });\n };\n}\n","import { type FetchService } from './fetch';\nimport type { ServiceDescriptor } from '@conduit-client/utils';\n\n// AbortError class that matches the standard AbortError\nclass AbortError extends Error {\n name = 'AbortError';\n constructor(message = 'This operation was aborted') {\n super(message);\n }\n}\n\nexport type MockResponse = {\n status?: number;\n statusText?: string;\n ok?: boolean;\n body?: any;\n delay?: number; // Delay in milliseconds to simulate network latency\n};\n\nexport type MockFetchService = {\n readonly requests: Array<Parameters<FetchService>>;\n readonly availableResponses: number;\n queueResponses: (...newResponses: Array<any>) => void;\n reset: () => void;\n readonly responsesUsed: number;\n} & ((...args: any[]) => Promise<any>);\n\nexport function buildMockFetchService(\n initialResponses: Array<any> = []\n): ServiceDescriptor<MockFetchService, 'fetch', '1.0'> {\n let responses: Array<any> = [...initialResponses];\n\n const networkAdapter = (...args: any[]) => {\n // Capture the full fetch parameters for more realistic testing\n const [url, fetchOptions = {}] = args;\n\n networkAdapter.requests.push(args);\n\n // Immediate abort detection - check if signal is already aborted\n if (fetchOptions.signal?.aborted) {\n return Promise.reject(new AbortError());\n }\n\n const result = responses.shift();\n if (result === undefined) {\n throw new Error('No more mock responses queued');\n }\n networkAdapter.availableResponses = responses.length;\n networkAdapter.responsesUsed++;\n\n if (result instanceof Error) {\n return Promise.reject(result);\n }\n\n // Simulate request delay if specified\n const delay = (result as MockResponse).delay || 0;\n\n // Create a promise that handles both delay simulation and runtime abort\n return new Promise((resolve, reject) => {\n let abortHandler: (() => void) | null = null;\n\n // Set up abort listener for runtime abort detection\n if (fetchOptions.signal) {\n abortHandler = () => {\n reject(new AbortError());\n };\n fetchOptions.signal.addEventListener('abort', abortHandler);\n }\n\n const completeRequest = () => {\n // Clean up abort listener\n if (abortHandler && fetchOptions.signal) {\n fetchOptions.signal.removeEventListener('abort', abortHandler);\n }\n\n // Check one more time if aborted during delay\n if (fetchOptions.signal?.aborted) {\n reject(new AbortError());\n return;\n }\n\n // Return successful response\n resolve({\n ok: result.ok !== undefined ? result.ok : true,\n statusText: result.statusText !== undefined ? result.statusText : 'ok',\n status: result.status !== undefined ? result.status : 200,\n json: () => Promise.resolve(result.body),\n } as Response);\n };\n\n if (delay > 0) {\n setTimeout(completeRequest, delay);\n } else {\n // Always use async behavior to maintain existing test expectations\n // Even without delay, tests expect async behavior for wire adapters\n setTimeout(completeRequest, 0);\n }\n });\n };\n\n networkAdapter.requests = [] as Array<any>;\n networkAdapter.availableResponses = responses.length;\n\n networkAdapter.queueResponses = (newResponses: Array<any>) => {\n responses = responses.concat(newResponses);\n networkAdapter.availableResponses = responses.length;\n };\n\n networkAdapter.fetch = (args: any) => networkAdapter(args);\n\n networkAdapter.reset = () => {\n networkAdapter.requests = [];\n responses = [];\n networkAdapter.availableResponses = 0;\n networkAdapter.responsesUsed = 0;\n };\n\n networkAdapter.responsesUsed = 0;\n return {\n type: 'fetch',\n version: '1.0',\n service: networkAdapter as MockFetchService,\n };\n}\n"],"names":["args","response","_a"],"mappings":";;;;;;AAiCO,SAAS,uBACZ,eAAsC;AAAA,EAClC,SAAS,CAAA;AAAA,EACT,OAAO;AAAA,EACP,UAAU,CAAA;AAAA,EACV,SAAS,CAAA;AACb,GACA,cACsB;AACtB,SAAO;AAAA,IACH,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS,YAAa,MAAuB;;AAEzC,YAAM,WAAU,kBAAa,kBAAb;AAEhB,YAAM;AAAA,QACF,SAAS,sBAAsB,CAAA;AAAA,QAC/B,OAAO,mBAAmB;AAAA,QAC1B,UAAU,uBAAuB,CAAA;AAAA,QACjC,SAAS,sBAAsB,CAAA;AAAA,MAAC,IAChC;AAEJ,YAAM,UAAU,oBAAoB;AAAA,QAChC,CAAC,iBAAiB,gBACd,gBAAgB,KAAK,CAACA,UAAS,YAAYA,OAAM,OAAO,CAAC;AAAA,QAC7D,oBAAoB,IAAI;AAAA,MAAA;AAG5B,aAAO,QAAQ,QAAQ,OAAO,EACzB,KAAK,CAACA,UAAS;AACZ,YAAI,kBAAkB;AAClB,iBAAO,iBAAiBA,OAAM,cAAc,OAAO;AAAA,QACvD,OAAO;AAEH,cAAI,cAAc;AACd,mBAAO,aAAa,WAAW,MAAM,MAAM,GAAGA,KAAI,CAAC;AAAA,UACvD;AACA,iBAAO,MAAM,GAAGA,KAAI;AAAA,QACxB;AAAA,MACJ,CAAC,EACA,KAAK,CAAC,aAAa;AAEhB,eAAO,qBAAqB;AAAA,UACxB,CAAC,iBAAiB,gBACd,gBAAgB,KAAK,CAACC,cAAa,YAAYA,WAAU,OAAO,CAAC;AAAA,UACrE,oBAAoB,QAAQ;AAAA,QAAA;AAAA,MAEpC,CAAC,EACA,QAAQ,MAAM;AAEX,YAAI,oBAAoB,SAAS,GAAG;AAEhC,iBAAO,oBAAoB;AAAA,YACvB,CAAC,iBAAiB,gBACd,gBAAgB,KAAK,MAAM,YAAY,OAAO,CAAC;AAAA,YACnD,QAAQ,QAAA;AAAA,UAAQ;AAAA,QAExB;AAAA,MACJ,CAAC;AAAA,IACT;AAAA,EAAA;AAER;ACnFO,SAAS,UACZ,YACA,aACA,CAAC,UAAU,UAAU,CAAA,CAAE,GACvB;AAAA,EACI,kBAAkB;AAAA,EAClB,eAAe,cAAc,UAAU;AAC3C,IAGI,IACW;AACf,MAAI,mBAAmB;AAGvB,MAAI,oBAAoB,WAAW,EAAC,mCAAS,UAAS;AAClD,QAAI,mBAAmB,SAAS,QAAQ,IAAI,UAAU,GAAG;AACrD,YAAM,IAAI,MAAM,YAAY;AAAA,IAChC;AACA,aAAS,QAAQ,IAAI,YAAY,WAAW;AAC5C,uBAAmB;AAAA,EACvB;AAGA,OAAI,mCAAS,oBAAmB,SAAS;AACrC,QAAI,mBAAmB,QAAQ,QAAQ,IAAI,UAAU,GAAG;AACpD,YAAM,IAAI,MAAM,YAAY;AAAA,IAChC;AACA,YAAQ,QAAQ,IAAI,YAAY,WAAW;AAAA,EAC/C,OAAO;AAEH,QACI,oBACA,mCAAS,YACT,QAAQ,IAAI,QAAQ,SAAgB,UAAU,GAChD;AACE,YAAM,IAAI,MAAM,YAAY;AAAA,IAChC;AAEA,QAAI,CAAC,kBAAkB;AACnB,cAAQ,UAAU;AAAA,QACd,GAAG,mCAAS;AAAA,QACZ,CAAC,UAAU,GAAG;AAAA,MAAA;AAAA,IAEtB;AAAA,EACJ;AAEA,SAAO,CAAC,UAAU,OAAO;AAC7B;ACvDA,MAAM,0CACF;AAQG,SAAS,uBACZ,EAAE,MAAA,GACF,aACe;AACf,QAAM,qBAAqB,UAAU,KAAK;AAE1C,SAAO,UAAU,iBAAiB,oBAAoB,aAAa;AAAA,IAC/D,iBAAiB;AAAA,IACjB,cAAc;AAAA,EAAA,CACjB;AACL;AAIO,SAAS,iCACZ,YACA,qBAAyC,CAAC,IAAI,cAAc,WAC9D;AACE,SAAO,CAAC,SAA0B;AAC9B,WAAO,oBAAoB,WAAW,OAAA,CAAQ,EAAE,KAAK,CAAC,UAAU;AAC5D,YAAM,0CAA0C,uBAAuB,OAAO,IAAI;AAClF,aAAO,MAAM,YACP,mBAAmB,MAAM,WAAW,uCAAuC,IAC3E;AAAA,IACV,CAAC;AAAA,EACL;AACJ;ACpCA,MAAM,mBAAmB,MAAM;AAAA,EAE3B,YAAY,UAAU,8BAA8B;AAChD,UAAM,OAAO;AAFjB,SAAA,OAAO;AAAA,EAGP;AACJ;AAkBO,SAAS,sBACZ,mBAA+B,IACoB;AACnD,MAAI,YAAwB,CAAC,GAAG,gBAAgB;AAEhD,QAAM,iBAAiB,IAAI,SAAgB;;AAEvC,UAAM,CAAC,KAAK,eAAe,CAAA,CAAE,IAAI;AAEjC,mBAAe,SAAS,KAAK,IAAI;AAGjC,SAAI,kBAAa,WAAb,mBAAqB,SAAS;AAC9B,aAAO,QAAQ,OAAO,IAAI,YAAY;AAAA,IAC1C;AAEA,UAAM,SAAS,UAAU,MAAA;AACzB,QAAI,WAAW,QAAW;AACtB,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACnD;AACA,mBAAe,qBAAqB,UAAU;AAC9C,mBAAe;AAEf,QAAI,kBAAkB,OAAO;AACzB,aAAO,QAAQ,OAAO,MAAM;AAAA,IAChC;AAGA,UAAM,QAAS,OAAwB,SAAS;AAGhD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,UAAI,eAAoC;AAGxC,UAAI,aAAa,QAAQ;AACrB,uBAAe,MAAM;AACjB,iBAAO,IAAI,YAAY;AAAA,QAC3B;AACA,qBAAa,OAAO,iBAAiB,SAAS,YAAY;AAAA,MAC9D;AAEA,YAAM,kBAAkB,MAAM;;AAE1B,YAAI,gBAAgB,aAAa,QAAQ;AACrC,uBAAa,OAAO,oBAAoB,SAAS,YAAY;AAAA,QACjE;AAGA,aAAIC,MAAA,aAAa,WAAb,gBAAAA,IAAqB,SAAS;AAC9B,iBAAO,IAAI,YAAY;AACvB;AAAA,QACJ;AAGA,gBAAQ;AAAA,UACJ,IAAI,OAAO,OAAO,SAAY,OAAO,KAAK;AAAA,UAC1C,YAAY,OAAO,eAAe,SAAY,OAAO,aAAa;AAAA,UAClE,QAAQ,OAAO,WAAW,SAAY,OAAO,SAAS;AAAA,UACtD,MAAM,MAAM,QAAQ,QAAQ,OAAO,IAAI;AAAA,QAAA,CAC9B;AAAA,MACjB;AAEA,UAAI,QAAQ,GAAG;AACX,mBAAW,iBAAiB,KAAK;AAAA,MACrC,OAAO;AAGH,mBAAW,iBAAiB,CAAC;AAAA,MACjC;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,iBAAe,WAAW,CAAA;AAC1B,iBAAe,qBAAqB,UAAU;AAE9C,iBAAe,iBAAiB,CAAC,iBAA6B;AAC1D,gBAAY,UAAU,OAAO,YAAY;AACzC,mBAAe,qBAAqB,UAAU;AAAA,EAClD;AAEA,iBAAe,QAAQ,CAAC,SAAc,eAAe,IAAI;AAEzD,iBAAe,QAAQ,MAAM;AACzB,mBAAe,WAAW,CAAA;AAC1B,gBAAY,CAAA;AACZ,mBAAe,qBAAqB;AACpC,mBAAe,gBAAgB;AAAA,EACnC;AAEA,iBAAe,gBAAgB;AAC/B,SAAO;AAAA,IACH,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,EAAA;AAEjB;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduit-client/service-fetch-network",
3
- "version": "3.5.0",
3
+ "version": "3.6.2",
4
4
  "private": false,
5
5
  "description": "Luvio Network Service definition",
6
6
  "type": "module",
@@ -31,9 +31,9 @@
31
31
  "watch": "npm run build --watch"
32
32
  },
33
33
  "dependencies": {
34
- "@conduit-client/jwt-manager": "3.5.0",
35
- "@conduit-client/service-retry": "3.5.0",
36
- "@conduit-client/utils": "3.5.0"
34
+ "@conduit-client/jwt-manager": "3.6.2",
35
+ "@conduit-client/service-retry": "3.6.2",
36
+ "@conduit-client/utils": "3.6.2"
37
37
  },
38
38
  "volta": {
39
39
  "extends": "../../../../package.json"