feat(medusa): Improve config loading (#1290)

This commit is contained in:
Adrien de Peretti
2022-04-21 12:49:56 +02:00
committed by GitHub
parent 89a6de4660
commit 313cb0658b
25 changed files with 225 additions and 175 deletions

View File

@@ -28,7 +28,7 @@ export const simpleProductFactory = async (
connection: Connection,
data: ProductFactoryData = {},
seed?: number
): Promise<Product> => {
): Promise<Product | undefined> => {
if (typeof seed !== "undefined") {
faker.seed(seed)
}
@@ -50,9 +50,9 @@ export const simpleProductFactory = async (
status: data.status,
is_giftcard: data.is_giftcard || false,
discountable: !data.is_giftcard,
tags: [],
profile_id: data.is_giftcard ? gcProfile.id : defaultProfile.id,
}
tags: [] as ProductTag[],
profile_id: data.is_giftcard ? gcProfile?.id : defaultProfile?.id,
} as Product
if (typeof data.tags !== "undefined") {
for (let i = 0; i < data.tags.length; i++) {
@@ -112,5 +112,5 @@ export const simpleProductFactory = async (
await simpleProductVariantFactory(connection, factoryData)
}
return await manager.findOne(Product, { id: prodId }, { relations: ["tags"] })
return manager.findOne(Product, { id: prodId }, { relations: ["tags"] })
}

View File

@@ -8,5 +8,7 @@ module.exports = {
// redis_url: REDIS_URL,
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`,
database_type: "postgres",
jwt_secret: 'test',
cookie_secret: 'test'
},
}

View File

@@ -6,6 +6,7 @@ const pkgs = glob
module.exports = {
testEnvironment: `node`,
testTimeout: 10000,
globalSetup: "<rootDir>/integration-tests/globalSetup.js",
globalTeardown: "<rootDir>/integration-tests/globalTeardown.js",
rootDir: `../`,

View File

@@ -24,5 +24,7 @@ module.exports = {
// redis_url: REDIS_URL,
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`,
database_type: "postgres",
jwt_secret: 'test',
cookie_secret: 'test'
},
}

View File

@@ -62,7 +62,6 @@
"core-js": "^3.6.5",
"cors": "^2.8.5",
"cross-spawn": "^7.0.3",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-session": "^1.17.1",
"fs-exists-cached": "^1.0.0",

View File

@@ -1,6 +1,5 @@
import _ from "lodash"
import jwt from "jsonwebtoken"
import config from "../../../../config"
import { validator } from "../../../../utils/validator"
import { IsEmail, IsNotEmpty, IsString } from "class-validator"
import AuthService from "../../../../services/auth"
@@ -28,10 +27,11 @@ import { MedusaError } from "medusa-core-utils"
* $ref: "#/components/schemas/user"
*/
export default async (req, res) => {
if (!config.jwtSecret) {
const { projectConfig: { jwt_secret } } = req.scope.resolve('configModule')
if (!jwt_secret) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
"Please configure jwtSecret in your environment"
"Please configure jwt_secret in your environment"
)
}
const validated = await validator(AdminPostAuthReq, req.body)
@@ -44,7 +44,7 @@ export default async (req, res) => {
if (result.success && result.user) {
// Add JWT to cookie
req.session.jwt = jwt.sign({ userId: result.user.id }, config.jwtSecret, {
req.session.jwt = jwt.sign({ userId: result.user.id }, jwt_secret, {
expiresIn: "24h",
})

View File

@@ -1,6 +1,5 @@
import { IsEmail, IsNotEmpty } from "class-validator"
import jwt from "jsonwebtoken"
import config from "../../../../config"
import AuthService from "../../../../services/auth"
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
@@ -29,8 +28,6 @@ export default async (req, res) => {
const validated = await validator(StorePostAuthReq, req.body)
const authService: AuthService = req.scope.resolve("authService")
const customerService: CustomerService = req.scope.resolve("customerService")
const result = await authService.authenticateCustomer(
validated.email,
validated.password
@@ -41,14 +38,14 @@ export default async (req, res) => {
}
// Add JWT to cookie
req.session.jwt = jwt.sign(
{ customer_id: result.customer?.id },
config.jwtSecret as string,
{
expiresIn: "30d",
}
)
const {
projectConfig: { jwt_secret },
} = req.scope.resolve("configModule")
req.session.jwt = jwt.sign({ customer_id: result.customer?.id }, jwt_secret!, {
expiresIn: "30d",
})
const customerService: CustomerService = req.scope.resolve("customerService")
const customer = await customerService.retrieve(result.customer?.id || "", {
relations: ["orders", "orders.items"],
})

View File

@@ -2,7 +2,6 @@ import { IsEmail, IsOptional, IsString } from "class-validator"
import jwt from "jsonwebtoken"
import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
import { Customer } from "../../../.."
import config from "../../../../config"
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
@@ -36,7 +35,10 @@ export default async (req, res) => {
let customer: Customer = await customerService.create(validated)
// Add JWT to cookie
req.session.jwt = jwt.sign({ customer_id: customer.id }, config.jwtSecret!, {
const {
projectConfig: { jwt_secret },
} = req.scope.resolve("configModule")
req.session.jwt = jwt.sign({ customer_id: customer.id }, jwt_secret!, {
expiresIn: "30d",
})

View File

@@ -1,44 +0,0 @@
import dotenv from "dotenv"
// Set the NODE_ENV to 'development' by default
process.env.NODE_ENV = process.env.NODE_ENV || "development"
const envFound = dotenv.config()
if (!envFound) {
// This error should crash whole process
throw new Error("⚠️ Couldn't find .env file ⚠️")
}
const config = {
/**
* Your favorite port
*/
port: parseInt(process.env.PORT, 10),
databaseURL: process.env.MONGODB_URI,
redisURI: process.env.REDIS_URI,
/**
* Your secret sauce
*/
jwtSecret: process.env.NODE_ENV === "test" ? "test" : process.env.JWT_SECRET,
cookieSecret:
process.env.NODE_ENV === "test" ? "test" : process.env.COOKIE_SECRET,
/**
* Used by winston logger
*/
logs: {
level: process.env.LOG_LEVEL || "silly",
},
/**
* API configs
*/
api: {
prefix: "/api",
},
}
export default config

View File

@@ -4,7 +4,6 @@ import jwt from "jsonwebtoken"
import { MockManager } from "medusa-test-utils"
import "reflect-metadata"
import supertest from "supertest"
import config from "../config"
import apiLoader from "../loaders/api"
import passportLoader from "../loaders/passport"
import servicesLoader from "../loaders/services"
@@ -22,9 +21,19 @@ const clientSessionOpts = {
secret: "test",
}
const config = {
projectConfig: {
jwt_secret: 'supersecret',
cookie_secret: 'superSecret',
admin_cors: '',
store_cors: ''
}
}
const testApp = express()
const container = createContainer()
container.register('configModule', asValue(config))
container.register({
logger: asValue({
error: () => {},
@@ -45,16 +54,16 @@ testApp.use((req, res, next) => {
next()
})
servicesLoader({ container })
strategiesLoader({ container })
passportLoader({ app: testApp, container })
servicesLoader({ container, configModule: config })
strategiesLoader({ container, configModule: config })
passportLoader({ app: testApp, container, configModule: config })
testApp.use((req, res, next) => {
req.scope = container.createScope()
next()
})
apiLoader({ container, rootDirectory: ".", app: testApp })
apiLoader({ container, app: testApp, configModule: config })
const supertestRequest = supertest(testApp)
@@ -68,7 +77,7 @@ export async function request(method, url, opts = {}) {
if (opts.adminSession.jwt) {
opts.adminSession.jwt = jwt.sign(
opts.adminSession.jwt,
config.jwtSecret,
config.projectConfig.jwt_secret,
{
expiresIn: "30m",
}
@@ -80,7 +89,7 @@ export async function request(method, url, opts = {}) {
if (opts.clientSession.jwt) {
opts.clientSession.jwt = jwt.sign(
opts.clientSession.jwt,
config.jwtSecret,
config.projectConfig.jwt_secret,
{
expiresIn: "30d",
}

View File

@@ -1,21 +1,18 @@
import { Express } from 'express'
import bodyParser from "body-parser"
import { getConfigFile } from "medusa-core-utils"
import routes from "../api"
import { AwilixContainer } from "awilix"
import { ConfigModule } from "../types/global"
type Options = {
app: Express;
rootDirectory: string;
app: Express
container: AwilixContainer
configModule: ConfigModule
}
export default async ({ app, rootDirectory, container }: Options) => {
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: Record<string, unknown> }
const config = (configModule && configModule.projectConfig) || {}
export default async ({ app, container, configModule }: Options) => {
app.use(bodyParser.json())
app.use("/", routes(container, config))
app.use("/", routes(container, configModule.projectConfig))
return app
}

View File

@@ -0,0 +1,61 @@
import { ConfigModule } from "../types/global"
import { getConfigFile } from "medusa-core-utils/dist"
const isProduction = ["production", "prod"].includes(process.env.NODE_ENV || "")
const errorHandler = isProduction
? (msg: string): never => {
throw new Error(msg)
}
: console.log
export default (rootDirectory: string): ConfigModule => {
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as {
configModule: ConfigModule
}
if (!configModule?.projectConfig?.redis_url) {
console.log(
`[medusa-config] ⚠️ redis_url not found. A fake redis instance will be used.`
)
}
const jwt_secret =
configModule?.projectConfig?.jwt_secret ?? process.env.JWT_SECRET
if (!jwt_secret) {
errorHandler(
`[medusa-config] ⚠️ jwt_secret not found.${
isProduction
? ""
: " fallback to either cookie_secret or default 'supersecret'."
}`
)
}
const cookie_secret =
configModule?.projectConfig?.cookie_secret ?? process.env.COOKIE_SECRET
if (!cookie_secret) {
errorHandler(
`[medusa-config] ⚠️ cookie_secret not found.${
isProduction
? ""
: " fallback to either cookie_secret or default 'supersecret'."
}`
)
}
if (!configModule?.projectConfig?.database_type) {
console.log(
`[medusa-config] ⚠️ database_type not found. fallback to default sqlite.`
)
}
return {
projectConfig: {
jwt_secret: jwt_secret ?? "supersecret",
cookie_secret: cookie_secret ?? "supersecret",
...configModule?.projectConfig,
},
plugins: configModule?.plugins ?? [],
}
}

View File

@@ -2,17 +2,10 @@ import { Connection, createConnection, LoggerOptions } from "typeorm"
import { ShortenedNamingStrategy } from "../utils/naming-strategy"
import { AwilixContainer } from "awilix"
import { ConnectionOptions } from "typeorm/connection/ConnectionOptions"
export type DatabaseConfig = {
database_type: string;
database_url?: string;
database_database?: string;
database_extra?: Record<string, unknown>;
database_logging: LoggerOptions
}
import { ConfigModule } from "../types/global"
type Options = {
configModule: { projectConfig: DatabaseConfig };
configModule: ConfigModule
container: AwilixContainer
}

View File

@@ -4,12 +4,11 @@ import cookieParser from "cookie-parser"
import morgan from "morgan"
import redis, { RedisConfig } from "redis"
import createStore from "connect-redis"
import config from "../config"
import { ConfigModule } from "../types/global"
type Options = {
app: Express;
configModule: { projectConfig: RedisConfig }
configModule: ConfigModule
}
export default async ({ app, configModule }: Options): Promise<Express> => {
@@ -23,12 +22,13 @@ export default async ({ app, configModule }: Options): Promise<Express> => {
sameSite = "none"
}
const sessionOpts = {
const { cookie_secret } = configModule.projectConfig
let sessionOpts = {
resave: true,
saveUninitialized: true,
cookieName: "session",
proxy: true,
secret: config.cookieSecret,
secret: cookie_secret,
cookie: {
sameSite,
secure,
@@ -37,7 +37,7 @@ export default async ({ app, configModule }: Options): Promise<Express> => {
store: null
}
if (configModule.projectConfig.redis_url) {
if (configModule?.projectConfig?.redis_url) {
const RedisStore = createStore(session)
const redisClient = redis.createClient(configModule.projectConfig.redis_url)
sessionOpts.store = new RedisStore({ client: redisClient })

View File

@@ -1,13 +1,14 @@
import loadConfig from './config'
import "reflect-metadata"
import Logger from "./logger"
import apiLoader from "./api"
import databaseLoader, { DatabaseConfig } from "./database"
import databaseLoader from "./database"
import defaultsLoader from "./defaults"
import expressLoader from "./express"
import modelsLoader from "./models"
import passportLoader from "./passport"
import pluginsLoader, { registerPluginModels } from "./plugins"
import redisLoader, { RedisConfig } from "./redis"
import redisLoader from "./redis"
import repositoriesLoader from "./repositories"
import requestIp from "request-ip"
import searchIndexLoader from "./search-index"
@@ -18,7 +19,6 @@ import { ClassOrFunctionReturning } from "awilix/lib/container"
import { Connection, getManager } from "typeorm"
import { Express, NextFunction, Request, Response } from "express"
import { asFunction, asValue, AwilixContainer, createContainer, Resolver } from "awilix"
import { getConfigFile } from "medusa-core-utils"
import { track } from "medusa-telemetry"
import { MedusaContainer } from "../types/global"
@@ -28,14 +28,6 @@ type Options = {
isTest: boolean
}
export type ConfigModule = {
projectConfig: DatabaseConfig & RedisConfig;
plugins: {
resolve: string;
options: Record<string, unknown>
}[];
}
export default async (
{
directory: rootDirectory,
@@ -43,9 +35,11 @@ export default async (
isTest
}: Options
): Promise<{ container: MedusaContainer; dbConnection: Connection; app: Express }> => {
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: ConfigModule }
const configModule = loadConfig(rootDirectory)
const container = createContainer() as MedusaContainer
container.register('configModule', asValue(configModule))
container.registerAdd = function (this: MedusaContainer, name: string, registration: typeof asFunction | typeof asValue) {
const storeKey = name + "_STORE"
@@ -73,7 +67,7 @@ export default async (
})
container.register({
logger: asValue(Logger),
logger: asValue(Logger)
})
await redisLoader({ container, configModule, logger: Logger })
@@ -89,6 +83,7 @@ export default async (
await registerPluginModels({
rootDirectory,
container,
configModule
})
const pmAct = Logger.success(pmActivity, "Plugin models initialized") || {}
track("PLUGIN_MODELS_INIT_COMPLETED", { duration: pmAct.duration })
@@ -122,7 +117,7 @@ export default async (
const expActivity = Logger.activity("Initializing express")
track("EXPRESS_INIT_STARTED")
await expressLoader({ app: expressApp, configModule })
await passportLoader({ app: expressApp, container })
await passportLoader({ app: expressApp, container, configModule })
const exAct = Logger.success(expActivity, "Express intialized") || {}
track("EXPRESS_INIT_COMPLETED", { duration: exAct.duration })
@@ -138,6 +133,7 @@ export default async (
await pluginsLoader({
container,
rootDirectory,
configModule,
app: expressApp,
activityId: pluginsActivity,
})
@@ -152,7 +148,7 @@ export default async (
const apiActivity = Logger.activity("Initializing API")
track("API_INIT_STARTED")
await apiLoader({ container, rootDirectory, app: expressApp })
await apiLoader({ container, app: expressApp, configModule })
const apiAct = Logger.success(apiActivity, "API initialized") || {}
track("API_INIT_COMPLETED", { duration: apiAct.duration })

View File

@@ -1,13 +1,12 @@
import config from "../config"
import passport from "passport"
import { AuthService } from "../services"
import { Express } from 'express'
import { MedusaContainer } from "../types/global"
import { ConfigModule, MedusaContainer } from "../types/global"
import { Strategy as BearerStrategy } from "passport-http-bearer"
import { Strategy as JWTStrategy } from "passport-jwt"
import { Strategy as LocalStrategy } from "passport-local"
export default async ({ app, container }: { app: Express; container: MedusaContainer }): Promise<void> => {
export default async ({ app, container, configModule }: { app: Express; container: MedusaContainer; configModule: ConfigModule; }): Promise<void> => {
const authService = container.resolve<AuthService>("authService")
// For good old email password authentication
@@ -34,11 +33,12 @@ export default async ({ app, container }: { app: Express; container: MedusaConta
// After a user has authenticated a JWT will be placed on a cookie, all
// calls will be authenticated based on the JWT
const { jwt_secret } = configModule.projectConfig
passport.use(
new JWTStrategy(
{
jwtFromRequest: (req) => req.session.jwt,
secretOrKey: config.jwtSecret,
secretOrKey: jwt_secret,
},
async (jwtPayload, done) => {
return done(null, jwtPayload)

View File

@@ -18,30 +18,30 @@ import { asValue, asClass, asFunction, aliasTo } from "awilix"
import { sync as existsSync } from "fs-exists-cached"
import { AbstractTaxService, isTaxCalculationStrategy } from "../interfaces"
import formatRegistrationName from "../utils/format-registration-name"
import { ClassConstructor, Logger, MedusaContainer } from "../types/global"
import { ConfigModule } from "./index"
import { ClassConstructor, ConfigModule, Logger, MedusaContainer } from "../types/global"
import { MiddlewareService } from "../services"
type Options = {
rootDirectory: string;
container: MedusaContainer;
app: Express;
rootDirectory: string
container: MedusaContainer
configModule: ConfigModule
app: Express
activityId: string
}
type PluginDetails = {
resolve: string;
name: string;
id: string;
options: Record<string, unknown>;
version: string;
resolve: string
name: string
id: string
options: Record<string, unknown>
version: string
}
/**
* Registers all services in the services directory
*/
export default async ({ rootDirectory, container, app, activityId }: Options): Promise<void> => {
const resolved = getResolvedPlugins(rootDirectory) || []
export default async ({ rootDirectory, container, app, configModule, activityId }: Options): Promise<void> => {
const resolved = getResolvedPlugins(rootDirectory, configModule) || []
await Promise.all(
resolved.map(async (pluginDetails) => {
@@ -59,13 +59,7 @@ export default async ({ rootDirectory, container, app, activityId }: Options): P
)
}
function getResolvedPlugins(rootDirectory: string): undefined | PluginDetails[] {
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: ConfigModule }
if (!configModule) {
return
}
function getResolvedPlugins(rootDirectory: string, configModule: ConfigModule): undefined | PluginDetails[] {
const { plugins } = configModule
const resolved = plugins.map((plugin) => {
@@ -90,8 +84,12 @@ function getResolvedPlugins(rootDirectory: string): undefined | PluginDetails[]
return resolved
}
export async function registerPluginModels({ rootDirectory, container }: { rootDirectory: string; container: MedusaContainer }): Promise<void> {
const resolved = getResolvedPlugins(rootDirectory) || []
export async function registerPluginModels({
rootDirectory,
container,
configModule
}: { rootDirectory: string; container: MedusaContainer; configModule: ConfigModule; }): Promise<void> {
const resolved = getResolvedPlugins(rootDirectory, configModule) || []
await Promise.all(
resolved.map(async (pluginDetails) => {
registerModels(pluginDetails, container)

View File

@@ -1,16 +1,12 @@
import { asValue } from "awilix"
import RealRedis from "ioredis"
import FakeRedis from "ioredis-mock"
import { MedusaContainer } from "../types/global"
import { ConfigModule, MedusaContainer } from "../types/global"
import { Logger } from "../types/global"
export type RedisConfig = {
redis_url?: string;
}
type Options = {
container: MedusaContainer;
configModule: { projectConfig: RedisConfig };
configModule: ConfigModule;
logger: Logger;
}

View File

@@ -2,13 +2,12 @@ import glob from "glob"
import path from "path"
import { asFunction } from "awilix"
import formatRegistrationName from "../utils/format-registration-name"
import { MedusaContainer } from "../types/global"
import { ConfigModule } from "./index"
import { ConfigModule, MedusaContainer } from "../types/global"
type Options = {
container: MedusaContainer;
configModule: ConfigModule
isTest: boolean;
isTest?: boolean;
}
/**

View File

@@ -7,7 +7,7 @@ import formatRegistrationName from "../utils/format-registration-name"
type LoaderOptions = {
container: AwilixContainer
configModule: object
isTest: boolean
isTest?: boolean
}
/**

View File

@@ -1,11 +1,11 @@
import Bull from "bull"
import { MockRepository, MockManager } from "medusa-test-utils"
import EventBusService from "../event-bus"
import config from "../../config"
import config from "../../loaders/config"
jest.genMockFromModule("bull")
jest.mock("bull")
jest.mock("../../config")
jest.mock("../../loaders/config")
config.redisURI = "testhost"

View File

@@ -19,6 +19,8 @@ describe("InviteService", () => {
userRepository: {},
inviteRepository: inviteRepo,
eventBusService: EventBusServiceMock,
}, {
projectConfig: { jwt_secret: 'superSecret' }
})
it("calls invite repository find", async () => {
@@ -40,6 +42,8 @@ describe("InviteService", () => {
userRepository: {},
inviteRepository: {},
eventBusService: EventBusServiceMock,
}, {
projectConfig: { jwt_secret: 'superSecret' }
})
it("validating a signed token succeeds", () => {
@@ -108,6 +112,8 @@ describe("InviteService", () => {
userRepository: userRepo,
inviteRepository: inviteRepo,
eventBusService: EventBusServiceMock,
}, {
projectConfig: { jwt_secret: 'superSecret' }
})
beforeEach(() => jest.clearAllMocks())
@@ -200,6 +206,8 @@ describe("InviteService", () => {
userRepository: {},
inviteRepository: inviteRepo,
eventBusService: EventBusServiceMock,
}, {
projectConfig: { jwt_secret: 'superSecret' }
})
inviteService.generateToken = jest.fn()

View File

@@ -4,11 +4,11 @@ import { BaseService } from "medusa-interfaces"
import { EntityManager } from "typeorm"
import { EventBusService, UserService } from "."
import { User } from ".."
import config from "../config"
import { UserRoles } from "../models/user"
import { InviteRepository } from "../repositories/invite"
import { UserRepository } from "../repositories/user"
import { ListInvite } from "../types/invites"
import { ConfigModule } from "../types/global"
// 7 days
const DEFAULT_VALID_DURATION = 1000 * 60 * 60 * 24 * 7
@@ -32,15 +32,22 @@ class InviteService extends BaseService {
private inviteRepository_: InviteRepository
private eventBus_: EventBusService
constructor({
manager,
userService,
userRepository,
inviteRepository,
eventBusService,
}: InviteServiceProps) {
protected readonly configModule_: ConfigModule
constructor(
{
manager,
userService,
userRepository,
inviteRepository,
eventBusService,
}: InviteServiceProps,
configModule: ConfigModule
) {
super()
this.configModule_ = configModule
/** @private @constant {EntityManager} */
this.manager_ = manager
@@ -62,13 +69,16 @@ class InviteService extends BaseService {
return this
}
const cloned = new InviteService({
manager,
inviteRepository: this.inviteRepository_,
userService: this.userService_,
userRepository: this.userRepo_,
eventBusService: this.eventBus_,
})
const cloned = new InviteService(
{
manager,
inviteRepository: this.inviteRepository_,
userService: this.userService_,
userRepository: this.userRepo_,
eventBusService: this.eventBus_,
},
this.configModule_
)
cloned.transactionManager_ = manager
@@ -76,12 +86,13 @@ class InviteService extends BaseService {
}
generateToken(data): string {
if (config.jwtSecret) {
return jwt.sign(data, config.jwtSecret)
const { jwt_secret } = this.configModule_.projectConfig
if (jwt_secret) {
return jwt.sign(data, jwt_secret)
}
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Please configure JwtSecret"
"Please configure jwt_secret"
)
}
@@ -248,12 +259,13 @@ class InviteService extends BaseService {
}
verifyToken(token): JwtPayload | string {
if (config.jwtSecret) {
return jwt.verify(token, config.jwtSecret)
const { jwt_secret } = this.configModule_.projectConfig
if (jwt_secret) {
return jwt.verify(token, jwt_secret)
}
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Please configure JwtSecret"
"Please configure jwt_secret"
)
}

View File

@@ -1,5 +1,6 @@
import { AwilixContainer } from "awilix"
import { Logger as _Logger } from "winston"
import { LoggerOptions } from "typeorm"
export type ClassConstructor<T> = {
new (...args: unknown[]): T
@@ -12,3 +13,30 @@ export type MedusaContainer = AwilixContainer & {
export type Logger = _Logger & {
progress: (activityId: string, msg: string) => void
}
export type ConfigModule = {
projectConfig: {
redis_url?: string
jwt_secret?: string
cookie_secret?: string
database_url?: string
database_type: string
database_database?: string
database_logging: LoggerOptions
database_extra?: Record<string, unknown> & {
ssl: { rejectUnauthorized: false }
}
store_cors?: string
admin_cors?: string
}
plugins: (
| {
resolve: string
options: Record<string, unknown>
}
| string
)[]
}

View File

@@ -1519,7 +1519,6 @@
chalk "^4.0.0"
configstore "5.0.1"
core-js "^3.6.5"
dotenv "^8.2.0"
execa "^5.1.1"
fs-exists-cached "^1.0.0"
fs-extra "^10.0.0"
@@ -3242,11 +3241,6 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
dotenv@^8.2.0:
version "8.6.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b"
integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"