refactor(medusa): Loaders to TS (#1288)
* refactor(medusa): Loaders * refactor(medusa): Improve MedusaContainer typings * refactor(medusa): Improve MedusaContainer typings
This commit is contained in:
committed by
GitHub
parent
ab2d81f786
commit
5f9197a656
@@ -5,19 +5,19 @@
|
||||
/packages/medusa/src/subscribers/notification.js
|
||||
/packages/medusa/src/subscribers/order.js
|
||||
/packages/medusa/src/subscribers/product.js
|
||||
/packages/medusa/src/loaders/api.js
|
||||
/packages/medusa/src/loaders/database.js
|
||||
/packages/medusa/src/loaders/defaults.js
|
||||
/packages/medusa/src/loaders/express.js
|
||||
/packages/medusa/src/loaders/index.js
|
||||
/packages/medusa/src/loaders/logger.js
|
||||
/packages/medusa/src/loaders/models.js
|
||||
/packages/medusa/src/loaders/passport.js
|
||||
/packages/medusa/src/loaders/plugins.js
|
||||
/packages/medusa/src/loaders/redis.js
|
||||
/packages/medusa/src/loaders/repositories.js
|
||||
/packages/medusa/src/loaders/services.js
|
||||
/packages/medusa/src/loaders/subscribers.js
|
||||
/packages/medusa/src/loaders/api.ts
|
||||
/packages/medusa/src/loaders/database.ts
|
||||
/packages/medusa/src/loaders/defaults.ts
|
||||
/packages/medusa/src/loaders/express.ts
|
||||
/packages/medusa/src/loaders/index.ts
|
||||
/packages/medusa/src/loaders/logger.ts
|
||||
/packages/medusa/src/loaders/models.ts
|
||||
/packages/medusa/src/loaders/passport.ts
|
||||
/packages/medusa/src/loaders/plugins.ts
|
||||
/packages/medusa/src/loaders/redis.ts
|
||||
/packages/medusa/src/loaders/repositories.ts
|
||||
/packages/medusa/src/loaders/services.ts
|
||||
/packages/medusa/src/loaders/subscribers.ts
|
||||
/packages/medusa/src/api/routes/admin/auth
|
||||
/packages/medusa/src/api/routes/admin/collections
|
||||
/packages/medusa/src/api/routes/store/carts
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { Express } from 'express'
|
||||
import bodyParser from "body-parser"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import routes from "../api"
|
||||
import { AwilixContainer } from "awilix"
|
||||
|
||||
export default async ({ app, rootDirectory, container }) => {
|
||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`)
|
||||
type Options = {
|
||||
app: Express;
|
||||
rootDirectory: string;
|
||||
container: AwilixContainer
|
||||
}
|
||||
|
||||
export default async ({ app, rootDirectory, container }: Options) => {
|
||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: Record<string, unknown> }
|
||||
const config = (configModule && configModule.projectConfig) || {}
|
||||
|
||||
app.use(bodyParser.json())
|
||||
@@ -1,8 +1,22 @@
|
||||
import { createConnection } from "typeorm"
|
||||
|
||||
import { Connection, createConnection, LoggerOptions } from "typeorm"
|
||||
import { ShortenedNamingStrategy } from "../utils/naming-strategy"
|
||||
import { AwilixContainer } from "awilix"
|
||||
import { ConnectionOptions } from "typeorm/connection/ConnectionOptions"
|
||||
|
||||
export default async ({ container, configModule }) => {
|
||||
export type DatabaseConfig = {
|
||||
database_type: string;
|
||||
database_url?: string;
|
||||
database_database?: string;
|
||||
database_extra?: Record<string, unknown>;
|
||||
database_logging: LoggerOptions
|
||||
}
|
||||
|
||||
type Options = {
|
||||
configModule: { projectConfig: DatabaseConfig };
|
||||
container: AwilixContainer
|
||||
}
|
||||
|
||||
export default async ({ container, configModule }: Options): Promise<Connection> => {
|
||||
const entities = container.resolve("db_entities")
|
||||
|
||||
const isSqlite = configModule.projectConfig.database_type === "sqlite"
|
||||
@@ -15,7 +29,7 @@ export default async ({ container, configModule }) => {
|
||||
entities,
|
||||
namingStrategy: new ShortenedNamingStrategy(),
|
||||
logging: configModule.projectConfig.database_logging || false,
|
||||
})
|
||||
} as ConnectionOptions)
|
||||
|
||||
if (isSqlite) {
|
||||
await connection.query(`PRAGMA foreign_keys = OFF`)
|
||||
@@ -1,10 +1,23 @@
|
||||
import { BasePaymentService, BaseNotificationService, BaseFulfillmentService } from 'medusa-interfaces'
|
||||
import { currencies } from "../utils/currencies"
|
||||
import { countries } from "../utils/countries"
|
||||
import { AwilixContainer } from "awilix"
|
||||
import { Logger } from "../types/global"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { CountryRepository } from "../repositories/country"
|
||||
import {
|
||||
FulfillmentProviderService,
|
||||
NotificationService,
|
||||
PaymentProviderService,
|
||||
ShippingProfileService,
|
||||
StoreService, TaxProviderService,
|
||||
} from "../services"
|
||||
import { CurrencyRepository } from "../repositories/currency"
|
||||
import { AbstractTaxService } from "../interfaces"
|
||||
|
||||
const silentResolution = (container, name, logger) => {
|
||||
const silentResolution = <T>(container: AwilixContainer, name: string, logger: Logger): T | never | undefined => {
|
||||
try {
|
||||
const resolved = container.resolve(name)
|
||||
return resolved
|
||||
return container.resolve<T>(name)
|
||||
} catch (err) {
|
||||
if (err.name !== "AwilixResolutionError") {
|
||||
throw err
|
||||
@@ -27,19 +40,20 @@ const silentResolution = (container, name, logger) => {
|
||||
`You don't have any ${identifier} provider plugins installed. You may want to add one to your project.`
|
||||
)
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export default async ({ container }) => {
|
||||
const storeService = container.resolve("storeService")
|
||||
const currencyRepository = container.resolve("currencyRepository")
|
||||
const countryRepository = container.resolve("countryRepository")
|
||||
const profileService = container.resolve("shippingProfileService")
|
||||
const logger = container.resolve("logger")
|
||||
export default async ({ container }: { container: AwilixContainer }): Promise<void> => {
|
||||
const storeService = container.resolve<StoreService>("storeService")
|
||||
const currencyRepository = container.resolve<typeof CurrencyRepository>("currencyRepository")
|
||||
const countryRepository = container.resolve<typeof CountryRepository>("countryRepository")
|
||||
const profileService = container.resolve<ShippingProfileService>("shippingProfileService")
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
|
||||
const entityManager = container.resolve("manager")
|
||||
const entityManager = container.resolve<EntityManager>("manager")
|
||||
|
||||
await entityManager.transaction(async (manager) => {
|
||||
await entityManager.transaction(async (manager: EntityManager) => {
|
||||
const countryRepo = manager.getCustomRepository(countryRepository)
|
||||
const hasCountries = await countryRepo.findOne()
|
||||
if (!hasCountries) {
|
||||
@@ -52,7 +66,7 @@ export default async ({ container }) => {
|
||||
const name = c.name.toUpperCase()
|
||||
const display = c.name
|
||||
|
||||
await manager.queryRunner.query(query, [
|
||||
await manager.queryRunner?.query(query, [
|
||||
iso2,
|
||||
iso3,
|
||||
numeric,
|
||||
@@ -63,7 +77,7 @@ export default async ({ container }) => {
|
||||
}
|
||||
})
|
||||
|
||||
await entityManager.transaction(async (manager) => {
|
||||
await entityManager.transaction(async (manager: EntityManager) => {
|
||||
const currencyRepo = manager.getCustomRepository(currencyRepository)
|
||||
const hasCurrencies = await currencyRepo.findOne()
|
||||
if (!hasCurrencies) {
|
||||
@@ -75,45 +89,42 @@ export default async ({ container }) => {
|
||||
const nat = c.symbol_native
|
||||
const name = c.name
|
||||
|
||||
await manager.queryRunner.query(query, [code, sym, nat, name])
|
||||
await manager.queryRunner?.query(query, [code, sym, nat, name])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await entityManager.transaction(async (manager) => {
|
||||
await entityManager.transaction(async (manager: EntityManager) => {
|
||||
await storeService.withTransaction(manager).create()
|
||||
|
||||
const pProviderService = container.resolve("paymentProviderService")
|
||||
|
||||
const payProviders =
|
||||
silentResolution(container, "paymentProviders", logger) || []
|
||||
|
||||
silentResolution<typeof BasePaymentService[]>(container, "paymentProviders", logger) || []
|
||||
const payIds = payProviders.map((p) => p.getIdentifier())
|
||||
|
||||
const pProviderService = container.resolve<PaymentProviderService>("paymentProviderService")
|
||||
await pProviderService.registerInstalledProviders(payIds)
|
||||
|
||||
const nProviderService = container.resolve("notificationService")
|
||||
|
||||
const notiProviders =
|
||||
silentResolution(container, "notificationProviders", logger) || []
|
||||
|
||||
silentResolution<typeof BaseNotificationService[]>(container, "notificationProviders", logger) || []
|
||||
const notiIds = notiProviders.map((p) => p.getIdentifier())
|
||||
|
||||
const nProviderService = container.resolve<NotificationService>("notificationService")
|
||||
await nProviderService.registerInstalledProviders(notiIds)
|
||||
|
||||
const fProviderService = container.resolve("fulfillmentProviderService")
|
||||
|
||||
const fulfilProviders =
|
||||
silentResolution(container, "fulfillmentProviders", logger) || []
|
||||
|
||||
silentResolution<typeof BaseFulfillmentService[]>(container, "fulfillmentProviders", logger) || []
|
||||
const fulfilIds = fulfilProviders.map((p) => p.getIdentifier())
|
||||
|
||||
const fProviderService = container.resolve<FulfillmentProviderService>("fulfillmentProviderService")
|
||||
await fProviderService.registerInstalledProviders(fulfilIds)
|
||||
|
||||
const tProviderService = container.resolve("taxProviderService")
|
||||
|
||||
const taxProviders =
|
||||
silentResolution(container, "taxProviders", logger) || []
|
||||
|
||||
silentResolution<AbstractTaxService[]>(container, "taxProviders", logger) || []
|
||||
const taxIds = taxProviders.map((p) => p.getIdentifier())
|
||||
|
||||
const tProviderService = container.resolve<TaxProviderService>("taxProviderService")
|
||||
await tProviderService.registerInstalledProviders(taxIds)
|
||||
|
||||
await profileService.withTransaction(manager).createDefault()
|
||||
@@ -1,13 +1,19 @@
|
||||
import { Express } from 'express'
|
||||
import session from "express-session"
|
||||
import cookieParser from "cookie-parser"
|
||||
import morgan from "morgan"
|
||||
import redis from "redis"
|
||||
import redis, { RedisConfig } from "redis"
|
||||
import createStore from "connect-redis"
|
||||
|
||||
import config from "../config"
|
||||
|
||||
export default async ({ app, configModule }) => {
|
||||
let sameSite = false
|
||||
type Options = {
|
||||
app: Express;
|
||||
configModule: { projectConfig: RedisConfig }
|
||||
}
|
||||
|
||||
export default async ({ app, configModule }: Options): Promise<Express> => {
|
||||
let sameSite: string | boolean = false
|
||||
let secure = false
|
||||
if (
|
||||
process.env.NODE_ENV === "production" ||
|
||||
@@ -17,7 +23,7 @@ export default async ({ app, configModule }) => {
|
||||
sameSite = "none"
|
||||
}
|
||||
|
||||
let sessionOpts = {
|
||||
const sessionOpts = {
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
cookieName: "session",
|
||||
@@ -28,6 +34,7 @@ export default async ({ app, configModule }) => {
|
||||
secure,
|
||||
maxAge: 10 * 60 * 60 * 1000,
|
||||
},
|
||||
store: null
|
||||
}
|
||||
|
||||
if (configModule.projectConfig.redis_url) {
|
||||
@@ -1,35 +1,58 @@
|
||||
import { asValue, createContainer } from "awilix"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import { track } from "medusa-telemetry"
|
||||
import "reflect-metadata"
|
||||
import requestIp from "request-ip"
|
||||
import { getManager } from "typeorm"
|
||||
import apiLoader from "./api"
|
||||
import databaseLoader from "./database"
|
||||
import defaultsLoader from "./defaults"
|
||||
import expressLoader from "./express"
|
||||
import Logger from "./logger"
|
||||
import apiLoader from "./api"
|
||||
import databaseLoader, { DatabaseConfig } 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 from "./redis"
|
||||
import redisLoader, { RedisConfig } from "./redis"
|
||||
import repositoriesLoader from "./repositories"
|
||||
import requestIp from "request-ip"
|
||||
import searchIndexLoader from "./search-index"
|
||||
import servicesLoader from "./services"
|
||||
import strategiesLoader from "./strategies"
|
||||
import subscribersLoader from "./subscribers"
|
||||
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"
|
||||
|
||||
export default async ({ directory: rootDirectory, expressApp, isTest }) => {
|
||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`)
|
||||
type Options = {
|
||||
directory: string;
|
||||
expressApp: Express;
|
||||
isTest: boolean
|
||||
}
|
||||
|
||||
const container = createContainer()
|
||||
container.registerAdd = function (name, registration) {
|
||||
export type ConfigModule = {
|
||||
projectConfig: DatabaseConfig & RedisConfig;
|
||||
plugins: {
|
||||
resolve: string;
|
||||
options: Record<string, unknown>
|
||||
}[];
|
||||
}
|
||||
|
||||
export default async (
|
||||
{
|
||||
directory: rootDirectory,
|
||||
expressApp,
|
||||
isTest
|
||||
}: Options
|
||||
): Promise<{ container: MedusaContainer; dbConnection: Connection; app: Express }> => {
|
||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: ConfigModule }
|
||||
|
||||
const container = createContainer() as MedusaContainer
|
||||
container.registerAdd = function (this: MedusaContainer, name: string, registration: typeof asFunction | typeof asValue) {
|
||||
const storeKey = name + "_STORE"
|
||||
|
||||
if (this.registrations[storeKey] === undefined) {
|
||||
this.register(storeKey, asValue([]))
|
||||
this.register(storeKey, asValue([] as Resolver<unknown>[]))
|
||||
}
|
||||
const store = this.resolve(storeKey)
|
||||
const store = this.resolve(storeKey) as (ClassOrFunctionReturning<unknown> | Resolver<unknown>)[]
|
||||
|
||||
if (this.registrations[name] === undefined) {
|
||||
this.register(name, asArray(store))
|
||||
@@ -40,14 +63,12 @@ export default async ({ directory: rootDirectory, expressApp, isTest }) => {
|
||||
}.bind(container)
|
||||
|
||||
// Add additional information to context of request
|
||||
expressApp.use((req, res, next) => {
|
||||
const ipAddress = requestIp.getClientIp(req)
|
||||
expressApp.use((req: Request, res: Response, next: NextFunction) => {
|
||||
const ipAddress = requestIp.getClientIp(req) as string
|
||||
|
||||
const context = {
|
||||
(req as any).request_context = {
|
||||
ip_address: ipAddress,
|
||||
}
|
||||
|
||||
req.request_context = context
|
||||
next()
|
||||
})
|
||||
|
||||
@@ -59,7 +80,7 @@ export default async ({ directory: rootDirectory, expressApp, isTest }) => {
|
||||
|
||||
const modelsActivity = Logger.activity("Initializing models")
|
||||
track("MODELS_INIT_STARTED")
|
||||
modelsLoader({ container, activityId: modelsActivity, isTest })
|
||||
modelsLoader({ container })
|
||||
const mAct = Logger.success(modelsActivity, "Models initialized") || {}
|
||||
track("MODELS_INIT_COMPLETED", { duration: mAct.duration })
|
||||
|
||||
@@ -68,71 +89,47 @@ export default async ({ directory: rootDirectory, expressApp, isTest }) => {
|
||||
await registerPluginModels({
|
||||
rootDirectory,
|
||||
container,
|
||||
activityId: pmActivity,
|
||||
})
|
||||
const pmAct = Logger.success(pmActivity, "Plugin models initialized") || {}
|
||||
track("PLUGIN_MODELS_INIT_COMPLETED", { duration: pmAct.duration })
|
||||
|
||||
const repoActivity = Logger.activity("Initializing repositories")
|
||||
track("REPOSITORIES_INIT_STARTED")
|
||||
repositoriesLoader({ container, activityId: repoActivity, isTest }) || {}
|
||||
repositoriesLoader({ container })
|
||||
const rAct = Logger.success(repoActivity, "Repositories initialized") || {}
|
||||
track("REPOSITORIES_INIT_COMPLETED", { duration: rAct.duration })
|
||||
|
||||
const dbActivity = Logger.activity("Initializing database")
|
||||
track("DATABASE_INIT_STARTED")
|
||||
const dbConnection = await databaseLoader({
|
||||
container,
|
||||
configModule,
|
||||
activityId: dbActivity,
|
||||
isTest,
|
||||
})
|
||||
const dbConnection = await databaseLoader({ container, configModule })
|
||||
const dbAct = Logger.success(dbActivity, "Database initialized") || {}
|
||||
track("DATABASE_INIT_COMPLETED", { duration: dbAct.duration })
|
||||
|
||||
container.register({
|
||||
manager: asValue(dbConnection.manager),
|
||||
})
|
||||
container.register({ manager: asValue(dbConnection.manager), })
|
||||
|
||||
const stratActivity = Logger.activity("Initializing strategies")
|
||||
track("STRATEGIES_INIT_STARTED")
|
||||
strategiesLoader({
|
||||
container,
|
||||
configModule,
|
||||
activityId: stratActivity,
|
||||
isTest,
|
||||
})
|
||||
strategiesLoader({ container, configModule, isTest })
|
||||
const stratAct = Logger.success(stratActivity, "Strategies initialized") || {}
|
||||
track("STRATEGIES_INIT_COMPLETED", { duration: stratAct.duration })
|
||||
|
||||
const servicesActivity = Logger.activity("Initializing services")
|
||||
track("SERVICES_INIT_STARTED")
|
||||
servicesLoader({
|
||||
container,
|
||||
configModule,
|
||||
activityId: servicesActivity,
|
||||
isTest,
|
||||
})
|
||||
servicesLoader({ container, configModule, isTest })
|
||||
const servAct = Logger.success(servicesActivity, "Services initialized") || {}
|
||||
track("SERVICES_INIT_COMPLETED", { duration: servAct.duration })
|
||||
|
||||
const expActivity = Logger.activity("Initializing express")
|
||||
track("EXPRESS_INIT_STARTED")
|
||||
await expressLoader({
|
||||
app: expressApp,
|
||||
configModule,
|
||||
activityId: expActivity,
|
||||
})
|
||||
await passportLoader({ app: expressApp, container, activityId: expActivity })
|
||||
await expressLoader({ app: expressApp, configModule })
|
||||
await passportLoader({ app: expressApp, container })
|
||||
const exAct = Logger.success(expActivity, "Express intialized") || {}
|
||||
track("EXPRESS_INIT_COMPLETED", { duration: exAct.duration })
|
||||
|
||||
// Add the registered services to the request scope
|
||||
expressApp.use((req, res, next) => {
|
||||
container.register({
|
||||
manager: asValue(getManager()),
|
||||
})
|
||||
req.scope = container.createScope()
|
||||
expressApp.use((req: Request, res: Response, next: NextFunction) => {
|
||||
container.register({ manager: asValue(getManager()) });
|
||||
(req as any).scope = container.createScope()
|
||||
next()
|
||||
})
|
||||
|
||||
@@ -149,39 +146,36 @@ export default async ({ directory: rootDirectory, expressApp, isTest }) => {
|
||||
|
||||
const subActivity = Logger.activity("Initializing subscribers")
|
||||
track("SUBSCRIBERS_INIT_STARTED")
|
||||
subscribersLoader({ container, activityId: subActivity })
|
||||
subscribersLoader({ container })
|
||||
const subAct = Logger.success(subActivity, "Subscribers initialized") || {}
|
||||
track("SUBSCRIBERS_INIT_COMPLETED", { duration: subAct.duration })
|
||||
|
||||
const apiActivity = Logger.activity("Initializing API")
|
||||
track("API_INIT_STARTED")
|
||||
await apiLoader({
|
||||
container,
|
||||
rootDirectory,
|
||||
app: expressApp,
|
||||
activityId: apiActivity,
|
||||
})
|
||||
await apiLoader({ container, rootDirectory, app: expressApp })
|
||||
const apiAct = Logger.success(apiActivity, "API initialized") || {}
|
||||
track("API_INIT_COMPLETED", { duration: apiAct.duration })
|
||||
|
||||
const defaultsActivity = Logger.activity("Initializing defaults")
|
||||
track("DEFAULTS_INIT_STARTED")
|
||||
await defaultsLoader({ container, activityId: defaultsActivity })
|
||||
await defaultsLoader({ container })
|
||||
const dAct = Logger.success(defaultsActivity, "Defaults initialized") || {}
|
||||
track("DEFAULTS_INIT_COMPLETED", { duration: dAct.duration })
|
||||
|
||||
const searchActivity = Logger.activity("Initializing search engine indexing")
|
||||
track("SEARCH_ENGINE_INDEXING_STARTED")
|
||||
searchIndexLoader({ container, activityId: searchActivity })
|
||||
await searchIndexLoader({ container })
|
||||
const searchAct = Logger.success(searchActivity, "Indexing completed") || {}
|
||||
track("SEARCH_ENGINE_INDEXING_COMPLETED", { duration: searchAct.duration })
|
||||
|
||||
return { container, dbConnection, app: expressApp }
|
||||
}
|
||||
|
||||
function asArray(resolvers) {
|
||||
function asArray(
|
||||
resolvers: (ClassOrFunctionReturning<unknown> | Resolver<unknown>)[]
|
||||
): { resolve: (container: AwilixContainer) => unknown[] } {
|
||||
return {
|
||||
resolve: (container, opts) =>
|
||||
resolvers.map((r) => container.build(r, opts)),
|
||||
resolve: (container: AwilixContainer) =>
|
||||
resolvers.map((resolver) => container.build(resolver)),
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
import logger from "@medusajs/medusa-cli/dist/reporter"
|
||||
|
||||
export default logger
|
||||
@@ -1,38 +1,38 @@
|
||||
import formatRegistrationName from "../utils/format-registration-name"
|
||||
import glob from "glob"
|
||||
import path from "path"
|
||||
import { ClassConstructor, MedusaContainer } from "../types/global"
|
||||
import { EntitySchema } from "typeorm"
|
||||
import { asClass, asValue } from "awilix"
|
||||
|
||||
import formatRegistrationName from "../utils/format-registration-name"
|
||||
import { asClass, asValue, AwilixContainer } from "awilix"
|
||||
|
||||
/**
|
||||
* Registers all models in the model directory
|
||||
*/
|
||||
export default ({ container }, config = { register: true }) => {
|
||||
export default ({ container }: { container: MedusaContainer }, config = { register: true }) => {
|
||||
const corePath = "../models/*.js"
|
||||
const coreFull = path.join(__dirname, corePath)
|
||||
|
||||
const toReturn = []
|
||||
const models: (ClassConstructor<unknown> | EntitySchema)[] = []
|
||||
|
||||
const core = glob.sync(coreFull, { cwd: __dirname })
|
||||
core.forEach((fn) => {
|
||||
const loaded = require(fn)
|
||||
const loaded = require(fn) as ClassConstructor<unknown> | EntitySchema
|
||||
|
||||
Object.entries(loaded).map(([key, val]) => {
|
||||
Object.entries(loaded).map(([key, val]: [string, ClassConstructor<unknown> | EntitySchema]) => {
|
||||
if (typeof val === "function" || val instanceof EntitySchema) {
|
||||
if (config.register) {
|
||||
const name = formatRegistrationName(fn)
|
||||
container.register({
|
||||
[name]: asClass(val),
|
||||
[name]: asClass(val as ClassConstructor<unknown>),
|
||||
})
|
||||
|
||||
container.registerAdd("db_entities", asValue(val))
|
||||
}
|
||||
|
||||
toReturn.push(val)
|
||||
models.push(val)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return toReturn
|
||||
return models
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
import config from "../config"
|
||||
import passport from "passport"
|
||||
import { Strategy as LocalStrategy } from "passport-local"
|
||||
import { AuthService } from "../services"
|
||||
import { Express } from 'express'
|
||||
import { MedusaContainer } from "../types/global"
|
||||
import { Strategy as BearerStrategy } from "passport-http-bearer"
|
||||
import { Strategy as JWTStrategy } from "passport-jwt"
|
||||
import config from "../config"
|
||||
import { Strategy as LocalStrategy } from "passport-local"
|
||||
|
||||
export default async ({ app, container }) => {
|
||||
const authService = container.resolve("authService")
|
||||
const userService = container.resolve("userService")
|
||||
export default async ({ app, container }: { app: Express; container: MedusaContainer }): Promise<void> => {
|
||||
const authService = container.resolve<AuthService>("authService")
|
||||
|
||||
// For good old email password authentication
|
||||
passport.use(
|
||||
@@ -17,7 +19,7 @@ export default async ({ app, container }) => {
|
||||
},
|
||||
async (email, password, done) => {
|
||||
try {
|
||||
const { success, user } = authService.authenticate(email, password)
|
||||
const { success, user } = await authService.authenticate(email, password)
|
||||
if (success) {
|
||||
return done(null, user)
|
||||
} else {
|
||||
@@ -1,4 +1,5 @@
|
||||
import glob from "glob"
|
||||
import { Express } from 'express'
|
||||
import { EntitySchema } from "typeorm"
|
||||
import {
|
||||
BaseService,
|
||||
@@ -15,16 +16,32 @@ import path from "path"
|
||||
import fs from "fs"
|
||||
import { asValue, asClass, asFunction, aliasTo } from "awilix"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
|
||||
import { AbstractTaxService } from "../interfaces/tax-service"
|
||||
import { isTaxCalculationStrategy } from "../interfaces/tax-calculation-strategy"
|
||||
import { AbstractTaxService, isTaxCalculationStrategy } from "../interfaces"
|
||||
import formatRegistrationName from "../utils/format-registration-name"
|
||||
import { ClassConstructor, Logger, MedusaContainer } from "../types/global"
|
||||
import { ConfigModule } from "./index"
|
||||
import { MiddlewareService } from "../services"
|
||||
|
||||
type Options = {
|
||||
rootDirectory: string;
|
||||
container: MedusaContainer;
|
||||
app: Express;
|
||||
activityId: string
|
||||
}
|
||||
|
||||
type PluginDetails = {
|
||||
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 }) => {
|
||||
const resolved = getResolvedPlugins(rootDirectory)
|
||||
export default async ({ rootDirectory, container, app, activityId }: Options): Promise<void> => {
|
||||
const resolved = getResolvedPlugins(rootDirectory) || []
|
||||
|
||||
await Promise.all(
|
||||
resolved.map(async (pluginDetails) => {
|
||||
@@ -42,8 +59,8 @@ export default async ({ rootDirectory, container, app, activityId }) => {
|
||||
)
|
||||
}
|
||||
|
||||
function getResolvedPlugins(rootDirectory) {
|
||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`)
|
||||
function getResolvedPlugins(rootDirectory: string): undefined | PluginDetails[] {
|
||||
const { configModule } = getConfigFile(rootDirectory, `medusa-config`) as { configModule: ConfigModule }
|
||||
|
||||
if (!configModule) {
|
||||
return
|
||||
@@ -73,8 +90,8 @@ function getResolvedPlugins(rootDirectory) {
|
||||
return resolved
|
||||
}
|
||||
|
||||
export async function registerPluginModels({ rootDirectory, container }) {
|
||||
const resolved = getResolvedPlugins(rootDirectory)
|
||||
export async function registerPluginModels({ rootDirectory, container }: { rootDirectory: string; container: MedusaContainer }): Promise<void> {
|
||||
const resolved = getResolvedPlugins(rootDirectory) || []
|
||||
await Promise.all(
|
||||
resolved.map(async (pluginDetails) => {
|
||||
registerModels(pluginDetails, container)
|
||||
@@ -82,7 +99,7 @@ export async function registerPluginModels({ rootDirectory, container }) {
|
||||
)
|
||||
}
|
||||
|
||||
async function runLoaders(pluginDetails, container) {
|
||||
async function runLoaders(pluginDetails: PluginDetails, container: MedusaContainer): Promise<void> {
|
||||
const loaderFiles = glob.sync(
|
||||
`${pluginDetails.resolve}/loaders/[!__]*.js`,
|
||||
{}
|
||||
@@ -95,7 +112,7 @@ async function runLoaders(pluginDetails, container) {
|
||||
await module(container, pluginDetails.options)
|
||||
}
|
||||
} catch (err) {
|
||||
const logger = container.resolve("logger")
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
logger.warn(`Running loader failed: ${err.message}`)
|
||||
return Promise.resolve()
|
||||
}
|
||||
@@ -103,12 +120,12 @@ async function runLoaders(pluginDetails, container) {
|
||||
)
|
||||
}
|
||||
|
||||
function registerMedusaApi(pluginDetails, container) {
|
||||
function registerMedusaApi(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
registerMedusaMiddleware(pluginDetails, container)
|
||||
registerStrategies(pluginDetails, container)
|
||||
}
|
||||
|
||||
function registerStrategies(pluginDetails, container) {
|
||||
function registerStrategies(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
let module
|
||||
try {
|
||||
const path = `${pluginDetails.resolve}/strategies/tax-calculation`
|
||||
@@ -128,14 +145,14 @@ function registerStrategies(pluginDetails, container) {
|
||||
).singleton(),
|
||||
})
|
||||
} else {
|
||||
const logger = container.resolve("logger")
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
logger.warn(
|
||||
`${pluginDetails.resolve}/strategies/tax-calculation did not export a class that implements ITaxCalculationStrategy. Your Medusa server will still work, but if you have written custom tax calculation logic it will not be used. Make sure to implement the ITaxCalculationStrategy interface.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function registerMedusaMiddleware(pluginDetails, container) {
|
||||
function registerMedusaMiddleware(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
let module
|
||||
try {
|
||||
module = require(`${pluginDetails.resolve}/api/medusa-middleware`).default
|
||||
@@ -143,7 +160,7 @@ function registerMedusaMiddleware(pluginDetails, container) {
|
||||
return
|
||||
}
|
||||
|
||||
const middlewareService = container.resolve("middlewareService")
|
||||
const middlewareService = container.resolve<MiddlewareService>("middlewareService")
|
||||
if (module.postAuthentication) {
|
||||
middlewareService.addPostAuthentication(
|
||||
module.postAuthentication,
|
||||
@@ -163,8 +180,8 @@ function registerMedusaMiddleware(pluginDetails, container) {
|
||||
}
|
||||
}
|
||||
|
||||
function registerCoreRouters(pluginDetails, container) {
|
||||
const middlewareService = container.resolve("middlewareService")
|
||||
function registerCoreRouters(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
const middlewareService = container.resolve<MiddlewareService>("middlewareService")
|
||||
const { resolve } = pluginDetails
|
||||
const adminFiles = glob.sync(`${resolve}/api/admin/[!__]*.js`, {})
|
||||
const storeFiles = glob.sync(`${resolve}/api/store/[!__]*.js`, {})
|
||||
@@ -190,13 +207,13 @@ function registerCoreRouters(pluginDetails, container) {
|
||||
* Registers the plugin's api routes.
|
||||
*/
|
||||
function registerApi(
|
||||
pluginDetails,
|
||||
app,
|
||||
pluginDetails: PluginDetails,
|
||||
app: Express,
|
||||
rootDirectory = "",
|
||||
container,
|
||||
activityId
|
||||
) {
|
||||
const logger = container.resolve("logger")
|
||||
container: MedusaContainer,
|
||||
activityId: string
|
||||
): Express {
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
logger.progress(
|
||||
activityId,
|
||||
`Registering custom endpoints for ${pluginDetails.name}`
|
||||
@@ -230,7 +247,7 @@ function registerApi(
|
||||
* registered
|
||||
* @return {void}
|
||||
*/
|
||||
async function registerServices(pluginDetails, container) {
|
||||
async function registerServices(pluginDetails: PluginDetails, container: MedusaContainer): Promise<void> {
|
||||
const files = glob.sync(`${pluginDetails.resolve}/services/[!__]*`, {})
|
||||
await Promise.all(
|
||||
files.map(async (fn) => {
|
||||
@@ -238,7 +255,7 @@ async function registerServices(pluginDetails, container) {
|
||||
const name = formatRegistrationName(fn)
|
||||
|
||||
if (!(loaded.prototype instanceof BaseService)) {
|
||||
const logger = container.resolve("logger")
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
const message = `Services must inherit from BaseService, please check ${fn}`
|
||||
logger.error(message)
|
||||
throw new Error(message)
|
||||
@@ -260,9 +277,9 @@ async function registerServices(pluginDetails, container) {
|
||||
[`pp_${loaded.identifier}`]: aliasTo(name),
|
||||
})
|
||||
} else if (loaded.prototype instanceof OauthService) {
|
||||
const oauthService = container.resolve("oauthService")
|
||||
|
||||
const appDetails = loaded.getAppDetails(pluginDetails.options)
|
||||
|
||||
const oauthService = container.resolve<typeof OauthService>("oauthService")
|
||||
await oauthService.registerOauthApp(appDetails)
|
||||
|
||||
const name = appDetails.application_name
|
||||
@@ -350,12 +367,11 @@ async function registerServices(pluginDetails, container) {
|
||||
* registered
|
||||
* @return {void}
|
||||
*/
|
||||
function registerSubscribers(pluginDetails, container) {
|
||||
function registerSubscribers(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
const files = glob.sync(`${pluginDetails.resolve}/subscribers/*.js`, {})
|
||||
files.forEach((fn) => {
|
||||
const loaded = require(fn).default
|
||||
|
||||
const name = formatRegistrationName(fn)
|
||||
container.build(
|
||||
asFunction(
|
||||
(cradle) => new loaded(cradle, pluginDetails.options)
|
||||
@@ -373,12 +389,12 @@ function registerSubscribers(pluginDetails, container) {
|
||||
* registered
|
||||
* @return {void}
|
||||
*/
|
||||
function registerRepositories(pluginDetails, container) {
|
||||
function registerRepositories(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
const files = glob.sync(`${pluginDetails.resolve}/repositories/*.js`, {})
|
||||
files.forEach((fn) => {
|
||||
const loaded = require(fn)
|
||||
const loaded = require(fn) as ClassConstructor<unknown>
|
||||
|
||||
Object.entries(loaded).map(([key, val]) => {
|
||||
Object.entries(loaded).map(([, val]: [string, ClassConstructor<unknown>]) => {
|
||||
if (typeof val === "function") {
|
||||
const name = formatRegistrationName(fn)
|
||||
container.register({
|
||||
@@ -400,12 +416,12 @@ function registerRepositories(pluginDetails, container) {
|
||||
* registered
|
||||
* @return {void}
|
||||
*/
|
||||
function registerModels(pluginDetails, container) {
|
||||
function registerModels(pluginDetails: PluginDetails, container: MedusaContainer): void {
|
||||
const files = glob.sync(`${pluginDetails.resolve}/models/*.js`, {})
|
||||
files.forEach((fn) => {
|
||||
const loaded = require(fn)
|
||||
const loaded = require(fn) as ClassConstructor<unknown> | EntitySchema
|
||||
|
||||
Object.entries(loaded).map(([key, val]) => {
|
||||
Object.entries(loaded).map(([, val]: [string, ClassConstructor<unknown> | EntitySchema]) => {
|
||||
if (typeof val === "function" || val instanceof EntitySchema) {
|
||||
const name = formatRegistrationName(fn)
|
||||
container.register({
|
||||
@@ -419,7 +435,7 @@ function registerModels(pluginDetails, container) {
|
||||
}
|
||||
|
||||
// TODO: Create unique id for each plugin
|
||||
function createPluginId(name) {
|
||||
function createPluginId(name: string): string {
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -431,7 +447,13 @@ function createPluginId(name) {
|
||||
* the name of the folder where the plugin is contained.
|
||||
* @return {object} the plugin details
|
||||
*/
|
||||
function resolvePlugin(pluginName) {
|
||||
function resolvePlugin(pluginName: string): {
|
||||
resolve: string;
|
||||
id: string;
|
||||
name: string;
|
||||
options: Record<string, unknown>
|
||||
version: string;
|
||||
} {
|
||||
// Only find plugins when we're not given an absolute path
|
||||
if (!existsSync(pluginName)) {
|
||||
// Find the plugin in the local plugins folder
|
||||
@@ -487,6 +509,7 @@ function resolvePlugin(pluginName) {
|
||||
resolve: resolvedPath,
|
||||
id: createPluginId(packageJSON.name),
|
||||
name: packageJSON.name,
|
||||
options: {},
|
||||
version: packageJSON.version,
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -496,6 +519,6 @@ function resolvePlugin(pluginName) {
|
||||
}
|
||||
}
|
||||
|
||||
function createFileContentHash(path, files) {
|
||||
function createFileContentHash(path, files): string {
|
||||
return path + files
|
||||
}
|
||||
@@ -1,8 +1,20 @@
|
||||
import { asValue } from "awilix"
|
||||
import RealRedis from "ioredis"
|
||||
import FakeRedis from "ioredis-mock"
|
||||
import { MedusaContainer } from "../types/global"
|
||||
import { Logger } from "../types/global"
|
||||
|
||||
const redisLoader = async ({ container, configModule, logger }) => {
|
||||
export type RedisConfig = {
|
||||
redis_url?: string;
|
||||
}
|
||||
|
||||
type Options = {
|
||||
container: MedusaContainer;
|
||||
configModule: { projectConfig: RedisConfig };
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
async function redisLoader({ container, configModule, logger }: Options): Promise<void> {
|
||||
if (configModule.projectConfig.redis_url) {
|
||||
// Economical way of dealing with redis clients
|
||||
const client = new RealRedis(configModule.projectConfig.redis_url)
|
||||
@@ -1,21 +1,22 @@
|
||||
import glob from "glob"
|
||||
import path from "path"
|
||||
import { Lifetime, asClass, asValue } from "awilix"
|
||||
import { asClass } from "awilix"
|
||||
|
||||
import formatRegistrationName from "../utils/format-registration-name"
|
||||
import { ClassConstructor, MedusaContainer } from "../types/global"
|
||||
|
||||
/**
|
||||
* Registers all models in the model directory
|
||||
*/
|
||||
export default ({ container }) => {
|
||||
export default ({ container }: { container: MedusaContainer }): void => {
|
||||
let corePath = "../repositories/*.js"
|
||||
const coreFull = path.join(__dirname, corePath)
|
||||
|
||||
const core = glob.sync(coreFull, { cwd: __dirname })
|
||||
core.forEach(fn => {
|
||||
const loaded = require(fn)
|
||||
const loaded = require(fn) as ClassConstructor<unknown>
|
||||
|
||||
Object.entries(loaded).map(([key, val]) => {
|
||||
Object.entries(loaded).map(([, val]: [string, ClassConstructor<unknown>]) => {
|
||||
if (typeof val === "function") {
|
||||
const name = formatRegistrationName(fn)
|
||||
container.register({
|
||||
@@ -1,9 +1,12 @@
|
||||
import ProductService from "../services/product"
|
||||
import { indexTypes } from "medusa-core-utils"
|
||||
import { MedusaContainer } from "../types/global"
|
||||
import DefaultSearchService from "../services/search"
|
||||
import { Logger } from "../types/global"
|
||||
|
||||
async function loadProductsIntoSearchEngine(container) {
|
||||
const searchService = container.resolve("searchService")
|
||||
const productService = container.resolve("productService")
|
||||
async function loadProductsIntoSearchEngine(container: MedusaContainer): Promise<void> {
|
||||
const searchService = container.resolve<DefaultSearchService>("searchService")
|
||||
const productService = container.resolve<ProductService>("productService")
|
||||
|
||||
const TAKE = 20
|
||||
let hasMore = true
|
||||
@@ -58,9 +61,9 @@ async function loadProductsIntoSearchEngine(container) {
|
||||
}
|
||||
}
|
||||
|
||||
export default async ({ container }) => {
|
||||
const searchService = container.resolve("searchService")
|
||||
const logger = container.resolve("logger")
|
||||
export default async ({ container }: { container: MedusaContainer }): Promise<void> => {
|
||||
const searchService = container.resolve<DefaultSearchService>("searchService")
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
if (searchService.isDefault) {
|
||||
logger.warn(
|
||||
"No search engine provider was found: make sure to include a search plugin to enable searching"
|
||||
@@ -1,13 +1,20 @@
|
||||
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"
|
||||
|
||||
type Options = {
|
||||
container: MedusaContainer;
|
||||
configModule: ConfigModule
|
||||
isTest: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all services in the services directory
|
||||
*/
|
||||
export default ({ container, configModule, isTest }) => {
|
||||
export default ({ container, configModule, isTest }: Options): void => {
|
||||
const useMock =
|
||||
typeof isTest !== "undefined" ? isTest : process.env.NODE_ENV === "test"
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import glob from "glob"
|
||||
import path from "path"
|
||||
import { asFunction } from "awilix"
|
||||
import { MedusaContainer } from "../types/global"
|
||||
|
||||
/**
|
||||
* Registers all subscribers in the subscribers directory
|
||||
*/
|
||||
export default ({ container }) => {
|
||||
export default ({ container }: { container: MedusaContainer }) => {
|
||||
const isTest = process.env.NODE_ENV === "test"
|
||||
|
||||
const corePath = isTest
|
||||
10
packages/medusa/src/types/global.ts
Normal file
10
packages/medusa/src/types/global.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { asFunction, asValue, AwilixContainer } from "awilix"
|
||||
import { Logger as _Logger } from "winston"
|
||||
|
||||
export type ClassConstructor<T> = {
|
||||
new (...args: any[]): T;
|
||||
};
|
||||
|
||||
export type MedusaContainer = AwilixContainer & { registerAdd: <T>(name: string, registration: T ) => MedusaContainer }
|
||||
|
||||
export type Logger = _Logger & { progress: (activityId: string, msg: string) => void }
|
||||
Reference in New Issue
Block a user