Compare commits
2 Commits
feat/clien
...
feat/bedro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66dc48c8a0 | ||
|
|
f4facb7d35 |
@@ -45,7 +45,9 @@ module.exports = {
|
||||
EModelEndpoint.azureAssistants,
|
||||
),
|
||||
[EModelEndpoint.bedrock]: generateConfig(
|
||||
process.env.BEDROCK_AWS_SECRET_ACCESS_KEY ?? process.env.BEDROCK_AWS_DEFAULT_REGION,
|
||||
process.env.BEDROCK_AWS_SECRET_ACCESS_KEY ??
|
||||
process.env.BEDROCK_AWS_BEARER_TOKEN ??
|
||||
process.env.BEDROCK_AWS_DEFAULT_REGION,
|
||||
),
|
||||
/* key will be part of separate config */
|
||||
[EModelEndpoint.agents]: generateConfig('true', undefined, EModelEndpoint.agents),
|
||||
|
||||
@@ -74,6 +74,23 @@ async function getEndpointsConfig(req) {
|
||||
};
|
||||
}
|
||||
|
||||
// Add individual credential flags for Bedrock
|
||||
if (mergedConfig[EModelEndpoint.bedrock]) {
|
||||
const userProvideAccessKeyId = process.env.BEDROCK_AWS_ACCESS_KEY_ID === 'user_provided';
|
||||
const userProvideSecretAccessKey =
|
||||
process.env.BEDROCK_AWS_SECRET_ACCESS_KEY === 'user_provided';
|
||||
const userProvideSessionToken = process.env.BEDROCK_AWS_SESSION_TOKEN === 'user_provided';
|
||||
const userProvideBearerToken = process.env.BEDROCK_AWS_BEARER_TOKEN === 'user_provided';
|
||||
|
||||
mergedConfig[EModelEndpoint.bedrock] = {
|
||||
...mergedConfig[EModelEndpoint.bedrock],
|
||||
userProvideAccessKeyId,
|
||||
userProvideSecretAccessKey,
|
||||
userProvideSessionToken,
|
||||
userProvideBearerToken,
|
||||
};
|
||||
}
|
||||
|
||||
const endpointsConfig = orderEndpointsConfig(mergedConfig);
|
||||
|
||||
await cache.set(CacheKeys.ENDPOINT_CONFIG, endpointsConfig);
|
||||
|
||||
@@ -8,27 +8,43 @@ const {
|
||||
bedrockOutputParser,
|
||||
removeNullishValues,
|
||||
} = require('librechat-data-provider');
|
||||
const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService');
|
||||
const { getUserKeyValues, checkUserKeyExpiry } = require('~/server/services/UserService');
|
||||
|
||||
const getOptions = async ({ req, overrideModel, endpointOption }) => {
|
||||
const {
|
||||
BEDROCK_AWS_SECRET_ACCESS_KEY,
|
||||
BEDROCK_AWS_ACCESS_KEY_ID,
|
||||
BEDROCK_AWS_SESSION_TOKEN,
|
||||
BEDROCK_AWS_BEARER_TOKEN,
|
||||
BEDROCK_REVERSE_PROXY,
|
||||
BEDROCK_AWS_DEFAULT_REGION,
|
||||
PROXY,
|
||||
} = process.env;
|
||||
const expiresAt = req.body.key;
|
||||
const isUserProvided = BEDROCK_AWS_SECRET_ACCESS_KEY === AuthType.USER_PROVIDED;
|
||||
const isUserProvided =
|
||||
BEDROCK_AWS_SECRET_ACCESS_KEY === AuthType.USER_PROVIDED ||
|
||||
BEDROCK_AWS_BEARER_TOKEN === AuthType.USER_PROVIDED;
|
||||
|
||||
let credentials = isUserProvided
|
||||
? await getUserKey({ userId: req.user.id, name: EModelEndpoint.bedrock })
|
||||
: {
|
||||
accessKeyId: BEDROCK_AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: BEDROCK_AWS_SECRET_ACCESS_KEY,
|
||||
...(BEDROCK_AWS_SESSION_TOKEN && { sessionToken: BEDROCK_AWS_SESSION_TOKEN }),
|
||||
};
|
||||
let userValues = null;
|
||||
if (isUserProvided) {
|
||||
if (expiresAt) {
|
||||
checkUserKeyExpiry(expiresAt, EModelEndpoint.bedrock);
|
||||
}
|
||||
userValues = await getUserKeyValues({ userId: req.user.id, name: EModelEndpoint.bedrock });
|
||||
}
|
||||
|
||||
let credentials;
|
||||
if (isUserProvided) {
|
||||
credentials = JSON.parse(userValues.apiKey);
|
||||
} else if (BEDROCK_AWS_BEARER_TOKEN) {
|
||||
credentials = { bearerToken: BEDROCK_AWS_BEARER_TOKEN };
|
||||
} else {
|
||||
credentials = {
|
||||
accessKeyId: BEDROCK_AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: BEDROCK_AWS_SECRET_ACCESS_KEY,
|
||||
...(BEDROCK_AWS_SESSION_TOKEN && { sessionToken: BEDROCK_AWS_SESSION_TOKEN }),
|
||||
};
|
||||
}
|
||||
|
||||
if (!credentials) {
|
||||
throw new Error('Bedrock credentials not provided. Please provide them again.');
|
||||
@@ -36,6 +52,7 @@ const getOptions = async ({ req, overrideModel, endpointOption }) => {
|
||||
|
||||
if (
|
||||
!isUserProvided &&
|
||||
!credentials.bearerToken &&
|
||||
(credentials.accessKeyId === undefined || credentials.accessKeyId === '') &&
|
||||
(credentials.secretAccessKey === undefined || credentials.secretAccessKey === '')
|
||||
) {
|
||||
|
||||
@@ -25,6 +25,26 @@ const DialogManager = ({
|
||||
endpointType={getEndpointField(endpointsConfig, keyDialogEndpoint, 'type')}
|
||||
onOpenChange={onOpenChange}
|
||||
userProvideURL={getEndpointField(endpointsConfig, keyDialogEndpoint, 'userProvideURL')}
|
||||
userProvideAccessKeyId={getEndpointField(
|
||||
endpointsConfig,
|
||||
keyDialogEndpoint,
|
||||
'userProvideAccessKeyId',
|
||||
)}
|
||||
userProvideSecretAccessKey={getEndpointField(
|
||||
endpointsConfig,
|
||||
keyDialogEndpoint,
|
||||
'userProvideSecretAccessKey',
|
||||
)}
|
||||
userProvideSessionToken={getEndpointField(
|
||||
endpointsConfig,
|
||||
keyDialogEndpoint,
|
||||
'userProvideSessionToken',
|
||||
)}
|
||||
userProvideBearerToken={getEndpointField(
|
||||
endpointsConfig,
|
||||
keyDialogEndpoint,
|
||||
'userProvideBearerToken',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
111
client/src/components/Input/SetKeyDialog/BedrockConfig.tsx
Normal file
111
client/src/components/Input/SetKeyDialog/BedrockConfig.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import React from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import InputWithLabel from './InputWithLabel';
|
||||
|
||||
const BedrockConfig = ({
|
||||
userProvideAccessKeyId,
|
||||
userProvideSecretAccessKey,
|
||||
userProvideSessionToken,
|
||||
userProvideBearerToken,
|
||||
}: {
|
||||
endpoint: EModelEndpoint | string;
|
||||
userProvideURL?: boolean | null;
|
||||
userProvideAccessKeyId?: boolean;
|
||||
userProvideSecretAccessKey?: boolean;
|
||||
userProvideSessionToken?: boolean;
|
||||
userProvideBearerToken?: boolean;
|
||||
}) => {
|
||||
const { control } = useFormContext();
|
||||
const localize = useLocalize();
|
||||
|
||||
const renderFields = () => {
|
||||
const fields: React.ReactNode[] = [];
|
||||
|
||||
if (userProvideAccessKeyId) {
|
||||
fields.push(
|
||||
<Controller
|
||||
key="bedrockAccessKeyId"
|
||||
name="bedrockAccessKeyId"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<InputWithLabel
|
||||
id="bedrockAccessKeyId"
|
||||
{...field}
|
||||
label={localize('com_endpoint_config_bedrock_access_key_id')}
|
||||
labelClassName="mb-1"
|
||||
inputClassName="mb-2"
|
||||
/>
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
if (userProvideSecretAccessKey) {
|
||||
if (fields.length > 0) fields.push(<div key="spacer1" className="mt-3" />);
|
||||
fields.push(
|
||||
<Controller
|
||||
key="bedrockSecretAccessKey"
|
||||
name="bedrockSecretAccessKey"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<InputWithLabel
|
||||
id="bedrockSecretAccessKey"
|
||||
{...field}
|
||||
label={localize('com_endpoint_config_bedrock_secret_access_key')}
|
||||
labelClassName="mb-1"
|
||||
inputClassName="mb-2"
|
||||
/>
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
if (userProvideSessionToken) {
|
||||
if (fields.length > 0) fields.push(<div key="spacer2" className="mt-3" />);
|
||||
fields.push(
|
||||
<Controller
|
||||
key="bedrockSessionToken"
|
||||
name="bedrockSessionToken"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<InputWithLabel
|
||||
id="bedrockSessionToken"
|
||||
{...field}
|
||||
label={localize('com_endpoint_config_bedrock_session_token')}
|
||||
labelClassName="mb-1"
|
||||
inputClassName="mb-2"
|
||||
/>
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
if (userProvideBearerToken) {
|
||||
if (fields.length > 0) fields.push(<div key="spacer3" className="mt-3" />);
|
||||
fields.push(
|
||||
<Controller
|
||||
key="bedrockBearerToken"
|
||||
name="bedrockBearerToken"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<InputWithLabel
|
||||
id="bedrockBearerToken"
|
||||
{...field}
|
||||
label={localize('com_endpoint_config_bedrock_bearer_token')}
|
||||
labelClassName="mb-1"
|
||||
inputClassName="mb-2"
|
||||
/>
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
return <>{fields}</>;
|
||||
};
|
||||
|
||||
return <form className="flex-wrap">{renderFields()}</form>;
|
||||
};
|
||||
|
||||
export default BedrockConfig;
|
||||
@@ -12,6 +12,7 @@ import CustomConfig from './CustomEndpoint';
|
||||
import GoogleConfig from './GoogleConfig';
|
||||
import OpenAIConfig from './OpenAIConfig';
|
||||
import OtherConfig from './OtherConfig';
|
||||
import BedrockConfig from './BedrockConfig';
|
||||
import HelpText from './HelpText';
|
||||
|
||||
const endpointComponents = {
|
||||
@@ -22,6 +23,7 @@ const endpointComponents = {
|
||||
[EModelEndpoint.gptPlugins]: OpenAIConfig,
|
||||
[EModelEndpoint.assistants]: OpenAIConfig,
|
||||
[EModelEndpoint.azureAssistants]: OpenAIConfig,
|
||||
[EModelEndpoint.bedrock]: BedrockConfig,
|
||||
default: OtherConfig,
|
||||
};
|
||||
|
||||
@@ -32,6 +34,7 @@ const formSet: Set<string> = new Set([
|
||||
EModelEndpoint.gptPlugins,
|
||||
EModelEndpoint.assistants,
|
||||
EModelEndpoint.azureAssistants,
|
||||
EModelEndpoint.bedrock,
|
||||
]);
|
||||
|
||||
const EXPIRY = {
|
||||
@@ -50,10 +53,18 @@ const SetKeyDialog = ({
|
||||
endpoint,
|
||||
endpointType,
|
||||
userProvideURL,
|
||||
userProvideAccessKeyId,
|
||||
userProvideSecretAccessKey,
|
||||
userProvideSessionToken,
|
||||
userProvideBearerToken,
|
||||
}: Pick<TDialogProps, 'open' | 'onOpenChange'> & {
|
||||
endpoint: EModelEndpoint | string;
|
||||
endpointType?: EModelEndpoint;
|
||||
userProvideURL?: boolean | null;
|
||||
userProvideAccessKeyId?: boolean;
|
||||
userProvideSecretAccessKey?: boolean;
|
||||
userProvideSessionToken?: boolean;
|
||||
userProvideBearerToken?: boolean;
|
||||
}) => {
|
||||
const methods = useForm({
|
||||
defaultValues: {
|
||||
@@ -63,6 +74,10 @@ const SetKeyDialog = ({
|
||||
azureOpenAIApiInstanceName: '',
|
||||
azureOpenAIApiDeploymentName: '',
|
||||
azureOpenAIApiVersion: '',
|
||||
bedrockAccessKeyId: '',
|
||||
bedrockSecretAccessKey: '',
|
||||
bedrockSessionToken: '',
|
||||
bedrockBearerToken: '',
|
||||
// TODO: allow endpoint definitions from user
|
||||
// name: '',
|
||||
// TODO: add custom endpoint models defined by user
|
||||
@@ -102,6 +117,7 @@ const SetKeyDialog = ({
|
||||
// TODO: handle other user provided options besides baseURL and apiKey
|
||||
methods.handleSubmit((data) => {
|
||||
const isAzure = endpoint === EModelEndpoint.azureOpenAI;
|
||||
const isBedrock = endpoint === EModelEndpoint.bedrock;
|
||||
const isOpenAIBase =
|
||||
isAzure ||
|
||||
endpoint === EModelEndpoint.openAI ||
|
||||
@@ -115,6 +131,9 @@ const SetKeyDialog = ({
|
||||
if (!isAzure && key.startsWith('azure')) {
|
||||
return false;
|
||||
}
|
||||
if (!isBedrock && key.startsWith('bedrock')) {
|
||||
return false;
|
||||
}
|
||||
if (isOpenAIBase && key === 'baseURL') {
|
||||
return false;
|
||||
}
|
||||
@@ -124,16 +143,67 @@ const SetKeyDialog = ({
|
||||
return data[key] === '';
|
||||
});
|
||||
|
||||
if (emptyValues.length > 0) {
|
||||
if (isBedrock) {
|
||||
const missingFields: string[] = [];
|
||||
let hasValidCredentials = false;
|
||||
|
||||
if (userProvideBearerToken && !data.bedrockBearerToken) {
|
||||
missingFields.push('AWS Bedrock Bearer Token');
|
||||
} else if (userProvideBearerToken && data.bedrockBearerToken) {
|
||||
hasValidCredentials = true;
|
||||
}
|
||||
|
||||
if (userProvideAccessKeyId && !data.bedrockAccessKeyId) {
|
||||
missingFields.push('AWS Access Key ID');
|
||||
}
|
||||
if (userProvideSecretAccessKey && !data.bedrockSecretAccessKey) {
|
||||
missingFields.push('AWS Secret Access Key');
|
||||
}
|
||||
|
||||
if (
|
||||
userProvideAccessKeyId &&
|
||||
userProvideSecretAccessKey &&
|
||||
data.bedrockAccessKeyId &&
|
||||
data.bedrockSecretAccessKey
|
||||
) {
|
||||
hasValidCredentials = true;
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
showToast({
|
||||
message: `${localize('com_endpoint_config_required_fields')} ${missingFields.join(', ')}`,
|
||||
status: 'error',
|
||||
});
|
||||
onOpenChange(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasValidCredentials) {
|
||||
showToast({
|
||||
message: localize('com_endpoint_config_bedrock_credentials_required'),
|
||||
status: 'error',
|
||||
});
|
||||
onOpenChange(true);
|
||||
return;
|
||||
}
|
||||
} else if (emptyValues.length > 0) {
|
||||
showToast({
|
||||
message: 'The following fields are required: ' + emptyValues.join(', '),
|
||||
message: `${localize('com_endpoint_config_required_fields')} ${emptyValues.join(', ')}`,
|
||||
status: 'error',
|
||||
});
|
||||
onOpenChange(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const { apiKey, baseURL, ...azureOptions } = data;
|
||||
const {
|
||||
apiKey,
|
||||
baseURL,
|
||||
bedrockAccessKeyId,
|
||||
bedrockSecretAccessKey,
|
||||
bedrockSessionToken,
|
||||
bedrockBearerToken,
|
||||
...azureOptions
|
||||
} = data;
|
||||
const userProvidedData = { apiKey, baseURL };
|
||||
if (isAzure) {
|
||||
userProvidedData.apiKey = JSON.stringify({
|
||||
@@ -142,6 +212,20 @@ const SetKeyDialog = ({
|
||||
azureOpenAIApiDeploymentName: azureOptions.azureOpenAIApiDeploymentName,
|
||||
azureOpenAIApiVersion: azureOptions.azureOpenAIApiVersion,
|
||||
});
|
||||
} else if (isBedrock) {
|
||||
// Prioritize bearer token if provided
|
||||
if (bedrockBearerToken) {
|
||||
userProvidedData.apiKey = JSON.stringify({
|
||||
bearerToken: bedrockBearerToken,
|
||||
});
|
||||
} else {
|
||||
// Use access keys
|
||||
userProvidedData.apiKey = JSON.stringify({
|
||||
accessKeyId: bedrockAccessKeyId,
|
||||
secretAccessKey: bedrockSecretAccessKey,
|
||||
...(bedrockSessionToken && { sessionToken: bedrockSessionToken }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
saveKey(JSON.stringify(userProvidedData));
|
||||
@@ -171,8 +255,8 @@ const SetKeyDialog = ({
|
||||
{expiryTime === 'never'
|
||||
? localize('com_endpoint_config_key_never_expires')
|
||||
: `${localize('com_endpoint_config_key_encryption')} ${new Date(
|
||||
expiryTime ?? 0,
|
||||
).toLocaleString()}`}
|
||||
expiryTime ?? 0,
|
||||
).toLocaleString()}`}
|
||||
</small>
|
||||
<Dropdown
|
||||
label="Expires "
|
||||
@@ -193,6 +277,10 @@ const SetKeyDialog = ({
|
||||
: endpoint
|
||||
}
|
||||
userProvideURL={userProvideURL}
|
||||
userProvideAccessKeyId={userProvideAccessKeyId}
|
||||
userProvideSecretAccessKey={userProvideSecretAccessKey}
|
||||
userProvideSessionToken={userProvideSessionToken}
|
||||
userProvideBearerToken={userProvideBearerToken}
|
||||
/>
|
||||
</FormProvider>
|
||||
<HelpText endpoint={endpoint} />
|
||||
|
||||
@@ -187,6 +187,12 @@
|
||||
"com_endpoint_config_key_never_expires": "Your key will never expire",
|
||||
"com_endpoint_config_placeholder": "Set your Key in the Header menu to chat.",
|
||||
"com_endpoint_config_value": "Enter value for",
|
||||
"com_endpoint_config_bedrock_access_key_id": "AWS Access Key ID",
|
||||
"com_endpoint_config_bedrock_secret_access_key": "AWS Secret Access Key",
|
||||
"com_endpoint_config_bedrock_session_token": "AWS Session Token",
|
||||
"com_endpoint_config_bedrock_bearer_token": "AWS Bedrock Bearer Token",
|
||||
"com_endpoint_config_bedrock_credentials_required": "Please provide either Access Keys (Access Key ID + Secret Access Key) or Bearer Token",
|
||||
"com_endpoint_config_required_fields": "The following fields are required:",
|
||||
"com_endpoint_context": "Context",
|
||||
"com_endpoint_context_info": "The maximum number of tokens that can be used for context. Use this for control of how many tokens are sent per request. If unspecified, will use system defaults based on known models' context size. Setting higher values may result in errors and/or higher token cost.",
|
||||
"com_endpoint_context_tokens": "Max Context Tokens",
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -48787,7 +48787,7 @@
|
||||
},
|
||||
"packages/data-schemas": {
|
||||
"name": "@librechat/data-schemas",
|
||||
"version": "0.0.12",
|
||||
"version": "0.0.13",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
|
||||
@@ -330,6 +330,10 @@ export type TConfig = {
|
||||
modelDisplayLabel?: string;
|
||||
userProvide?: boolean | null;
|
||||
userProvideURL?: boolean | null;
|
||||
userProvideAccessKeyId?: boolean;
|
||||
userProvideSecretAccessKey?: boolean;
|
||||
userProvideSessionToken?: boolean;
|
||||
userProvideBearerToken?: boolean;
|
||||
disableBuilder?: boolean;
|
||||
retrievalModels?: string[];
|
||||
capabilities?: string[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@librechat/data-schemas",
|
||||
"version": "0.0.12",
|
||||
"version": "0.0.13",
|
||||
"description": "Mongoose schemas and models for LibreChat",
|
||||
"type": "module",
|
||||
"main": "dist/index.cjs",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import path from 'path';
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
import { getLogDirectory } from './utils';
|
||||
|
||||
const logDir = path.join(__dirname, '..', '..', '..', 'api', 'logs');
|
||||
const logDir = getLogDirectory();
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING = 'false' } = process.env;
|
||||
|
||||
|
||||
37
packages/data-schemas/src/config/utils.ts
Normal file
37
packages/data-schemas/src/config/utils.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Determine the log directory in a cross-compatible way.
|
||||
* Priority:
|
||||
* 1. LIBRECHAT_LOG_DIR environment variable
|
||||
* 2. If running within LibreChat monorepo (when cwd ends with /api), use api/logs
|
||||
* 3. If api/logs exists relative to cwd, use that (for running from project root)
|
||||
* 4. Otherwise, use logs directory relative to process.cwd()
|
||||
*
|
||||
* This avoids using __dirname which is not available in ESM modules
|
||||
*/
|
||||
export const getLogDirectory = (): string => {
|
||||
if (process.env.LIBRECHAT_LOG_DIR) {
|
||||
return process.env.LIBRECHAT_LOG_DIR;
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
|
||||
// Check if we're running from within the api directory
|
||||
if (cwd.endsWith('/api') || cwd.endsWith('\\api')) {
|
||||
return path.join(cwd, 'logs');
|
||||
}
|
||||
|
||||
// Check if api/logs exists relative to current directory (running from project root)
|
||||
// We'll just use the path and let the file system create it if needed
|
||||
const apiLogsPath = path.join(cwd, 'api', 'logs');
|
||||
|
||||
// For LibreChat project structure, use api/logs
|
||||
// For external consumers, they should set LIBRECHAT_LOG_DIR
|
||||
if (cwd.includes('LibreChat')) {
|
||||
return apiLogsPath;
|
||||
}
|
||||
|
||||
// Default to logs directory relative to current working directory
|
||||
return path.join(cwd, 'logs');
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
import path from 'path';
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
import { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat } from './parsers';
|
||||
import { getLogDirectory } from './utils';
|
||||
|
||||
const logDir = path.join(__dirname, '..', '..', '..', 'api', 'logs');
|
||||
const logDir = getLogDirectory();
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING, CONSOLE_JSON, DEBUG_CONSOLE } = process.env;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user