Skip to content

Commit

Permalink
Support for proxying requests to proxy server
Browse files Browse the repository at this point in the history
  • Loading branch information
zbenamram committed Aug 12, 2024
1 parent ccbe2e5 commit ae34349
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 32 deletions.
19 changes: 13 additions & 6 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const defaultConfig = {
timeout: 5000,
eventSinkEndpoint: '/events',
errorSinkEndpoint: '/errors',
remoteConfigFetchEndpoint: '/config',
remoteConfigFetchEndpoint: '/v2/config',
telemetryEndpoint: '/telemetry',
useRemoteConfig: true,
useTelemetry: true,
Expand All @@ -22,7 +22,7 @@ const defaultConfig = {

// After the close command is sent, wait for this many milliseconds before
// exiting. This gives any hanging responses a chance to return.
waitAfterClose: 1000,
waitAfterClose: 1000
};

const errors = {
Expand All @@ -39,7 +39,7 @@ const errors = {
NO_CLIENT_ID:
'No Client ID Provided, set SUPERGOOD_CLIENT_ID or pass it as an argument',
NO_CLIENT_SECRET:
'No Client Secret Provided, set SUPERGOOD_CLIENT_SECRET or pass it as an argument',
'No Client Secret Provided, set SUPERGOOD_CLIENT_SECRET or pass it as an argument'
};

const SensitiveKeyActions = {
Expand All @@ -50,7 +50,7 @@ const SensitiveKeyActions = {
const EndpointActions = {
ALLOW: 'Allow',
IGNORE: 'Ignore'
}
};

const TestErrorPath = '/api/supergood-test-error';
const LocalClientId = 'local-client-id';
Expand All @@ -59,7 +59,13 @@ const LocalClientSecret = 'local-client-secret';
const ContentType = {
Json: 'application/json',
Text: 'text/plain',
EventStream: 'text/event-stream',
EventStream: 'text/event-stream'
};

const SupergoodProxyHeaders = {
upstreamHeader: 'X-Supergood-Upstream',
clientId: 'X-Supergood-ClientID',
clientSecret: 'X-Supergood-ClientSecret'
};

export {
Expand All @@ -70,5 +76,6 @@ export {
LocalClientSecret,
SensitiveKeyActions,
EndpointActions,
ContentType
ContentType,
SupergoodProxyHeaders
};
32 changes: 29 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
TestErrorPath,
LocalClientId,
LocalClientSecret,
ContentType
ContentType,
SupergoodProxyHeaders
} from './constants';
import onExit from 'signal-exit';
import { NodeRequestInterceptor } from './interceptor/NodeRequestInterceptor';
Expand All @@ -44,6 +45,7 @@ const Supergood = () => {
let errorSinkUrl: string;
let remoteConfigFetchUrl: string;
let telemetryUrl: string;
let proxyUrl: URL;

let headerOptions: HeaderOptionType;
let supergoodConfig: ConfigType;
Expand Down Expand Up @@ -88,7 +90,9 @@ const Supergood = () => {
},
baseUrl = process.env.SUPERGOOD_BASE_URL || 'https://api.supergood.ai',
baseTelemetryUrl = process.env.SUPERGOOD_TELEMETRY_BASE_URL ||
'https://telemetry.supergood.ai'
'https://telemetry.supergood.ai',
baseProxyURL = process.env.SUPERGOOD_PROXY_BASE_URL ||
'https://proxy.supergood.ai'
): TConfig extends { useRemoteConfig: false } ? void : Promise<void> => {
if (!clientId) throw new Error(errors.NO_CLIENT_ID);
if (!clientSecret) throw new Error(errors.NO_CLIENT_SECRET);
Expand Down Expand Up @@ -139,6 +143,7 @@ const Supergood = () => {

telemetryUrl = `${baseTelemetryUrl}${supergoodConfig.telemetryEndpoint}`;
errorSinkUrl = `${baseTelemetryUrl}${supergoodConfig.errorSinkEndpoint}`;
proxyUrl = new URL(baseProxyURL);

headerOptions = getHeaderOptions(
clientId,
Expand All @@ -153,9 +158,12 @@ const Supergood = () => {
remoteConfigFetchUrl,
headerOptions
);
const { endpointConfig, proxyConfig } =
processRemoteConfig(remoteConfigPayload);
supergoodConfig = {
...supergoodConfig,
remoteConfig: processRemoteConfig(remoteConfigPayload)
remoteConfig: endpointConfig,
proxyConfig: proxyConfig?.vendorCredentialConfig
};
} catch (e) {
log.error(
Expand Down Expand Up @@ -204,6 +212,22 @@ const Supergood = () => {
if (endpointConfig?.ignored) return;

cacheRequest(requestData, baseUrl);
const proxyConfigForHost =
supergoodConfig?.proxyConfig[request.url.host];
if (proxyConfigForHost?.enabled) {
request.headers.set(
SupergoodProxyHeaders.upstreamHeader,
request.url.protocol + '//' + request.url.host
);
request.headers.set(SupergoodProxyHeaders.clientId, clientId);
request.headers.set(
SupergoodProxyHeaders.clientSecret,
clientSecret
);
request.url.host = proxyUrl.host;
request.url.hostname = proxyUrl.hostname;
request.url.protocol = proxyUrl.protocol;
}
} catch (e) {
log.error(
errors.CACHING_REQUEST,
Expand Down Expand Up @@ -580,6 +604,8 @@ const Supergood = () => {
);
};

const modifyRequestForProxy = () => {};

const stopCapture = () => {
supergoodAsyncLocalStorage.disable();
};
Expand Down
13 changes: 13 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface ConfigType {
telemetryEndpoint: string; // Defaults to {baseUrl}/telemetry if not provided
waitAfterClose: number;
remoteConfig: RemoteConfigType;
proxyConfig: { [key: string]: { enabled: boolean } };
useRemoteConfig: boolean;
useTelemetry: boolean;
logRequestHeaders: boolean;
Expand Down Expand Up @@ -139,6 +140,17 @@ interface LoggerType {
debug: (message: string, payload?: any) => void;
}

type RemoteConfigPayloadTypeV2 = {
endpointConfig: RemoteConfigPayloadType;
proxyConfig: RemoteConfigProxyType;
};

type RemoteConfigProxyType = {
vendorCredentialConfig: {
[key: string]: { enabled: boolean };
};
};

type RemoteConfigPayloadType = Array<{
domain: string;
endpoints: Array<{
Expand Down Expand Up @@ -178,6 +190,7 @@ export type {
RemoteConfigType,
EndpointConfigType,
RemoteConfigPayloadType,
RemoteConfigPayloadTypeV2,
MetadataType,
TelemetryType,
SupergoodContext,
Expand Down
56 changes: 33 additions & 23 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ResponseType,
EventRequestType,
ErrorPayloadType,
RemoteConfigPayloadType,
RemoteConfigPayloadTypeV2,
RemoteConfigType,
EndpointConfigType,
SensitiveKeyMetadata,
Expand Down Expand Up @@ -579,28 +579,38 @@ const get = (
});
};

const processRemoteConfig = (remoteConfigPayload: RemoteConfigPayloadType) => {
return (remoteConfigPayload || []).reduce((remoteConfig, domainConfig) => {
const { domain, endpoints } = domainConfig;
const endpointConfig = endpoints.reduce((endpointConfig, endpoint) => {
const { matchingRegex, endpointConfiguration, method } = endpoint;
const { regex, location } = matchingRegex;
const { action, sensitiveKeys } = endpointConfiguration;
endpointConfig[regex] = {
location,
regex,
method,
ignored: action === EndpointActions.IGNORE,
sensitiveKeys: (sensitiveKeys || []).map((key) => ({
keyPath: key.keyPath,
action: key.action
}))
};
return endpointConfig;
}, {} as { [endpointName: string]: EndpointConfigType });
remoteConfig[domain] = endpointConfig;
return remoteConfig;
}, {} as RemoteConfigType);
const processRemoteConfig = (
remoteConfigPayload: RemoteConfigPayloadTypeV2
) => {
const endpointConfig = (remoteConfigPayload?.endpointConfig || []).reduce(
(remoteConfig, domainConfig) => {
const { domain, endpoints } = domainConfig;
const endpointConfig = endpoints.reduce((endpointConfig, endpoint) => {
const { matchingRegex, endpointConfiguration, method } = endpoint;
const { regex, location } = matchingRegex;
const { action, sensitiveKeys } = endpointConfiguration;
endpointConfig[regex] = {
location,
regex,
method,
ignored: action === EndpointActions.IGNORE,
sensitiveKeys: (sensitiveKeys || []).map((key) => ({
keyPath: key.keyPath,
action: key.action
}))
};
return endpointConfig;
}, {} as { [endpointName: string]: EndpointConfigType });
remoteConfig[domain] = endpointConfig;
return remoteConfig;
},
{} as RemoteConfigType
);

return {
endpointConfig,
proxyConfig: remoteConfigPayload?.proxyConfig || new Map()
};
};

const sleep = (ms: number) => {
Expand Down

0 comments on commit ae34349

Please sign in to comment.