feat(medusa): Improve config loading (#1290)
This commit is contained in:
committed by
GitHub
parent
89a6de4660
commit
313cb0658b
@@ -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"] })
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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: `../`,
|
||||
|
||||
@@ -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'
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
})
|
||||
|
||||
|
||||
@@ -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"],
|
||||
})
|
||||
|
||||
@@ -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",
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
61
packages/medusa/src/loaders/config.ts
Normal file
61
packages/medusa/src/loaders/config.ts
Normal 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 ?? [],
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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 })
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ import formatRegistrationName from "../utils/format-registration-name"
|
||||
type LoaderOptions = {
|
||||
container: AwilixContainer
|
||||
configModule: object
|
||||
isTest: boolean
|
||||
isTest?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)[]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user