feat(medusa): Improve config loading (#1290)
This commit is contained in:
1 parent
89a6de4660
commit
313cb0658b
25 files changed
+214
-164
No files matched your search
@@ -28,7 +28,7 @@ export const simpleProductFactory = async (
|
|||||||
connection: Connection,
|
connection: Connection,
|
||||||
data: ProductFactoryData = {},
|
data: ProductFactoryData = {},
|
||||||
seed?: number
|
seed?: number
|
||||||
): Promise<Product> => {
|
): Promise<Product | undefined> => {
|
||||||
if (typeof seed !== "undefined") {
|
if (typeof seed !== "undefined") {
|
||||||
faker.seed(seed)
|
faker.seed(seed)
|
||||||
}
|
}
|
||||||
@@ -50,9 +50,9 @@ export const simpleProductFactory = async (
|
|||||||
status: data.status,
|
status: data.status,
|
||||||
is_giftcard: data.is_giftcard || false,
|
is_giftcard: data.is_giftcard || false,
|
||||||
discountable: !data.is_giftcard,
|
discountable: !data.is_giftcard,
|
||||||
tags: [],
|
tags: [] as ProductTag[],
|
||||||
profile_id: data.is_giftcard ? gcProfile.id : defaultProfile.id,
|
profile_id: data.is_giftcard ? gcProfile?.id : defaultProfile?.id,
|
||||||
}
|
} as Product
|
||||||
|
|
||||||
if (typeof data.tags !== "undefined") {
|
if (typeof data.tags !== "undefined") {
|
||||||
for (let i = 0; i < data.tags.length; i++) {
|
for (let i = 0; i < data.tags.length; i++) {
|
||||||
@@ -112,5 +112,5 @@ export const simpleProductFactory = async (
|
|||||||
await simpleProductVariantFactory(connection, factoryData)
|
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,
|
// redis_url: REDIS_URL,
|
||||||
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`,
|
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`,
|
||||||
database_type: "postgres",
|
database_type: "postgres",
|
||||||
|
jwt_secret: 'test',
|
||||||
|
cookie_secret: 'test'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ const pkgs = glob
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
testEnvironment: `node`,
|
testEnvironment: `node`,
|
||||||
|
testTimeout: 10000,
|
||||||
globalSetup: "<rootDir>/integration-tests/globalSetup.js",
|
globalSetup: "<rootDir>/integration-tests/globalSetup.js",
|
||||||
globalTeardown: "<rootDir>/integration-tests/globalTeardown.js",
|
globalTeardown: "<rootDir>/integration-tests/globalTeardown.js",
|
||||||
rootDir: `../`,
|
rootDir: `../`,
|
||||||
|
|||||||
@@ -24,5 +24,7 @@ module.exports = {
|
|||||||
// redis_url: REDIS_URL,
|
// redis_url: REDIS_URL,
|
||||||
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`,
|
database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`,
|
||||||
database_type: "postgres",
|
database_type: "postgres",
|
||||||
|
jwt_secret: 'test',
|
||||||
|
cookie_secret: 'test'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,6 @@
|
|||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cross-spawn": "^7.0.3",
|
"cross-spawn": "^7.0.3",
|
||||||
"dotenv": "^8.2.0",
|
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
"fs-exists-cached": "^1.0.0",
|
"fs-exists-cached": "^1.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import jwt from "jsonwebtoken"
|
import jwt from "jsonwebtoken"
|
||||||
import config from "../../../../config"
|
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
import { IsEmail, IsNotEmpty, IsString } from "class-validator"
|
import { IsEmail, IsNotEmpty, IsString } from "class-validator"
|
||||||
import AuthService from "../../../../services/auth"
|
import AuthService from "../../../../services/auth"
|
||||||
@@ -28,10 +27,11 @@ import { MedusaError } from "medusa-core-utils"
|
|||||||
* $ref: "#/components/schemas/user"
|
* $ref: "#/components/schemas/user"
|
||||||
*/
|
*/
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
if (!config.jwtSecret) {
|
const { projectConfig: { jwt_secret } } = req.scope.resolve('configModule')
|
||||||
|
if (!jwt_secret) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
MedusaError.Types.NOT_FOUND,
|
||||||
"Please configure jwtSecret in your environment"
|
"Please configure jwt_secret in your environment"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const validated = await validator(AdminPostAuthReq, req.body)
|
const validated = await validator(AdminPostAuthReq, req.body)
|
||||||
@@ -44,7 +44,7 @@ export default async (req, res) => {
|
|||||||
|
|
||||||
if (result.success && result.user) {
|
if (result.success && result.user) {
|
||||||
// Add JWT to cookie
|
// 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",
|
expiresIn: "24h",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { IsEmail, IsNotEmpty } from "class-validator"
|
import { IsEmail, IsNotEmpty } from "class-validator"
|
||||||
import jwt from "jsonwebtoken"
|
import jwt from "jsonwebtoken"
|
||||||
import config from "../../../../config"
|
|
||||||
import AuthService from "../../../../services/auth"
|
import AuthService from "../../../../services/auth"
|
||||||
import CustomerService from "../../../../services/customer"
|
import CustomerService from "../../../../services/customer"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
@@ -29,8 +28,6 @@ export default async (req, res) => {
|
|||||||
const validated = await validator(StorePostAuthReq, req.body)
|
const validated = await validator(StorePostAuthReq, req.body)
|
||||||
|
|
||||||
const authService: AuthService = req.scope.resolve("authService")
|
const authService: AuthService = req.scope.resolve("authService")
|
||||||
const customerService: CustomerService = req.scope.resolve("customerService")
|
|
||||||
|
|
||||||
const result = await authService.authenticateCustomer(
|
const result = await authService.authenticateCustomer(
|
||||||
validated.email,
|
validated.email,
|
||||||
validated.password
|
validated.password
|
||||||
@@ -41,14 +38,14 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add JWT to cookie
|
// Add JWT to cookie
|
||||||
req.session.jwt = jwt.sign(
|
const {
|
||||||
{ customer_id: result.customer?.id },
|
projectConfig: { jwt_secret },
|
||||||
config.jwtSecret as string,
|
} = req.scope.resolve("configModule")
|
||||||
{
|
req.session.jwt = jwt.sign({ customer_id: result.customer?.id }, jwt_secret!, {
|
||||||
expiresIn: "30d",
|
expiresIn: "30d",
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
|
const customerService: CustomerService = req.scope.resolve("customerService")
|
||||||
const customer = await customerService.retrieve(result.customer?.id || "", {
|
const customer = await customerService.retrieve(result.customer?.id || "", {
|
||||||
relations: ["orders", "orders.items"],
|
relations: ["orders", "orders.items"],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { IsEmail, IsOptional, IsString } from "class-validator"
|
|||||||
import jwt from "jsonwebtoken"
|
import jwt from "jsonwebtoken"
|
||||||
import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
|
import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
|
||||||
import { Customer } from "../../../.."
|
import { Customer } from "../../../.."
|
||||||
import config from "../../../../config"
|
|
||||||
import CustomerService from "../../../../services/customer"
|
import CustomerService from "../../../../services/customer"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -36,7 +35,10 @@ export default async (req, res) => {
|
|||||||
let customer: Customer = await customerService.create(validated)
|
let customer: Customer = await customerService.create(validated)
|
||||||
|
|
||||||
// Add JWT to cookie
|
// 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",
|
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 { MockManager } from "medusa-test-utils"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import supertest from "supertest"
|
import supertest from "supertest"
|
||||||
import config from "../config"
|
|
||||||
import apiLoader from "../loaders/api"
|
import apiLoader from "../loaders/api"
|
||||||
import passportLoader from "../loaders/passport"
|
import passportLoader from "../loaders/passport"
|
||||||
import servicesLoader from "../loaders/services"
|
import servicesLoader from "../loaders/services"
|
||||||
@@ -22,9 +21,19 @@ const clientSessionOpts = {
|
|||||||
secret: "test",
|
secret: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
projectConfig: {
|
||||||
|
jwt_secret: 'supersecret',
|
||||||
|
cookie_secret: 'superSecret',
|
||||||
|
admin_cors: '',
|
||||||
|
store_cors: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testApp = express()
|
const testApp = express()
|
||||||
|
|
||||||
const container = createContainer()
|
const container = createContainer()
|
||||||
|
container.register('configModule', asValue(config))
|
||||||
container.register({
|
container.register({
|
||||||
logger: asValue({
|
logger: asValue({
|
||||||
error: () => {},
|
error: () => {},
|
||||||
@@ -45,16 +54,16 @@ testApp.use((req, res, next) => {
|
|||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
servicesLoader({ container })
|
servicesLoader({ container, configModule: config })
|
||||||
strategiesLoader({ container })
|
strategiesLoader({ container, configModule: config })
|
||||||
passportLoader({ app: testApp, container })
|
passportLoader({ app: testApp, container, configModule: config })
|
||||||
|
|
||||||
testApp.use((req, res, next) => {
|
testApp.use((req, res, next) => {
|
||||||
req.scope = container.createScope()
|
req.scope = container.createScope()
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
apiLoader({ container, rootDirectory: ".", app: testApp })
|
apiLoader({ container, app: testApp, configModule: config })
|
||||||
|
|
||||||
const supertestRequest = supertest(testApp)
|
const supertestRequest = supertest(testApp)
|
||||||
|
|
||||||
@@ -68,7 +77,7 @@ export async function request(method, url, opts = {}) {
|
|||||||
if (opts.adminSession.jwt) {
|
if (opts.adminSession.jwt) {
|
||||||
opts.adminSession.jwt = jwt.sign(
|
opts.adminSession.jwt = jwt.sign(
|
||||||
opts.adminSession.jwt,
|
opts.adminSession.jwt,
|
||||||
config.jwtSecret,
|
config.projectConfig.jwt_secret,
|
||||||
{
|
{
|
||||||
expiresIn: "30m",
|
expiresIn: "30m",
|
||||||
}
|
}
|
||||||
@@ -80,7 +89,7 @@ export async function request(method, url, opts = {}) {
|
|||||||
if (opts.clientSession.jwt) {
|
if (opts.clientSession.jwt) {
|
||||||
opts.clientSession.jwt = jwt.sign(
|
opts.clientSession.jwt = jwt.sign(
|
||||||
opts.clientSession.jwt,
|
opts.clientSession.jwt,
|
||||||
config.jwtSecret,
|
config.projectConfig.jwt_secret,
|
||||||
{
|
{
|
||||||
expiresIn: "30d",
|
expiresIn: "30d",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
import { Express } from 'express'
|
import { Express } from 'express'
|
||||||
import bodyParser from "body-parser"
|
import bodyParser from "body-parser"
|
||||||
import { getConfigFile } from "medusa-core-utils"
|
|
||||||
import routes from "../api"
|
import routes from "../api"
|
||||||
import { AwilixContainer } from "awilix"
|
import { AwilixContainer } from "awilix"
|
||||||
|
import { ConfigModule } from "../types/global"
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
app: Express;
|
app: Express
|
||||||
rootDirectory: string;
|
|
||||||
container: AwilixContainer
|
container: AwilixContainer
|
||||||
|
configModule: ConfigModule
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async ({ app, rootDirectory, container }: Options) => {
|
export default async ({ app, container, configModule }: Options) => {
|
||||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: Record<string, unknown> }
|
|
||||||
const config = (configModule && configModule.projectConfig) || {}
|
|
||||||
|
|
||||||
app.use(bodyParser.json())
|
app.use(bodyParser.json())
|
||||||
app.use("/", routes(container, config))
|
app.use("/", routes(container, configModule.projectConfig))
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
@@ -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 { ShortenedNamingStrategy } from "../utils/naming-strategy"
|
||||||
import { AwilixContainer } from "awilix"
|
import { AwilixContainer } from "awilix"
|
||||||
import { ConnectionOptions } from "typeorm/connection/ConnectionOptions"
|
import { ConnectionOptions } from "typeorm/connection/ConnectionOptions"
|
||||||
|
import { ConfigModule } from "../types/global"
|
||||||
export type DatabaseConfig = {
|
|
||||||
database_type: string;
|
|
||||||
database_url?: string;
|
|
||||||
database_database?: string;
|
|
||||||
database_extra?: Record<string, unknown>;
|
|
||||||
database_logging: LoggerOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
configModule: { projectConfig: DatabaseConfig };
|
configModule: ConfigModule
|
||||||
container: AwilixContainer
|
container: AwilixContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ import cookieParser from "cookie-parser"
|
|||||||
import morgan from "morgan"
|
import morgan from "morgan"
|
||||||
import redis, { RedisConfig } from "redis"
|
import redis, { RedisConfig } from "redis"
|
||||||
import createStore from "connect-redis"
|
import createStore from "connect-redis"
|
||||||
|
import { ConfigModule } from "../types/global"
|
||||||
import config from "../config"
|
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
app: Express;
|
app: Express;
|
||||||
configModule: { projectConfig: RedisConfig }
|
configModule: ConfigModule
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async ({ app, configModule }: Options): Promise<Express> => {
|
export default async ({ app, configModule }: Options): Promise<Express> => {
|
||||||
@@ -23,12 +22,13 @@ export default async ({ app, configModule }: Options): Promise<Express> => {
|
|||||||
sameSite = "none"
|
sameSite = "none"
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessionOpts = {
|
const { cookie_secret } = configModule.projectConfig
|
||||||
|
let sessionOpts = {
|
||||||
resave: true,
|
resave: true,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookieName: "session",
|
cookieName: "session",
|
||||||
proxy: true,
|
proxy: true,
|
||||||
secret: config.cookieSecret,
|
secret: cookie_secret,
|
||||||
cookie: {
|
cookie: {
|
||||||
sameSite,
|
sameSite,
|
||||||
secure,
|
secure,
|
||||||
@@ -37,7 +37,7 @@ export default async ({ app, configModule }: Options): Promise<Express> => {
|
|||||||
store: null
|
store: null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configModule.projectConfig.redis_url) {
|
if (configModule?.projectConfig?.redis_url) {
|
||||||
const RedisStore = createStore(session)
|
const RedisStore = createStore(session)
|
||||||
const redisClient = redis.createClient(configModule.projectConfig.redis_url)
|
const redisClient = redis.createClient(configModule.projectConfig.redis_url)
|
||||||
sessionOpts.store = new RedisStore({ client: redisClient })
|
sessionOpts.store = new RedisStore({ client: redisClient })
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
import loadConfig from './config'
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import Logger from "./logger"
|
import Logger from "./logger"
|
||||||
import apiLoader from "./api"
|
import apiLoader from "./api"
|
||||||
import databaseLoader, { DatabaseConfig } from "./database"
|
import databaseLoader from "./database"
|
||||||
import defaultsLoader from "./defaults"
|
import defaultsLoader from "./defaults"
|
||||||
import expressLoader from "./express"
|
import expressLoader from "./express"
|
||||||
import modelsLoader from "./models"
|
import modelsLoader from "./models"
|
||||||
import passportLoader from "./passport"
|
import passportLoader from "./passport"
|
||||||
import pluginsLoader, { registerPluginModels } from "./plugins"
|
import pluginsLoader, { registerPluginModels } from "./plugins"
|
||||||
import redisLoader, { RedisConfig } from "./redis"
|
import redisLoader from "./redis"
|
||||||
import repositoriesLoader from "./repositories"
|
import repositoriesLoader from "./repositories"
|
||||||
import requestIp from "request-ip"
|
import requestIp from "request-ip"
|
||||||
import searchIndexLoader from "./search-index"
|
import searchIndexLoader from "./search-index"
|
||||||
@@ -18,7 +19,6 @@ import { ClassOrFunctionReturning } from "awilix/lib/container"
|
|||||||
import { Connection, getManager } from "typeorm"
|
import { Connection, getManager } from "typeorm"
|
||||||
import { Express, NextFunction, Request, Response } from "express"
|
import { Express, NextFunction, Request, Response } from "express"
|
||||||
import { asFunction, asValue, AwilixContainer, createContainer, Resolver } from "awilix"
|
import { asFunction, asValue, AwilixContainer, createContainer, Resolver } from "awilix"
|
||||||
import { getConfigFile } from "medusa-core-utils"
|
|
||||||
import { track } from "medusa-telemetry"
|
import { track } from "medusa-telemetry"
|
||||||
import { MedusaContainer } from "../types/global"
|
import { MedusaContainer } from "../types/global"
|
||||||
|
|
||||||
@@ -28,14 +28,6 @@ type Options = {
|
|||||||
isTest: boolean
|
isTest: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfigModule = {
|
|
||||||
projectConfig: DatabaseConfig & RedisConfig;
|
|
||||||
plugins: {
|
|
||||||
resolve: string;
|
|
||||||
options: Record<string, unknown>
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async (
|
export default async (
|
||||||
{
|
{
|
||||||
directory: rootDirectory,
|
directory: rootDirectory,
|
||||||
@@ -43,9 +35,11 @@ export default async (
|
|||||||
isTest
|
isTest
|
||||||
}: Options
|
}: Options
|
||||||
): Promise<{ container: MedusaContainer; dbConnection: Connection; app: Express }> => {
|
): 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
|
const container = createContainer() as MedusaContainer
|
||||||
|
container.register('configModule', asValue(configModule))
|
||||||
|
|
||||||
container.registerAdd = function (this: MedusaContainer, name: string, registration: typeof asFunction | typeof asValue) {
|
container.registerAdd = function (this: MedusaContainer, name: string, registration: typeof asFunction | typeof asValue) {
|
||||||
const storeKey = name + "_STORE"
|
const storeKey = name + "_STORE"
|
||||||
|
|
||||||
@@ -73,7 +67,7 @@ export default async (
|
|||||||
})
|
})
|
||||||
|
|
||||||
container.register({
|
container.register({
|
||||||
logger: asValue(Logger),
|
logger: asValue(Logger)
|
||||||
})
|
})
|
||||||
|
|
||||||
await redisLoader({ container, configModule, logger: Logger })
|
await redisLoader({ container, configModule, logger: Logger })
|
||||||
@@ -89,6 +83,7 @@ export default async (
|
|||||||
await registerPluginModels({
|
await registerPluginModels({
|
||||||
rootDirectory,
|
rootDirectory,
|
||||||
container,
|
container,
|
||||||
|
configModule
|
||||||
})
|
})
|
||||||
const pmAct = Logger.success(pmActivity, "Plugin models initialized") || {}
|
const pmAct = Logger.success(pmActivity, "Plugin models initialized") || {}
|
||||||
track("PLUGIN_MODELS_INIT_COMPLETED", { duration: pmAct.duration })
|
track("PLUGIN_MODELS_INIT_COMPLETED", { duration: pmAct.duration })
|
||||||
@@ -122,7 +117,7 @@ export default async (
|
|||||||
const expActivity = Logger.activity("Initializing express")
|
const expActivity = Logger.activity("Initializing express")
|
||||||
track("EXPRESS_INIT_STARTED")
|
track("EXPRESS_INIT_STARTED")
|
||||||
await expressLoader({ app: expressApp, configModule })
|
await expressLoader({ app: expressApp, configModule })
|
||||||
await passportLoader({ app: expressApp, container })
|
await passportLoader({ app: expressApp, container, configModule })
|
||||||
const exAct = Logger.success(expActivity, "Express intialized") || {}
|
const exAct = Logger.success(expActivity, "Express intialized") || {}
|
||||||
track("EXPRESS_INIT_COMPLETED", { duration: exAct.duration })
|
track("EXPRESS_INIT_COMPLETED", { duration: exAct.duration })
|
||||||
|
|
||||||
@@ -138,6 +133,7 @@ export default async (
|
|||||||
await pluginsLoader({
|
await pluginsLoader({
|
||||||
container,
|
container,
|
||||||
rootDirectory,
|
rootDirectory,
|
||||||
|
configModule,
|
||||||
app: expressApp,
|
app: expressApp,
|
||||||
activityId: pluginsActivity,
|
activityId: pluginsActivity,
|
||||||
})
|
})
|
||||||
@@ -152,7 +148,7 @@ export default async (
|
|||||||
|
|
||||||
const apiActivity = Logger.activity("Initializing API")
|
const apiActivity = Logger.activity("Initializing API")
|
||||||
track("API_INIT_STARTED")
|
track("API_INIT_STARTED")
|
||||||
await apiLoader({ container, rootDirectory, app: expressApp })
|
await apiLoader({ container, app: expressApp, configModule })
|
||||||
const apiAct = Logger.success(apiActivity, "API initialized") || {}
|
const apiAct = Logger.success(apiActivity, "API initialized") || {}
|
||||||
track("API_INIT_COMPLETED", { duration: apiAct.duration })
|
track("API_INIT_COMPLETED", { duration: apiAct.duration })
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import config from "../config"
|
|
||||||
import passport from "passport"
|
import passport from "passport"
|
||||||
import { AuthService } from "../services"
|
import { AuthService } from "../services"
|
||||||
import { Express } from 'express'
|
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 BearerStrategy } from "passport-http-bearer"
|
||||||
import { Strategy as JWTStrategy } from "passport-jwt"
|
import { Strategy as JWTStrategy } from "passport-jwt"
|
||||||
import { Strategy as LocalStrategy } from "passport-local"
|
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")
|
const authService = container.resolve<AuthService>("authService")
|
||||||
|
|
||||||
// For good old email password authentication
|
// 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
|
// After a user has authenticated a JWT will be placed on a cookie, all
|
||||||
// calls will be authenticated based on the JWT
|
// calls will be authenticated based on the JWT
|
||||||
|
const { jwt_secret } = configModule.projectConfig
|
||||||
passport.use(
|
passport.use(
|
||||||
new JWTStrategy(
|
new JWTStrategy(
|
||||||
{
|
{
|
||||||
jwtFromRequest: (req) => req.session.jwt,
|
jwtFromRequest: (req) => req.session.jwt,
|
||||||
secretOrKey: config.jwtSecret,
|
secretOrKey: jwt_secret,
|
||||||
},
|
},
|
||||||
async (jwtPayload, done) => {
|
async (jwtPayload, done) => {
|
||||||
return done(null, jwtPayload)
|
return done(null, jwtPayload)
|
||||||
|
|||||||
@@ -18,30 +18,30 @@ import { asValue, asClass, asFunction, aliasTo } from "awilix"
|
|||||||
import { sync as existsSync } from "fs-exists-cached"
|
import { sync as existsSync } from "fs-exists-cached"
|
||||||
import { AbstractTaxService, isTaxCalculationStrategy } from "../interfaces"
|
import { AbstractTaxService, isTaxCalculationStrategy } from "../interfaces"
|
||||||
import formatRegistrationName from "../utils/format-registration-name"
|
import formatRegistrationName from "../utils/format-registration-name"
|
||||||
import { ClassConstructor, Logger, MedusaContainer } from "../types/global"
|
import { ClassConstructor, ConfigModule, Logger, MedusaContainer } from "../types/global"
|
||||||
import { ConfigModule } from "./index"
|
|
||||||
import { MiddlewareService } from "../services"
|
import { MiddlewareService } from "../services"
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
rootDirectory: string;
|
rootDirectory: string
|
||||||
container: MedusaContainer;
|
container: MedusaContainer
|
||||||
app: Express;
|
configModule: ConfigModule
|
||||||
|
app: Express
|
||||||
activityId: string
|
activityId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PluginDetails = {
|
type PluginDetails = {
|
||||||
resolve: string;
|
resolve: string
|
||||||
name: string;
|
name: string
|
||||||
id: string;
|
id: string
|
||||||
options: Record<string, unknown>;
|
options: Record<string, unknown>
|
||||||
version: string;
|
version: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers all services in the services directory
|
* Registers all services in the services directory
|
||||||
*/
|
*/
|
||||||
export default async ({ rootDirectory, container, app, activityId }: Options): Promise<void> => {
|
export default async ({ rootDirectory, container, app, configModule, activityId }: Options): Promise<void> => {
|
||||||
const resolved = getResolvedPlugins(rootDirectory) || []
|
const resolved = getResolvedPlugins(rootDirectory, configModule) || []
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
resolved.map(async (pluginDetails) => {
|
resolved.map(async (pluginDetails) => {
|
||||||
@@ -59,13 +59,7 @@ export default async ({ rootDirectory, container, app, activityId }: Options): P
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResolvedPlugins(rootDirectory: string): undefined | PluginDetails[] {
|
function getResolvedPlugins(rootDirectory: string, configModule: ConfigModule): undefined | PluginDetails[] {
|
||||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: ConfigModule }
|
|
||||||
|
|
||||||
if (!configModule) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { plugins } = configModule
|
const { plugins } = configModule
|
||||||
|
|
||||||
const resolved = plugins.map((plugin) => {
|
const resolved = plugins.map((plugin) => {
|
||||||
@@ -90,8 +84,12 @@ function getResolvedPlugins(rootDirectory: string): undefined | PluginDetails[]
|
|||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function registerPluginModels({ rootDirectory, container }: { rootDirectory: string; container: MedusaContainer }): Promise<void> {
|
export async function registerPluginModels({
|
||||||
const resolved = getResolvedPlugins(rootDirectory) || []
|
rootDirectory,
|
||||||
|
container,
|
||||||
|
configModule
|
||||||
|
}: { rootDirectory: string; container: MedusaContainer; configModule: ConfigModule; }): Promise<void> {
|
||||||
|
const resolved = getResolvedPlugins(rootDirectory, configModule) || []
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
resolved.map(async (pluginDetails) => {
|
resolved.map(async (pluginDetails) => {
|
||||||
registerModels(pluginDetails, container)
|
registerModels(pluginDetails, container)
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
import RealRedis from "ioredis"
|
import RealRedis from "ioredis"
|
||||||
import FakeRedis from "ioredis-mock"
|
import FakeRedis from "ioredis-mock"
|
||||||
import { MedusaContainer } from "../types/global"
|
import { ConfigModule, MedusaContainer } from "../types/global"
|
||||||
import { Logger } from "../types/global"
|
import { Logger } from "../types/global"
|
||||||
|
|
||||||
export type RedisConfig = {
|
|
||||||
redis_url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
container: MedusaContainer;
|
container: MedusaContainer;
|
||||||
configModule: { projectConfig: RedisConfig };
|
configModule: ConfigModule;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import glob from "glob"
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import { asFunction } from "awilix"
|
import { asFunction } from "awilix"
|
||||||
import formatRegistrationName from "../utils/format-registration-name"
|
import formatRegistrationName from "../utils/format-registration-name"
|
||||||
import { MedusaContainer } from "../types/global"
|
import { ConfigModule, MedusaContainer } from "../types/global"
|
||||||
import { ConfigModule } from "./index"
|
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
container: MedusaContainer;
|
container: MedusaContainer;
|
||||||
configModule: ConfigModule
|
configModule: ConfigModule
|
||||||
isTest: boolean;
|
isTest?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import formatRegistrationName from "../utils/format-registration-name"
|
|||||||
type LoaderOptions = {
|
type LoaderOptions = {
|
||||||
container: AwilixContainer
|
container: AwilixContainer
|
||||||
configModule: object
|
configModule: object
|
||||||
isTest: boolean
|
isTest?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import Bull from "bull"
|
import Bull from "bull"
|
||||||
import { MockRepository, MockManager } from "medusa-test-utils"
|
import { MockRepository, MockManager } from "medusa-test-utils"
|
||||||
import EventBusService from "../event-bus"
|
import EventBusService from "../event-bus"
|
||||||
import config from "../../config"
|
import config from "../../loaders/config"
|
||||||
|
|
||||||
jest.genMockFromModule("bull")
|
jest.genMockFromModule("bull")
|
||||||
jest.mock("bull")
|
jest.mock("bull")
|
||||||
jest.mock("../../config")
|
jest.mock("../../loaders/config")
|
||||||
|
|
||||||
config.redisURI = "testhost"
|
config.redisURI = "testhost"
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ describe("InviteService", () => {
|
|||||||
userRepository: {},
|
userRepository: {},
|
||||||
inviteRepository: inviteRepo,
|
inviteRepository: inviteRepo,
|
||||||
eventBusService: EventBusServiceMock,
|
eventBusService: EventBusServiceMock,
|
||||||
|
}, {
|
||||||
|
projectConfig: { jwt_secret: 'superSecret' }
|
||||||
})
|
})
|
||||||
|
|
||||||
it("calls invite repository find", async () => {
|
it("calls invite repository find", async () => {
|
||||||
@@ -40,6 +42,8 @@ describe("InviteService", () => {
|
|||||||
userRepository: {},
|
userRepository: {},
|
||||||
inviteRepository: {},
|
inviteRepository: {},
|
||||||
eventBusService: EventBusServiceMock,
|
eventBusService: EventBusServiceMock,
|
||||||
|
}, {
|
||||||
|
projectConfig: { jwt_secret: 'superSecret' }
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validating a signed token succeeds", () => {
|
it("validating a signed token succeeds", () => {
|
||||||
@@ -108,6 +112,8 @@ describe("InviteService", () => {
|
|||||||
userRepository: userRepo,
|
userRepository: userRepo,
|
||||||
inviteRepository: inviteRepo,
|
inviteRepository: inviteRepo,
|
||||||
eventBusService: EventBusServiceMock,
|
eventBusService: EventBusServiceMock,
|
||||||
|
}, {
|
||||||
|
projectConfig: { jwt_secret: 'superSecret' }
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => jest.clearAllMocks())
|
beforeEach(() => jest.clearAllMocks())
|
||||||
@@ -200,6 +206,8 @@ describe("InviteService", () => {
|
|||||||
userRepository: {},
|
userRepository: {},
|
||||||
inviteRepository: inviteRepo,
|
inviteRepository: inviteRepo,
|
||||||
eventBusService: EventBusServiceMock,
|
eventBusService: EventBusServiceMock,
|
||||||
|
}, {
|
||||||
|
projectConfig: { jwt_secret: 'superSecret' }
|
||||||
})
|
})
|
||||||
|
|
||||||
inviteService.generateToken = jest.fn()
|
inviteService.generateToken = jest.fn()
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { BaseService } from "medusa-interfaces"
|
|||||||
import { EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
import { EventBusService, UserService } from "."
|
import { EventBusService, UserService } from "."
|
||||||
import { User } from ".."
|
import { User } from ".."
|
||||||
import config from "../config"
|
|
||||||
import { UserRoles } from "../models/user"
|
import { UserRoles } from "../models/user"
|
||||||
import { InviteRepository } from "../repositories/invite"
|
import { InviteRepository } from "../repositories/invite"
|
||||||
import { UserRepository } from "../repositories/user"
|
import { UserRepository } from "../repositories/user"
|
||||||
import { ListInvite } from "../types/invites"
|
import { ListInvite } from "../types/invites"
|
||||||
|
import { ConfigModule } from "../types/global"
|
||||||
|
|
||||||
// 7 days
|
// 7 days
|
||||||
const DEFAULT_VALID_DURATION = 1000 * 60 * 60 * 24 * 7
|
const DEFAULT_VALID_DURATION = 1000 * 60 * 60 * 24 * 7
|
||||||
@@ -32,15 +32,22 @@ class InviteService extends BaseService {
|
|||||||
private inviteRepository_: InviteRepository
|
private inviteRepository_: InviteRepository
|
||||||
private eventBus_: EventBusService
|
private eventBus_: EventBusService
|
||||||
|
|
||||||
constructor({
|
protected readonly configModule_: ConfigModule
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
{
|
||||||
manager,
|
manager,
|
||||||
userService,
|
userService,
|
||||||
userRepository,
|
userRepository,
|
||||||
inviteRepository,
|
inviteRepository,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
}: InviteServiceProps) {
|
}: InviteServiceProps,
|
||||||
|
configModule: ConfigModule
|
||||||
|
) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
this.configModule_ = configModule
|
||||||
|
|
||||||
/** @private @constant {EntityManager} */
|
/** @private @constant {EntityManager} */
|
||||||
this.manager_ = manager
|
this.manager_ = manager
|
||||||
|
|
||||||
@@ -62,13 +69,16 @@ class InviteService extends BaseService {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloned = new InviteService({
|
const cloned = new InviteService(
|
||||||
|
{
|
||||||
manager,
|
manager,
|
||||||
inviteRepository: this.inviteRepository_,
|
inviteRepository: this.inviteRepository_,
|
||||||
userService: this.userService_,
|
userService: this.userService_,
|
||||||
userRepository: this.userRepo_,
|
userRepository: this.userRepo_,
|
||||||
eventBusService: this.eventBus_,
|
eventBusService: this.eventBus_,
|
||||||
})
|
},
|
||||||
|
this.configModule_
|
||||||
|
)
|
||||||
|
|
||||||
cloned.transactionManager_ = manager
|
cloned.transactionManager_ = manager
|
||||||
|
|
||||||
@@ -76,12 +86,13 @@ class InviteService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateToken(data): string {
|
generateToken(data): string {
|
||||||
if (config.jwtSecret) {
|
const { jwt_secret } = this.configModule_.projectConfig
|
||||||
return jwt.sign(data, config.jwtSecret)
|
if (jwt_secret) {
|
||||||
|
return jwt.sign(data, jwt_secret)
|
||||||
}
|
}
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
"Please configure JwtSecret"
|
"Please configure jwt_secret"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,12 +259,13 @@ class InviteService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
verifyToken(token): JwtPayload | string {
|
verifyToken(token): JwtPayload | string {
|
||||||
if (config.jwtSecret) {
|
const { jwt_secret } = this.configModule_.projectConfig
|
||||||
return jwt.verify(token, config.jwtSecret)
|
if (jwt_secret) {
|
||||||
|
return jwt.verify(token, jwt_secret)
|
||||||
}
|
}
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
"Please configure JwtSecret"
|
"Please configure jwt_secret"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { AwilixContainer } from "awilix"
|
import { AwilixContainer } from "awilix"
|
||||||
import { Logger as _Logger } from "winston"
|
import { Logger as _Logger } from "winston"
|
||||||
|
import { LoggerOptions } from "typeorm"
|
||||||
|
|
||||||
export type ClassConstructor<T> = {
|
export type ClassConstructor<T> = {
|
||||||
new (...args: unknown[]): T
|
new (...args: unknown[]): T
|
||||||
@@ -12,3 +13,30 @@ export type MedusaContainer = AwilixContainer & {
|
|||||||
export type Logger = _Logger & {
|
export type Logger = _Logger & {
|
||||||
progress: (activityId: string, msg: string) => void
|
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"
|
chalk "^4.0.0"
|
||||||
configstore "5.0.1"
|
configstore "5.0.1"
|
||||||
core-js "^3.6.5"
|
core-js "^3.6.5"
|
||||||
dotenv "^8.2.0"
|
|
||||||
execa "^5.1.1"
|
execa "^5.1.1"
|
||||||
fs-exists-cached "^1.0.0"
|
fs-exists-cached "^1.0.0"
|
||||||
fs-extra "^10.0.0"
|
fs-extra "^10.0.0"
|
||||||
@@ -3242,11 +3241,6 @@ dot-prop@^5.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-obj "^2.0.0"
|
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:
|
duplexer3@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||||
|
|||||||
Reference in new issue
Block a user