From b9021527043405dde0de3044c5abf276e83e6848 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Fri, 29 Nov 2024 14:53:23 -0500 Subject: [PATCH 01/13] Add hash based paths to response saver --- .../lib/services/response-saver.service.ts | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index f27ccbf21b9..9f33e669320 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -1,9 +1,18 @@ import fs from 'node:fs'; import path from 'node:path'; +import crypto from 'node:crypto'; import type { AxiosResponse } from 'axios'; import type { Connection } from '@nangohq/shared'; import type { Metadata } from '@nangohq/types'; +const FILTER_HEADERS = ['authorization', 'user-agent', 'nango-proxy-user-agent', 'accept-encoding', 'retries', 'host']; + +interface CachedRequest { + requestIdentityHash: string; + requestIdentity: unknown[]; + data: unknown; +} + export function ensureDirectoryExists(directoryName: string): void { if (!fs.existsSync(directoryName)) { fs.mkdirSync(directoryName, { recursive: true }); @@ -77,17 +86,33 @@ export function onAxiosRequestFulfilled({ const [pathname, params] = response.request.path.split('?'); const strippedPath = pathname.replace('/', ''); - let concatenateIfExists = false; + const requestIdentity = [ + ['method', method], + ['pathname', pathname], + ['params', params] + ]; - if (params && params.includes('page')) { - concatenateIfExists = true; + const headers = response.request.getHeaders(); + for (const [key, value] of Object.entries(headers)) { + if (FILTER_HEADERS.includes(key)) { + continue; + } + requestIdentity.push([`headers.${key}`, value]); } - saveResponse({ + requestIdentity.sort((a, b) => a[0].localeCompare(b[0])); + + const requestHash = crypto.createHash('sha1').update(JSON.stringify(requestIdentity)).digest('hex'); + + saveResponse({ directoryName, - data: response.data, - customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}.json`, - concatenateIfExists + data: { + requestIdentityHash: requestHash, + requestIdentity, + response: response.data + }, + customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestHash}.json`, + concatenateIfExists: false }); return response; From 2f0c22fbbce2d5acbae5ccb5b120d553919dcdc8 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Mon, 2 Dec 2024 12:26:32 -0500 Subject: [PATCH 02/13] Got responseSaver handling request body --- .../lib/services/response-saver.service.ts | 91 ++++++++++++++----- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 9f33e669320..40cb455e360 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -1,7 +1,7 @@ import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; -import type { AxiosResponse } from 'axios'; +import type { AxiosRequestConfig, AxiosResponse } from 'axios'; import type { Connection } from '@nangohq/shared'; import type { Metadata } from '@nangohq/types'; @@ -13,6 +13,11 @@ interface CachedRequest { data: unknown; } +interface ConfigIdentity { + requestIdentityHash: string; + requestIdentity: unknown[]; +} + export function ensureDirectoryExists(directoryName: string): void { if (!fs.existsSync(directoryName)) { fs.mkdirSync(directoryName, { recursive: true }); @@ -83,37 +88,79 @@ export function onAxiosRequestFulfilled({ return response; } - const [pathname, params] = response.request.path.split('?'); + const [pathname] = response.request.path.split('?'); const strippedPath = pathname.replace('/', ''); + const requestIdentity = computeConfigIdentity(response.config); + + saveResponse({ + directoryName, + data: { + ...requestIdentity, + data: response.data + }, + customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestIdentity.requestIdentityHash}.json`, + concatenateIfExists: false + }); + + return response; +} + +function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { + const method = config.method?.toLowerCase() || 'get'; + const requestIdentity = [ ['method', method], - ['pathname', pathname], - ['params', params] + ['url', config.url], + ['params', config.params] ]; - const headers = response.request.getHeaders(); - for (const [key, value] of Object.entries(headers)) { - if (FILTER_HEADERS.includes(key)) { - continue; + const dataIdentity = computeDataIdentity(config); + if (dataIdentity) { + requestIdentity.push(['data', dataIdentity]); + } + + if (config.headers !== undefined) { + // headers are always an object, not an AxiosHeaders type, because of + // how the proxy function works + for (const [key, value] of Object.entries(config.headers)) { + if (FILTER_HEADERS.includes(key)) { + continue; + } + requestIdentity.push([`headers.${key}`, value]); } - requestIdentity.push([`headers.${key}`, value]); } - requestIdentity.sort((a, b) => a[0].localeCompare(b[0])); + // sort by key so we have a consistent hash + requestIdentity.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)); - const requestHash = crypto.createHash('sha1').update(JSON.stringify(requestIdentity)).digest('hex'); + const requestIdentityHash = crypto.createHash('sha1').update(JSON.stringify(requestIdentity)).digest('hex'); - saveResponse({ - directoryName, - data: { - requestIdentityHash: requestHash, - requestIdentity, - response: response.data - }, - customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestHash}.json`, - concatenateIfExists: false - }); + return { + requestIdentityHash, + requestIdentity + }; +} - return response; +function computeDataIdentity(config: AxiosRequestConfig): string | undefined { + const data = config.data; + + if (!data) { + return undefined; + } + + let dataString = ''; + if (typeof data === 'string') { + dataString = data; + } else if (Buffer.isBuffer(data)) { + dataString = data.toString('base64'); + } else { + dataString = JSON.stringify(data); + } + + if (dataString.length > 1000) { + return 'sha1:' + crypto.createHash('sha1').update(dataString).digest('hex'); + } else { + return dataString; + } } From 4a49bf7c3c4a20dbd486980e9778fa8ba5dfd139 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Mon, 2 Dec 2024 14:42:03 -0500 Subject: [PATCH 03/13] Handle error when unable to compute identity for request body --- packages/cli/lib/services/response-saver.service.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 40cb455e360..492c1d72024 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -155,7 +155,15 @@ function computeDataIdentity(config: AxiosRequestConfig): string | undefined { } else if (Buffer.isBuffer(data)) { dataString = data.toString('base64'); } else { - dataString = JSON.stringify(data); + try { + dataString = JSON.stringify(data); + } catch (e) { + if (e instanceof Error) { + throw new Error(`Unable to compute request identity: ${e.message}`); + } else { + throw new Error('Unable to compute request identity'); + } + } } if (dataString.length > 1000) { From ceed1259d4b21f2682f2a978c4ff5e24b2175bb6 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Mon, 2 Dec 2024 14:50:40 -0500 Subject: [PATCH 04/13] Clean up headers --- packages/cli/lib/services/response-saver.service.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 492c1d72024..244f7bb26f6 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -121,14 +121,8 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { } if (config.headers !== undefined) { - // headers are always an object, not an AxiosHeaders type, because of - // how the proxy function works - for (const [key, value] of Object.entries(config.headers)) { - if (FILTER_HEADERS.includes(key)) { - continue; - } - requestIdentity.push([`headers.${key}`, value]); - } + const filteredHeaders = Object.fromEntries(Object.entries(config.headers).filter(([key]) => !FILTER_HEADERS.includes(key))); + requestIdentity.push([`headers`, filteredHeaders]); } // sort by key so we have a consistent hash From 1e88a7ba549f38d21983d43762a8e14e95d6cb15 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Tue, 3 Dec 2024 10:15:14 -0500 Subject: [PATCH 05/13] Use arrays for all nested request values It's cleaner for ordering --- .../cli/lib/services/response-saver.service.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 244f7bb26f6..26673cc7e3e 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -10,7 +10,7 @@ const FILTER_HEADERS = ['authorization', 'user-agent', 'nango-proxy-user-agent', interface CachedRequest { requestIdentityHash: string; requestIdentity: unknown[]; - data: unknown; + response: unknown; } interface ConfigIdentity { @@ -97,7 +97,7 @@ export function onAxiosRequestFulfilled({ directoryName, data: { ...requestIdentity, - data: response.data + response: response.data }, customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestIdentity.requestIdentityHash}.json`, concatenateIfExists: false @@ -108,11 +108,12 @@ export function onAxiosRequestFulfilled({ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { const method = config.method?.toLowerCase() || 'get'; + const params = sortEntries(Object.entries(config.params || {})); - const requestIdentity = [ + const requestIdentity: [string, unknown][] = [ ['method', method], ['url', config.url], - ['params', config.params] + ['params', params] ]; const dataIdentity = computeDataIdentity(config); @@ -121,12 +122,13 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { } if (config.headers !== undefined) { - const filteredHeaders = Object.fromEntries(Object.entries(config.headers).filter(([key]) => !FILTER_HEADERS.includes(key))); + const filteredHeaders = Object.entries(config.headers).filter(([key]) => !FILTER_HEADERS.includes(key)); + sortEntries(filteredHeaders); requestIdentity.push([`headers`, filteredHeaders]); } // sort by key so we have a consistent hash - requestIdentity.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)); + sortEntries(requestIdentity); const requestIdentityHash = crypto.createHash('sha1').update(JSON.stringify(requestIdentity)).digest('hex'); @@ -136,6 +138,10 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { }; } +function sortEntries(entries: [string, unknown][]): [string, unknown][] { + return entries.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)); +} + function computeDataIdentity(config: AxiosRequestConfig): string | undefined { const data = config.data; From 33e6ee653970f126d2a5adfebd93490230aa3859 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Tue, 3 Dec 2024 10:16:43 -0500 Subject: [PATCH 06/13] Remove concatenate param --- .../lib/services/response-saver.service.ts | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 26673cc7e3e..5519dc1d609 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -24,29 +24,12 @@ export function ensureDirectoryExists(directoryName: string): void { } } -function saveResponse({ - directoryName, - data, - customFilePath, - concatenateIfExists -}: { - directoryName: string; - data: T | T[]; - customFilePath: string; - concatenateIfExists: boolean; -}): void { +function saveResponse({ directoryName, data, customFilePath }: { directoryName: string; data: T | T[]; customFilePath: string }): void { ensureDirectoryExists(`${directoryName}/mocks`); const filePath = path.join(directoryName, customFilePath); ensureDirectoryExists(path.dirname(filePath)); - if (fs.existsSync(filePath)) { - const existingData = JSON.parse(fs.readFileSync(filePath, 'utf8')); - if (concatenateIfExists && Array.isArray(existingData) && Array.isArray(data)) { - data = data.concat(existingData); - } - } - fs.writeFileSync(filePath, JSON.stringify(data, null, 2)); } @@ -74,15 +57,13 @@ export function onAxiosRequestFulfilled({ saveResponse>({ directoryName, data: { metadata: connection.metadata as Metadata, connection_config: connection.connection_config }, - customFilePath: 'mocks/nango/getConnection.json', - concatenateIfExists: false + customFilePath: 'mocks/nango/getConnection.json' }); saveResponse({ directoryName, data: connection.metadata as Metadata, - customFilePath: 'mocks/nango/getMetadata.json', - concatenateIfExists: false + customFilePath: 'mocks/nango/getMetadata.json' }); return response; @@ -99,8 +80,7 @@ export function onAxiosRequestFulfilled({ ...requestIdentity, response: response.data }, - customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestIdentity.requestIdentityHash}.json`, - concatenateIfExists: false + customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestIdentity.requestIdentityHash}.json` }); return response; From f8504ac2f9f4e31d7e81760dcac04168662ceec4 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Tue, 3 Dec 2024 10:18:31 -0500 Subject: [PATCH 07/13] Fix header filtering --- packages/cli/lib/services/response-saver.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 5519dc1d609..50671d5195e 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -102,7 +102,7 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { } if (config.headers !== undefined) { - const filteredHeaders = Object.entries(config.headers).filter(([key]) => !FILTER_HEADERS.includes(key)); + const filteredHeaders = Object.entries(config.headers).filter(([key]) => !FILTER_HEADERS.includes(key.toLowerCase())); sortEntries(filteredHeaders); requestIdentity.push([`headers`, filteredHeaders]); } From 50c99d8965e3115795135e608e32e344a6651a9a Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Tue, 3 Dec 2024 15:40:03 -0500 Subject: [PATCH 08/13] Serialize endpoint instead of url --- .../lib/services/response-saver.service.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 50671d5195e..6c074f3e797 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -7,15 +7,17 @@ import type { Metadata } from '@nangohq/types'; const FILTER_HEADERS = ['authorization', 'user-agent', 'nango-proxy-user-agent', 'accept-encoding', 'retries', 'host']; -interface CachedRequest { +interface ConfigIdentity { + method: string; + endpoint: string; requestIdentityHash: string; requestIdentity: unknown[]; - response: unknown; } -interface ConfigIdentity { +interface CachedRequest { requestIdentityHash: string; requestIdentity: unknown[]; + response: unknown; } export function ensureDirectoryExists(directoryName: string): void { @@ -48,7 +50,6 @@ export function onAxiosRequestFulfilled({ return response; } const directoryName = `${process.env['NANGO_MOCKS_RESPONSE_DIRECTORY'] ?? ''}${providerConfigKey}`; - const method = response.config.method?.toLowerCase() || 'get'; if (response.request.path.includes(`/connection/${connectionId}?provider_config_key=${providerConfigKey}`)) { const connection = response.data as Connection; @@ -69,9 +70,6 @@ export function onAxiosRequestFulfilled({ return response; } - const [pathname] = response.request.path.split('?'); - const strippedPath = pathname.replace('/', ''); - const requestIdentity = computeConfigIdentity(response.config); saveResponse({ @@ -80,7 +78,7 @@ export function onAxiosRequestFulfilled({ ...requestIdentity, response: response.data }, - customFilePath: `mocks/nango/${method}/${strippedPath}/${syncName}/${requestIdentity.requestIdentityHash}.json` + customFilePath: `mocks/nango/${requestIdentity.method}/${requestIdentity.endpoint}/${syncName}/${requestIdentity.requestIdentityHash}.json` }); return response; @@ -90,9 +88,12 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { const method = config.method?.toLowerCase() || 'get'; const params = sortEntries(Object.entries(config.params || {})); + const url = new URL(config.url!); + const endpoint = url.pathname.replace(/^\/proxy\//, ''); + const requestIdentity: [string, unknown][] = [ ['method', method], - ['url', config.url], + ['endpoint', endpoint], ['params', params] ]; @@ -113,6 +114,8 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { const requestIdentityHash = crypto.createHash('sha1').update(JSON.stringify(requestIdentity)).digest('hex'); return { + method, + endpoint, requestIdentityHash, requestIdentity }; From 946e9daebf22ebd5e6242f3f691b34979674940e Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Tue, 3 Dec 2024 15:40:47 -0500 Subject: [PATCH 09/13] Remove some more headers --- packages/cli/lib/services/response-saver.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 6c074f3e797..e7583557adf 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -5,7 +5,7 @@ import type { AxiosRequestConfig, AxiosResponse } from 'axios'; import type { Connection } from '@nangohq/shared'; import type { Metadata } from '@nangohq/types'; -const FILTER_HEADERS = ['authorization', 'user-agent', 'nango-proxy-user-agent', 'accept-encoding', 'retries', 'host']; +const FILTER_HEADERS = ['authorization', 'user-agent', 'nango-proxy-user-agent', 'accept-encoding', 'retries', 'host', 'connection-id', 'provider-config-key']; interface ConfigIdentity { method: string; From 7a5a63f34bf71e02b36aa33cafb79777ac60557a Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Wed, 4 Dec 2024 08:41:30 -0500 Subject: [PATCH 10/13] Tweak headers some more Also fix path for dry-run saving --- .../lib/services/response-saver.service.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index e7583557adf..b547f0a3b31 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -5,7 +5,22 @@ import type { AxiosRequestConfig, AxiosResponse } from 'axios'; import type { Connection } from '@nangohq/shared'; import type { Metadata } from '@nangohq/types'; -const FILTER_HEADERS = ['authorization', 'user-agent', 'nango-proxy-user-agent', 'accept-encoding', 'retries', 'host', 'connection-id', 'provider-config-key']; +const FILTER_HEADERS = [ + 'authorization', + 'user-agent', + 'nango-proxy-user-agent', + 'accept-encoding', + 'retries', + 'host', + 'connection-id', + 'provider-config-key', + 'nango-is-sync', + 'nango-is-dry-run', + 'nango-activity-log-id', + 'content-type', + 'accept', + 'base-url-override' +]; interface ConfigIdentity { method: string; @@ -78,7 +93,7 @@ export function onAxiosRequestFulfilled({ ...requestIdentity, response: response.data }, - customFilePath: `mocks/nango/${requestIdentity.method}/${requestIdentity.endpoint}/${syncName}/${requestIdentity.requestIdentityHash}.json` + customFilePath: `mocks/nango/${requestIdentity.method}/proxy/${requestIdentity.endpoint}/${syncName}/${requestIdentity.requestIdentityHash}.json` }); return response; From ccde360f00b7aee4a18f13349031428738f2e617 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Wed, 4 Dec 2024 10:43:29 -0500 Subject: [PATCH 11/13] Go ahead and save response status and headers --- packages/cli/lib/services/response-saver.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index b547f0a3b31..77cafd99b4c 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -33,6 +33,8 @@ interface CachedRequest { requestIdentityHash: string; requestIdentity: unknown[]; response: unknown; + status: number; + headers: Record; } export function ensureDirectoryExists(directoryName: string): void { @@ -91,7 +93,9 @@ export function onAxiosRequestFulfilled({ directoryName, data: { ...requestIdentity, - response: response.data + response: response.data, + status: response.status, + headers: response.headers as Record }, customFilePath: `mocks/nango/${requestIdentity.method}/proxy/${requestIdentity.endpoint}/${syncName}/${requestIdentity.requestIdentityHash}.json` }); From 9f30ffd42d0465915bd752a706723cce3d0a3a3a Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Wed, 4 Dec 2024 11:36:43 -0500 Subject: [PATCH 12/13] Use object instead of array for request identity --- .../lib/services/response-saver.service.ts | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index 77cafd99b4c..c7f98762089 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -26,12 +26,20 @@ interface ConfigIdentity { method: string; endpoint: string; requestIdentityHash: string; - requestIdentity: unknown[]; + requestIdentity: RequestIdentity; +} + +interface RequestIdentity { + method: string; + endpoint: string; + params: [string, unknown][]; + headers: [string, unknown][]; + data?: unknown; } interface CachedRequest { requestIdentityHash: string; - requestIdentity: unknown[]; + requestIdentity: RequestIdentity; response: unknown; status: number; headers: Record; @@ -110,26 +118,23 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { const url = new URL(config.url!); const endpoint = url.pathname.replace(/^\/proxy\//, ''); - const requestIdentity: [string, unknown][] = [ - ['method', method], - ['endpoint', endpoint], - ['params', params] - ]; - const dataIdentity = computeDataIdentity(config); - if (dataIdentity) { - requestIdentity.push(['data', dataIdentity]); - } + let headers: [string, string][] = []; if (config.headers !== undefined) { const filteredHeaders = Object.entries(config.headers).filter(([key]) => !FILTER_HEADERS.includes(key.toLowerCase())); sortEntries(filteredHeaders); - requestIdentity.push([`headers`, filteredHeaders]); + headers = filteredHeaders; } - // sort by key so we have a consistent hash - sortEntries(requestIdentity); - + // order is important to the request hash + const requestIdentity = { + method, + endpoint, + params, + headers, + data: dataIdentity + }; const requestIdentityHash = crypto.createHash('sha1').update(JSON.stringify(requestIdentity)).digest('hex'); return { From 0d349778dd432742e6136d436013b75da62f35f3 Mon Sep 17 00:00:00 2001 From: nalanj <5594+nalanj@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:20:27 -0500 Subject: [PATCH 13/13] Update packages/cli/lib/services/response-saver.service.ts Co-authored-by: Samuel Bodin <1637651+bodinsamuel@users.noreply.github.com> --- packages/cli/lib/services/response-saver.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/lib/services/response-saver.service.ts b/packages/cli/lib/services/response-saver.service.ts index c7f98762089..3b740ca2bbe 100644 --- a/packages/cli/lib/services/response-saver.service.ts +++ b/packages/cli/lib/services/response-saver.service.ts @@ -128,7 +128,7 @@ function computeConfigIdentity(config: AxiosRequestConfig): ConfigIdentity { } // order is important to the request hash - const requestIdentity = { + const requestIdentity: RequestIdentity = { method, endpoint, params,