feat(medusa, modules-sdk, types, utils): Re work modules loading and remove legacy functions (#5496)

This commit is contained in:
Adrien de Peretti
2023-11-02 17:59:13 +01:00
committed by GitHub
parent ca411e54eb
commit 154c9b43bd
39 changed files with 616 additions and 393 deletions

View File

@@ -0,0 +1,8 @@
---
"@medusajs/medusa": patch
"@medusajs/modules-sdk": patch
"@medusajs/types": patch
"@medusajs/utils": patch
---
feat(medusa, modules-sdk, types, utils): Re work modules loading and remove legacy functions

View File

@@ -14,15 +14,17 @@ async function bootstrapApp({ cwd, env = {} } = {}) {
const loaders = require("@medusajs/medusa/dist/loaders").default const loaders = require("@medusajs/medusa/dist/loaders").default
const { container, dbConnection, pgConnection } = await loaders({ const { container, dbConnection, pgConnection, disposeResources } =
directory: path.resolve(cwd || process.cwd()), await loaders({
expressApp: app, directory: path.resolve(cwd || process.cwd()),
isTest: false, expressApp: app,
}) isTest: false,
})
const PORT = await getPort() const PORT = await getPort()
return { return {
disposeResources,
container, container,
db: dbConnection, db: dbConnection,
pgConnection, pgConnection,
@@ -55,6 +57,7 @@ module.exports = {
expressServer.close(), expressServer.close(),
db?.destroy(), db?.destroy(),
pgConnection?.context?.destroy(), pgConnection?.context?.destroy(),
container.dispose(),
]) ])
if (typeof global !== "undefined" && global?.gc) { if (typeof global !== "undefined" && global?.gc) {

View File

@@ -9,6 +9,7 @@ module.exports = {
`/www/`, `/www/`,
`/dist/`, `/dist/`,
`/node_modules/`, `/node_modules/`,
"<rootDir>/node_modules",
`__tests__/fixtures`, `__tests__/fixtures`,
`__testfixtures__`, `__testfixtures__`,
`.cache`, `.cache`,

View File

@@ -13,7 +13,7 @@ eventEmitter.setMaxListeners(Infinity)
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
export default class LocalEventBusService extends AbstractEventBusModuleService { export default class LocalEventBusService extends AbstractEventBusModuleService {
protected readonly logger_: Logger protected readonly logger_?: Logger
protected readonly eventEmitter_: EventEmitter protected readonly eventEmitter_: EventEmitter
constructor({ logger }: MedusaContainer & InjectedDependencies) { constructor({ logger }: MedusaContainer & InjectedDependencies) {
@@ -53,7 +53,7 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
event.eventName event.eventName
) )
this.logger_.info( this.logger_?.info(
`Processing ${event.eventName} which has ${eventListenersCount} subscribers` `Processing ${event.eventName} which has ${eventListenersCount} subscribers`
) )
@@ -73,7 +73,7 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
// @ts-ignore // @ts-ignore
await subscriber(...args) await subscriber(...args)
} catch (e) { } catch (e) {
this.logger_.error( this.logger_?.error(
`An error occurred while processing ${event.toString()}: ${e}` `An error occurred while processing ${event.toString()}: ${e}`
) )
} }

View File

@@ -46,7 +46,7 @@ export function getMigration(
const generator = orm.getSchemaGenerator() const generator = orm.getSchemaGenerator()
if (hasTable) { if (hasTable) {
const updateSql = await generator.getUpdateSchemaSQL() /* const updateSql = await generator.getUpdateSchemaSQL()
const entityUpdates = updateSql const entityUpdates = updateSql
.split(";") .split(";")
.map((sql) => sql.trim()) .map((sql) => sql.trim())
@@ -65,7 +65,10 @@ export function getMigration(
} }
} else { } else {
logger.info(`Skipping "${tableName}" migration.`) logger.info(`Skipping "${tableName}" migration.`)
} }*/
logger.info(
`Link module "${serviceName}" table update skipped because the table already exists. Please write your own migration if needed.`
)
} else { } else {
try { try {
await generator.createSchema() await generator.createSchema()

View File

@@ -6,20 +6,72 @@ import { composeTableName } from "./compose-link-name"
export function generateGraphQLSchema( export function generateGraphQLSchema(
joinerConfig: ModuleJoinerConfig, joinerConfig: ModuleJoinerConfig,
primary: ModuleJoinerRelationship, primary: ModuleJoinerRelationship,
foreign: ModuleJoinerRelationship foreign: ModuleJoinerRelationship,
{ logger }: { logger } = { logger: console }
) { ) {
const fieldNames = primary.foreignKey.split(",").concat(foreign.foreignKey) let fieldNames!: string[]
let entityName!: string
const entityName = toPascalCase( if (!joinerConfig.isReadOnlyLink) {
"Link_" + fieldNames = primary.foreignKey.split(",").concat(foreign.foreignKey)
(joinerConfig.databaseConfig?.tableName ??
composeTableName( entityName = toPascalCase(
primary.serviceName, "Link_" +
primary.foreignKey, (joinerConfig.databaseConfig?.tableName ??
foreign.serviceName, composeTableName(
foreign.foreignKey primary.serviceName,
)) primary.foreignKey,
) foreign.serviceName,
foreign.foreignKey
))
)
}
let typeDef = ""
for (const extend of joinerConfig.extends ?? []) {
const extendedModule = MedusaModule.getModuleInstance(extend.serviceName)
if (!extendedModule && !extend.relationship.isInternalService) {
throw new Error(
`Module ${extend.serviceName} not found. Please verify that the module is configured and installed, also the module must be loaded before the link modules.`
)
}
const extJoinerConfig = MedusaModule.getJoinerConfig(
extend.relationship.serviceName
)
let extendedEntityName =
extJoinerConfig?.linkableKeys?.[extend.relationship.foreignKey]!
if (!extendedEntityName && (!primary || !foreign)) {
logger.warn(
`Link modules schema: No linkable key found for ${extend.relationship.foreignKey} on module ${extend.relationship.serviceName}.`
)
continue
}
const fieldName = camelToSnakeCase(
lowerCaseFirst(extend.relationship.alias)
)
let type = extend.relationship.isList ? `[${entityName}]` : entityName
if (extJoinerConfig?.isReadOnlyLink) {
type = extend.relationship.isList
? `[${extendedEntityName}]`
: extendedEntityName
}
typeDef += `
extend type ${extend.serviceName} {
${fieldName}: ${type}
}
`
}
if (joinerConfig.isReadOnlyLink) {
return typeDef
}
// Pivot table fields // Pivot table fields
const fields = fieldNames.reduce((acc, curr) => { const fields = fieldNames.reduce((acc, curr) => {
@@ -48,7 +100,7 @@ export function generateGraphQLSchema(
composeTableName(foreign.serviceName) composeTableName(foreign.serviceName)
)}` )}`
let typeDef = ` typeDef += `
type ${entityName} { type ${entityName} {
${(Object.entries(fields) as any) ${(Object.entries(fields) as any)
.map( .map(
@@ -66,36 +118,6 @@ export function generateGraphQLSchema(
} }
` `
for (const extend of joinerConfig.extends ?? []) {
const extendedModule = MedusaModule.getModuleInstance(extend.serviceName)
if (!extendedModule && !extend.relationship.isInternalService) {
throw new Error(
`Module ${extend.serviceName} not found. Please verify that the module is configured and installed, also the module must be loaded before the link modules.`
)
}
const joinerConfig = MedusaModule.getJoinerConfig(extend.serviceName)
let extendedEntityName =
joinerConfig?.linkableKeys?.[extend.relationship.primaryKey]!
if (!extendedEntityName) {
continue
}
extendedEntityName = toPascalCase(extendedEntityName)
const linkTableFieldName = camelToSnakeCase(
lowerCaseFirst(extend.relationship.alias)
)
const type = extend.relationship.isList ? `[${entityName}]` : entityName
typeDef += `
extend type ${extendedEntityName} {
${linkTableFieldName}: ${type}
}
`
}
return typeDef return typeDef
} }

View File

@@ -1,7 +1,9 @@
import { buildRegexpIfValid } from "./build-regexp-if-valid"; import { buildRegexpIfValid } from "./build-regexp-if-valid"
export function parseCorsOrigins(str: string): (string | RegExp)[] { export function parseCorsOrigins(str: string): (string | RegExp)[] {
return str.split(",").map((subStr) => { return !str
return buildRegexpIfValid(subStr) ?? subStr ? []
}) : str.split(",").map((subStr) => {
return buildRegexpIfValid(subStr) ?? subStr
})
} }

View File

@@ -1,4 +1,3 @@
import { ModulesHelper } from "@medusajs/modules-sdk"
import { FlagRouter } from "@medusajs/utils" import { FlagRouter } from "@medusajs/utils"
import { defaultRelationsExtended } from "." import { defaultRelationsExtended } from "."
import { import {
@@ -7,6 +6,7 @@ import {
StoreService, StoreService,
} from "../../../../services" } from "../../../../services"
import { ExtendedStoreDTO } from "../../../../types/store" import { ExtendedStoreDTO } from "../../../../types/store"
import { MedusaModule } from "@medusajs/modules-sdk"
/** /**
* @oas [get] /admin/store * @oas [get] /admin/store
@@ -62,7 +62,6 @@ export default async (req, res) => {
const storeService: StoreService = req.scope.resolve("storeService") const storeService: StoreService = req.scope.resolve("storeService")
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
const modulesHelper: ModulesHelper = req.scope.resolve("modulesHelper")
const paymentProviderService: PaymentProviderService = req.scope.resolve( const paymentProviderService: PaymentProviderService = req.scope.resolve(
"paymentProviderService" "paymentProviderService"
@@ -80,7 +79,16 @@ export default async (req, res) => {
})) as ExtendedStoreDTO })) as ExtendedStoreDTO
data.feature_flags = featureFlagRouter.listFlags() data.feature_flags = featureFlagRouter.listFlags()
data.modules = modulesHelper.modules data.modules = MedusaModule.getLoadedModules()
.map((loadedModule) => {
return Object.entries(loadedModule).map(([key, service]) => {
return {
module: key,
resolution: service.__definition.defaultPackage,
}
})
})
.flat()
const paymentProviders = await paymentProviderService.list() const paymentProviders = await paymentProviderService.list()
const fulfillmentProviders = await fulfillmentProviderService.list() const fulfillmentProviders = await fulfillmentProviderService.list()

View File

@@ -12,23 +12,24 @@ import {
} from "../services" } from "../services"
import getMigrations, { getModuleSharedResources } from "./utils/get-migrations" import getMigrations, { getModuleSharedResources } from "./utils/get-migrations"
import { ConfigModule } from "../types/global"
import { CreateProductCategoryInput } from "../types/product-category"
import { CreateProductInput } from "../types/product"
import { IPricingModuleService } from "@medusajs/types" import { IPricingModuleService } from "@medusajs/types"
import express from "express"
import fs from "fs"
import { sync as existsSync } from "fs-exists-cached"
import { getConfigFile } from "medusa-core-utils"
import { track } from "medusa-telemetry"
import path from "path"
import loaders from "../loaders"
import { handleConfigError } from "../loaders/config"
import featureFlagLoader from "../loaders/feature-flags"
import IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain" import IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain"
import Logger from "../loaders/logger" import Logger from "../loaders/logger"
import PublishableApiKeyService from "../services/publishable-api-key"
import { SalesChannel } from "../models" import { SalesChannel } from "../models"
import { sync as existsSync } from "fs-exists-cached" import PublishableApiKeyService from "../services/publishable-api-key"
import express from "express" import { ConfigModule } from "../types/global"
import featureFlagLoader from "../loaders/feature-flags" import { CreateProductInput } from "../types/product"
import fs from "fs" import { CreateProductCategoryInput } from "../types/product-category"
import { getConfigFile } from "medusa-core-utils" import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { handleConfigError } from "../loaders/config"
import loaders from "../loaders"
import path from "path"
import { track } from "medusa-telemetry"
type SeedOptions = { type SeedOptions = {
directory: string directory: string
@@ -122,7 +123,7 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) {
"shippingProfileService" "shippingProfileService"
) )
const pricingModuleService: IPricingModuleService = container.resolve( const pricingModuleService: IPricingModuleService = container.resolve(
"pricingModuleService" ModuleRegistrationName.PRICING
) )
/* eslint-enable */ /* eslint-enable */

View File

@@ -1,4 +1,4 @@
import { MedusaModule, registerModules } from "@medusajs/modules-sdk" import { MedusaModule, registerMedusaModule } from "@medusajs/modules-sdk"
import fs from "fs" import fs from "fs"
import { sync as existsSync } from "fs-exists-cached" import { sync as existsSync } from "fs-exists-cached"
import glob from "glob" import glob from "glob"
@@ -96,8 +96,13 @@ function resolvePlugin(pluginName) {
export function getInternalModules(configModule) { export function getInternalModules(configModule) {
const modules = [] const modules = []
const moduleResolutions = {}
const moduleResolutions = registerModules(configModule.modules) Object.entries(configModule.modules ?? {}).forEach(([moduleKey, module]) => {
moduleResolutions[moduleKey] = registerMedusaModule(moduleKey, module)[
moduleKey
]
})
for (const moduleResolution of Object.values(moduleResolutions)) { for (const moduleResolution of Object.values(moduleResolutions)) {
if ( if (
@@ -256,7 +261,12 @@ export const getModuleSharedResources = (configModule, featureFlagsRouter) => {
} }
export const runIsolatedModulesMigration = async (configModule) => { export const runIsolatedModulesMigration = async (configModule) => {
const moduleResolutions = registerModules(configModule.modules) const moduleResolutions = {}
Object.entries(configModule.modules ?? {}).forEach(([moduleKey, module]) => {
moduleResolutions[moduleKey] = registerMedusaModule(moduleKey, module)[
moduleKey
]
})
for (const moduleResolution of Object.values(moduleResolutions)) { for (const moduleResolution of Object.values(moduleResolutions)) {
if ( if (
@@ -276,7 +286,12 @@ export const runIsolatedModulesMigration = async (configModule) => {
} }
export const revertIsolatedModulesMigration = async (configModule) => { export const revertIsolatedModulesMigration = async (configModule) => {
const moduleResolutions = registerModules(configModule.modules) const moduleResolutions = {}
Object.entries(configModule.modules ?? {}).forEach(([moduleKey, module]) => {
moduleResolutions[moduleKey] = registerMedusaModule(moduleKey, module)[
moduleKey
]
})
for (const moduleResolution of Object.values(moduleResolutions)) { for (const moduleResolution of Object.values(moduleResolutions)) {
if ( if (

View File

@@ -3,7 +3,6 @@ import {
moduleLoader, moduleLoader,
ModulesDefinition, ModulesDefinition,
registerMedusaModule, registerMedusaModule,
registerModules,
} from "@medusajs/modules-sdk" } from "@medusajs/modules-sdk"
import { asValue, createContainer } from "awilix" import { asValue, createContainer } from "awilix"
import express from "express" import express from "express"
@@ -19,7 +18,6 @@ import passportLoader from "../loaders/passport"
import repositories from "../loaders/repositories" import repositories from "../loaders/repositories"
import servicesLoader from "../loaders/services" import servicesLoader from "../loaders/services"
import strategiesLoader from "../loaders/strategies" import strategiesLoader from "../loaders/strategies"
import modules from "../modules-config"
const adminSessionOpts = { const adminSessionOpts = {
cookieName: "session", cookieName: "session",
@@ -33,12 +31,13 @@ const clientSessionOpts = {
secret: "test", secret: "test",
} }
const moduleResolutions = registerModules({}) const moduleResolutions = {}
// Load non legacy modules Object.entries(ModulesDefinition).forEach(([moduleKey, module]) => {
Object.keys(modules).map((moduleKey) => {
moduleResolutions[moduleKey] = registerMedusaModule( moduleResolutions[moduleKey] = registerMedusaModule(
moduleKey, moduleKey,
ModulesDefinition[moduleKey] module.defaultModuleDeclaration,
undefined,
module
)[moduleKey] )[moduleKey]
}) })
@@ -84,7 +83,7 @@ container.register("modulesHelper", asValue(moduleHelper))
container.register("configModule", asValue(config)) container.register("configModule", asValue(config))
container.register({ container.register({
logger: asValue({ logger: asValue({
error: () => { }, error: () => {},
}), }),
manager: asValue(MockManager), manager: asValue(MockManager),
}) })
@@ -146,7 +145,10 @@ export async function request(method, url, opts = {}) {
headers.Cookie = headers.Cookie || "" headers.Cookie = headers.Cookie || ""
if (opts.adminSession) { if (opts.adminSession) {
const token = jwt.sign( const token = jwt.sign(
{ user_id: opts.adminSession.userId || opts.adminSession.jwt?.userId, domain: "admin" }, {
user_id: opts.adminSession.userId || opts.adminSession.jwt?.userId,
domain: "admin",
},
config.projectConfig.jwt_secret config.projectConfig.jwt_secret
) )
@@ -154,7 +156,11 @@ export async function request(method, url, opts = {}) {
} }
if (opts.clientSession) { if (opts.clientSession) {
const token = jwt.sign( const token = jwt.sign(
{ customer_id: opts.clientSession.customer_id || opts.clientSession.jwt?.customer_id, domain: "store" }, {
customer_id:
opts.clientSession.customer_id || opts.clientSession.jwt?.customer_id,
domain: "store",
},
config.projectConfig.jwt_secret config.projectConfig.jwt_secret
) )

View File

@@ -1,4 +1,8 @@
import { moduleLoader, registerModules } from "@medusajs/modules-sdk" import {
InternalModuleDeclaration,
ModulesDefinition,
} from "@medusajs/modules-sdk"
import { MODULE_RESOURCE_TYPE } from "@medusajs/types"
import { Express, NextFunction, Request, Response } from "express" import { Express, NextFunction, Request, Response } from "express"
import databaseLoader, { dataSource } from "./database" import databaseLoader, { dataSource } from "./database"
@@ -17,10 +21,8 @@ import loadConfig from "./config"
import defaultsLoader from "./defaults" import defaultsLoader from "./defaults"
import expressLoader from "./express" import expressLoader from "./express"
import featureFlagsLoader from "./feature-flags" import featureFlagsLoader from "./feature-flags"
import IsolatePricingDomainFeatureFlag from "./feature-flags/isolate-pricing-domain"
import IsolateProductDomainFeatureFlag from "./feature-flags/isolate-product-domain"
import Logger from "./logger" import Logger from "./logger"
import loadMedusaApp from "./medusa-app" import loadMedusaApp, { mergeDefaultModules } from "./medusa-app"
import modelsLoader from "./models" import modelsLoader from "./models"
import passportLoader from "./passport" import passportLoader from "./passport"
import pgConnectionLoader from "./pg-connection" import pgConnectionLoader from "./pg-connection"
@@ -37,6 +39,34 @@ type Options = {
isTest: boolean isTest: boolean
} }
async function loadLegacyModulesEntities(configModules, container) {
for (const [moduleName, moduleConfig] of Object.entries(configModules)) {
const definition = ModulesDefinition[moduleName]
if (!definition.isLegacy) {
continue
}
if (
(moduleConfig as InternalModuleDeclaration).resources ===
MODULE_RESOURCE_TYPE.SHARED ||
(definition.defaultModuleDeclaration as InternalModuleDeclaration)
.resources === MODULE_RESOURCE_TYPE.SHARED
) {
const module = await import(
(moduleConfig as InternalModuleDeclaration).resolve ??
(definition.defaultPackage as string)
)
if (module.default?.models) {
module.default.models.map((model) =>
container.registerAdd("db_entities", asValue(model))
)
}
}
}
}
export default async ({ export default async ({
directory: rootDirectory, directory: rootDirectory,
expressApp, expressApp,
@@ -98,16 +128,8 @@ export default async ({
const pgConnection = await pgConnectionLoader({ container, configModule }) const pgConnection = await pgConnectionLoader({ container, configModule })
const modulesActivity = Logger.activity(`Initializing modules${EOL}`) const configModules = mergeDefaultModules(configModule.modules)
await loadLegacyModulesEntities(configModules, container)
track("MODULES_INIT_STARTED")
await moduleLoader({
container,
moduleResolutions: registerModules(configModule?.modules),
logger: Logger,
})
const modAct = Logger.success(modulesActivity, "Modules initialized") || {}
track("MODULES_INIT_COMPLETED", { duration: modAct.duration })
const dbActivity = Logger.activity(`Initializing database${EOL}`) const dbActivity = Logger.activity(`Initializing database${EOL}`)
track("DATABASE_INIT_STARTED") track("DATABASE_INIT_STARTED")
@@ -129,13 +151,6 @@ export default async ({
}) })
container.register("remoteQuery", asValue(null)) // ensure remoteQuery is always registered container.register("remoteQuery", asValue(null)) // ensure remoteQuery is always registered
// Only load non legacy modules, the legacy modules (non migrated yet) are retrieved by the registerModule above
if (
featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key) ||
featureFlagRouter.isFeatureEnabled(IsolatePricingDomainFeatureFlag.key)
) {
await loadMedusaApp({ configModule, container })
}
const servicesActivity = Logger.activity(`Initializing services${EOL}`) const servicesActivity = Logger.activity(`Initializing services${EOL}`)
track("SERVICES_INIT_STARTED") track("SERVICES_INIT_STARTED")
@@ -143,6 +158,18 @@ export default async ({
const servAct = Logger.success(servicesActivity, "Services initialized") || {} const servAct = Logger.success(servicesActivity, "Services initialized") || {}
track("SERVICES_INIT_COMPLETED", { duration: servAct.duration }) track("SERVICES_INIT_COMPLETED", { duration: servAct.duration })
const modulesActivity = Logger.activity(`Initializing modules${EOL}`)
track("MODULES_INIT_STARTED")
// Move before services init once all modules are migrated and do not rely on core resources anymore
await loadMedusaApp({
configModule,
container,
})
const modAct = Logger.success(modulesActivity, "Modules initialized") || {}
track("MODULES_INIT_COMPLETED", { duration: modAct.duration })
const expActivity = Logger.activity(`Initializing express${EOL}`) const expActivity = Logger.activity(`Initializing express${EOL}`)
track("EXPRESS_INIT_STARTED") track("EXPRESS_INIT_STARTED")
await expressLoader({ app: expressApp, configModule }) await expressLoader({ app: expressApp, configModule })
@@ -196,5 +223,10 @@ export default async ({
Logger.success(searchActivity, "Indexing event emitted") || {} Logger.success(searchActivity, "Indexing event emitted") || {}
track("SEARCH_ENGINE_INDEXING_COMPLETED", { duration: searchAct.duration }) track("SEARCH_ENGINE_INDEXING_COMPLETED", { duration: searchAct.duration })
return { container, dbConnection, app: expressApp, pgConnection } return {
container,
dbConnection,
app: expressApp,
pgConnection,
}
} }

View File

@@ -1,26 +1,51 @@
import { CommonTypes, MedusaContainer } from "@medusajs/types" import {
CommonTypes,
InternalModuleDeclaration,
MedusaContainer,
ModuleDefinition,
} from "@medusajs/types"
import { import {
MedusaApp, MedusaApp,
MedusaAppOutput, MedusaAppOutput,
ModulesDefinition, ModulesDefinition,
} from "@medusajs/modules-sdk" } from "@medusajs/modules-sdk"
import { ContainerRegistrationKeys } from "@medusajs/utils" import { ContainerRegistrationKeys, isObject } from "@medusajs/utils"
import { asValue } from "awilix" import { asValue } from "awilix"
import { joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { mergeModulesConfig } from "../utils/merge-modules-config"
import modulesConfig from "../modules-config"
import { remoteQueryFetchData } from ".." import { remoteQueryFetchData } from ".."
export function mergeDefaultModules(
modulesConfig: CommonTypes.ConfigModule["modules"]
) {
const defaultModules = Object.values(ModulesDefinition).filter(
(definition: ModuleDefinition) => {
return !!definition.defaultPackage
}
)
const configModules = { ...modulesConfig } ?? {}
for (const defaultModule of defaultModules as ModuleDefinition[]) {
configModules[defaultModule.key] ??= defaultModule.defaultModuleDeclaration
}
return configModules
}
export const loadMedusaApp = async ( export const loadMedusaApp = async (
{ {
configModule, configModule,
container, container,
}: { configModule: CommonTypes.ConfigModule; container: MedusaContainer }, }: {
configModule: {
modules?: CommonTypes.ConfigModule["modules"]
projectConfig: CommonTypes.ConfigModule["projectConfig"]
}
container: MedusaContainer
},
config = { registerInContainer: true } config = { registerInContainer: true }
): Promise<MedusaAppOutput> => { ): Promise<MedusaAppOutput> => {
mergeModulesConfig(configModule.modules ?? {}, modulesConfig)
const injectedDependencies = { const injectedDependencies = {
[ContainerRegistrationKeys.PG_CONNECTION]: container.resolve( [ContainerRegistrationKeys.PG_CONNECTION]: container.resolve(
ContainerRegistrationKeys.PG_CONNECTION ContainerRegistrationKeys.PG_CONNECTION
@@ -34,8 +59,34 @@ export const loadMedusaApp = async (
}, },
} }
container.register(ContainerRegistrationKeys.REMOTE_QUERY, asValue(undefined))
container.register(ContainerRegistrationKeys.REMOTE_LINK, asValue(undefined))
const configModules = mergeDefaultModules(configModule.modules)
// Apply default options to legacy modules
for (const moduleKey of Object.keys(configModules)) {
if (!ModulesDefinition[moduleKey].isLegacy) {
continue
}
if (isObject(configModules[moduleKey])) {
;(
configModules[moduleKey] as Partial<InternalModuleDeclaration>
).options ??= {
database: {
type: "postgres",
url: configModule.projectConfig.database_url,
extra: configModule.projectConfig.database_extra,
schema: configModule.projectConfig.database_schema,
logging: configModule.projectConfig.database_logging,
},
}
}
}
const medusaApp = await MedusaApp({ const medusaApp = await MedusaApp({
modulesConfig, modulesConfig: configModules,
servicesConfig: joinerConfig, servicesConfig: joinerConfig,
remoteFetchData: remoteQueryFetchData(container), remoteFetchData: remoteQueryFetchData(container),
sharedContainer: container, sharedContainer: container,
@@ -48,18 +99,25 @@ export const loadMedusaApp = async (
} }
container.register("remoteLink", asValue(medusaApp.link)) container.register("remoteLink", asValue(medusaApp.link))
container.register(
ContainerRegistrationKeys.REMOTE_QUERY,
asValue(medusaApp.query)
)
const { query, modules } = medusaApp for (const [serviceKey, moduleService] of Object.entries(medusaApp.modules)) {
// Medusa app load all non legacy modules, so we need to register them in the container since they are into their own container
// We might decide to do it elsewhere but for now I think it is fine
for (const [serviceKey, moduleService] of Object.entries(modules)) {
container.register( container.register(
ModulesDefinition[serviceKey].registrationName, ModulesDefinition[serviceKey].registrationName,
asValue(moduleService) asValue(moduleService)
) )
} }
container.register("remoteQuery", asValue(query))
// Register all unresolved modules as undefined to be present in the container with undefined value by defaul
// but still resolvable
for (const [, moduleDefinition] of Object.entries(ModulesDefinition)) {
if (!container.hasRegistration(moduleDefinition.registrationName)) {
container.register(moduleDefinition.registrationName, asValue(undefined))
}
}
return medusaApp return medusaApp
} }

View File

@@ -1,5 +1,5 @@
import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils" import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils"
import { AwilixContainer, asValue } from "awilix" import { asValue, AwilixContainer } from "awilix"
import { ConfigModule } from "../types/global" import { ConfigModule } from "../types/global"
type Options = { type Options = {
@@ -9,7 +9,7 @@ type Options = {
export default async ({ container, configModule }: Options): Promise<any> => { export default async ({ container, configModule }: Options): Promise<any> => {
if (container.hasRegistration(ContainerRegistrationKeys.PG_CONNECTION)) { if (container.hasRegistration(ContainerRegistrationKeys.PG_CONNECTION)) {
return return container.resolve(ContainerRegistrationKeys.PG_CONNECTION)
} }
// Share a knex connection to be consumed by the shared modules // Share a knex connection to be consumed by the shared modules

View File

@@ -2,6 +2,7 @@ import { MedusaModuleConfig, Modules } from "@medusajs/modules-sdk"
const modules: MedusaModuleConfig = { const modules: MedusaModuleConfig = {
[Modules.PRODUCT]: true, [Modules.PRODUCT]: true,
[Modules.PRICING]: true,
} }
export default modules export default modules

View File

@@ -27,14 +27,17 @@ export default class EventBusService
protected readonly config_: ConfigModule protected readonly config_: ConfigModule
protected readonly stagedJobService_: StagedJobService protected readonly stagedJobService_: StagedJobService
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
protected readonly eventBusModuleService_: EventBusTypes.IEventBusModuleService protected get eventBusModuleService_(): EventBusTypes.IEventBusModuleService {
return this.__container__.eventBusModuleService
}
protected readonly logger_: Logger protected readonly logger_: Logger
protected shouldEnqueuerRun: boolean protected shouldEnqueuerRun: boolean
protected enqueue_: Promise<void> protected enqueue_: Promise<void>
constructor( constructor(
{ stagedJobService, eventBusModuleService, logger }: InjectedDependencies, { stagedJobService, logger }: InjectedDependencies,
config, config,
isSingleton = true isSingleton = true
) { ) {
@@ -43,7 +46,6 @@ export default class EventBusService
this.logger_ = logger this.logger_ = logger
this.config_ = config this.config_ = config
this.eventBusModuleService_ = eventBusModuleService
this.stagedJobService_ = stagedJobService this.stagedJobService_ = stagedJobService
if (process.env.NODE_ENV !== "test" && isSingleton) { if (process.env.NODE_ENV !== "test" && isSingleton) {

View File

@@ -70,7 +70,10 @@ export default class OrderEditService extends TransactionBaseService {
protected readonly taxProviderService_: TaxProviderService protected readonly taxProviderService_: TaxProviderService
protected readonly lineItemAdjustmentService_: LineItemAdjustmentService protected readonly lineItemAdjustmentService_: LineItemAdjustmentService
protected readonly orderEditItemChangeService_: OrderEditItemChangeService protected readonly orderEditItemChangeService_: OrderEditItemChangeService
protected readonly inventoryService_: IInventoryService | undefined
protected get inventoryService_(): IInventoryService | undefined {
return this.__container__.inventoryService
}
constructor({ constructor({
orderEditRepository, orderEditRepository,
@@ -82,7 +85,6 @@ export default class OrderEditService extends TransactionBaseService {
orderEditItemChangeService, orderEditItemChangeService,
lineItemAdjustmentService, lineItemAdjustmentService,
taxProviderService, taxProviderService,
inventoryService,
}: InjectedDependencies) { }: InjectedDependencies) {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
super(arguments[0]) super(arguments[0])
@@ -96,7 +98,6 @@ export default class OrderEditService extends TransactionBaseService {
this.orderEditItemChangeService_ = orderEditItemChangeService this.orderEditItemChangeService_ = orderEditItemChangeService
this.lineItemAdjustmentService_ = lineItemAdjustmentService this.lineItemAdjustmentService_ = lineItemAdjustmentService
this.taxProviderService_ = taxProviderService this.taxProviderService_ = taxProviderService
this.inventoryService_ = inventoryService
} }
async retrieve( async retrieve(

View File

@@ -2,7 +2,6 @@ import {
CalculatedPriceSetDTO, CalculatedPriceSetDTO,
IPricingModuleService, IPricingModuleService,
PriceSetMoneyAmountDTO, PriceSetMoneyAmountDTO,
RemoteJoinerQuery,
RemoteQueryFunction, RemoteQueryFunction,
} from "@medusajs/types" } from "@medusajs/types"
import { FlagRouter, removeNullish } from "@medusajs/utils" import { FlagRouter, removeNullish } from "@medusajs/utils"
@@ -56,8 +55,13 @@ class PricingService extends TransactionBaseService {
protected readonly priceSelectionStrategy: IPriceSelectionStrategy protected readonly priceSelectionStrategy: IPriceSelectionStrategy
protected readonly productVariantService: ProductVariantService protected readonly productVariantService: ProductVariantService
protected readonly featureFlagRouter: FlagRouter protected readonly featureFlagRouter: FlagRouter
protected readonly pricingModuleService: IPricingModuleService
protected readonly remoteQuery: RemoteQueryFunction protected get pricingModuleService(): IPricingModuleService {
return this.__container__.pricingModuleService
}
protected get remoteQuery(): RemoteQueryFunction {
return this.__container__.remoteQuery
}
constructor({ constructor({
productVariantService, productVariantService,
@@ -65,8 +69,6 @@ class PricingService extends TransactionBaseService {
regionService, regionService,
priceSelectionStrategy, priceSelectionStrategy,
featureFlagRouter, featureFlagRouter,
remoteQuery,
pricingModuleService,
}: InjectedDependencies) { }: InjectedDependencies) {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
super(arguments[0]) super(arguments[0])
@@ -76,8 +78,6 @@ class PricingService extends TransactionBaseService {
this.priceSelectionStrategy = priceSelectionStrategy this.priceSelectionStrategy = priceSelectionStrategy
this.productVariantService = productVariantService this.productVariantService = productVariantService
this.featureFlagRouter = featureFlagRouter this.featureFlagRouter = featureFlagRouter
this.pricingModuleService = pricingModuleService
this.remoteQuery = remoteQuery
} }
/** /**

View File

@@ -1,6 +1,5 @@
import { EntityManager, In } from "typeorm" import { EntityManager, In } from "typeorm"
import { import {
ICacheService,
IEventBusService, IEventBusService,
IInventoryService, IInventoryService,
InventoryItemDTO, InventoryItemDTO,
@@ -42,17 +41,20 @@ class ProductVariantInventoryService extends TransactionBaseService {
protected readonly salesChannelLocationService_: SalesChannelLocationService protected readonly salesChannelLocationService_: SalesChannelLocationService
protected readonly salesChannelInventoryService_: SalesChannelInventoryService protected readonly salesChannelInventoryService_: SalesChannelInventoryService
protected readonly productVariantService_: ProductVariantService protected readonly productVariantService_: ProductVariantService
protected readonly stockLocationService_: IStockLocationService
protected readonly inventoryService_: IInventoryService
protected readonly eventBusService_: IEventBusService protected readonly eventBusService_: IEventBusService
protected readonly cacheService_: ICacheService
protected get inventoryService_(): IInventoryService {
return this.__container__.inventoryService
}
protected get stockLocationService_(): IStockLocationService {
return this.__container__.stockLocationService
}
constructor({ constructor({
stockLocationService,
salesChannelLocationService, salesChannelLocationService,
salesChannelInventoryService, salesChannelInventoryService,
productVariantService, productVariantService,
inventoryService,
eventBusService, eventBusService,
}: InjectedDependencies) { }: InjectedDependencies) {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
@@ -60,9 +62,7 @@ class ProductVariantInventoryService extends TransactionBaseService {
this.salesChannelLocationService_ = salesChannelLocationService this.salesChannelLocationService_ = salesChannelLocationService
this.salesChannelInventoryService_ = salesChannelInventoryService this.salesChannelInventoryService_ = salesChannelInventoryService
this.stockLocationService_ = stockLocationService
this.productVariantService_ = productVariantService this.productVariantService_ = productVariantService
this.inventoryService_ = inventoryService
this.eventBusService_ = eventBusService this.eventBusService_ = eventBusService
} }

View File

@@ -13,11 +13,13 @@ type InjectedDependencies = {
class SalesChannelInventoryService extends TransactionBaseService { class SalesChannelInventoryService extends TransactionBaseService {
protected readonly salesChannelLocationService_: SalesChannelLocationService protected readonly salesChannelLocationService_: SalesChannelLocationService
protected readonly eventBusService_: EventBusTypes.IEventBusService protected readonly eventBusService_: EventBusTypes.IEventBusService
protected readonly inventoryService_: IInventoryService
protected get inventoryService_(): IInventoryService {
return this.__container__.inventoryService
}
constructor({ constructor({
salesChannelLocationService, salesChannelLocationService,
inventoryService,
eventBusService, eventBusService,
}: InjectedDependencies) { }: InjectedDependencies) {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
@@ -25,7 +27,6 @@ class SalesChannelInventoryService extends TransactionBaseService {
this.salesChannelLocationService_ = salesChannelLocationService this.salesChannelLocationService_ = salesChannelLocationService
this.eventBusService_ = eventBusService this.eventBusService_ = eventBusService
this.inventoryService_ = inventoryService
} }
/** /**

View File

@@ -19,19 +19,17 @@ type InjectedDependencies = {
class SalesChannelLocationService extends TransactionBaseService { class SalesChannelLocationService extends TransactionBaseService {
protected readonly salesChannelService_: SalesChannelService protected readonly salesChannelService_: SalesChannelService
protected readonly eventBusService_: IEventBusService protected readonly eventBusService_: IEventBusService
protected readonly stockLocationService_: IStockLocationService
constructor({ protected get stockLocationService_(): IStockLocationService {
salesChannelService, return this.__container__.stockLocationService
stockLocationService, }
eventBusService,
}: InjectedDependencies) { constructor({ salesChannelService, eventBusService }: InjectedDependencies) {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
super(arguments[0]) super(arguments[0])
this.salesChannelService_ = salesChannelService this.salesChannelService_ = salesChannelService
this.eventBusService_ = eventBusService this.eventBusService_ = eventBusService
this.stockLocationService_ = stockLocationService
} }
/** /**

View File

@@ -1,11 +1,6 @@
import { import { ConfigModule } from "@medusajs/types"
ConfigModule,
ExternalModuleDeclaration,
InternalModuleDeclaration,
} from "@medusajs/types"
import { ModulesDefinition } from "@medusajs/modules-sdk" import { ModulesDefinition } from "@medusajs/modules-sdk"
import { isObject } from "./is-object"
/** /**
* Merge the modules config from the medusa-config file with the modules config from medusa package * Merge the modules config from the medusa-config file with the modules config from medusa package
@@ -13,24 +8,30 @@ import { isObject } from "./is-object"
* @param medusaInternalModulesConfig * @param medusaInternalModulesConfig
*/ */
export function mergeModulesConfig( export function mergeModulesConfig(
modules: ConfigModule["modules"], modules: ConfigModule["modules"] = {},
medusaInternalModulesConfig medusaInternalModulesConfig = {}
) { ) {
for (const [moduleName, moduleConfig] of Object.entries(modules as any)) { const modules_ = ({ ...modules } as ConfigModule["modules"])!
const userModulesConfigKeys = Object.keys(modules)
const internalModulesConfigKeys = Object.keys(medusaInternalModulesConfig)
const allModulesKeys = new Set([
...userModulesConfigKeys,
...internalModulesConfigKeys,
])
for (const moduleName of allModulesKeys) {
const internalModuleConfig = medusaInternalModulesConfig[moduleName]
const moduleDefinition = ModulesDefinition[moduleName] const moduleDefinition = ModulesDefinition[moduleName]
if (moduleDefinition?.isLegacy) { if (moduleDefinition?.isLegacy) {
continue continue
} }
const isModuleEnabled = moduleConfig === true || isObject(moduleConfig) modules_[moduleName] ??= internalModuleConfig
if (!isModuleEnabled) {
delete medusaInternalModulesConfig[moduleName]
} else {
medusaInternalModulesConfig[moduleName] = moduleConfig as Partial<
InternalModuleDeclaration | ExternalModuleDeclaration
>
}
} }
return modules_
} }

View File

@@ -3,6 +3,5 @@ export * from "./definitions"
export * from "./loaders" export * from "./loaders"
export * from "./medusa-app" export * from "./medusa-app"
export * from "./medusa-module" export * from "./medusa-module"
export * from "./module-helper"
export * from "./remote-link" export * from "./remote-link"
export * from "./remote-query" export * from "./remote-query"

View File

@@ -4,8 +4,8 @@ import {
MODULE_SCOPE, MODULE_SCOPE,
ModuleDefinition, ModuleDefinition,
} from "@medusajs/types" } from "@medusajs/types"
import MODULE_DEFINITIONS from "../../definitions" import { ModulesDefinition } from "../../definitions"
import { registerModules } from "../register-modules" import { registerMedusaModule } from "../register-modules"
const RESOLVED_PACKAGE = "@medusajs/test-service-resolved" const RESOLVED_PACKAGE = "@medusajs/test-service-resolved"
jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE)) jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE))
@@ -30,13 +30,18 @@ describe("module definitions loader", () => {
jest.clearAllMocks() jest.clearAllMocks()
// Clear module definitions // Clear module definitions
MODULE_DEFINITIONS.splice(0, MODULE_DEFINITIONS.length) const allProperties = Object.getOwnPropertyNames(ModulesDefinition)
allProperties.forEach((property) => {
delete ModulesDefinition[property]
})
}) })
it("Resolves module with default definition given empty config", () => { it("Resolves module with default definition given empty config", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({}) const res = registerMedusaModule(defaultDefinition.key)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({ expect.objectContaining({
@@ -53,9 +58,11 @@ describe("module definitions loader", () => {
describe("boolean config", () => { describe("boolean config", () => {
it("Resolves module with no resolution path when given false", () => { it("Resolves module with no resolution path when given false", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({ [defaultDefinition.key]: false }) const res = registerMedusaModule(defaultDefinition.key, false)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({ expect.objectContaining({
@@ -68,10 +75,12 @@ describe("module definitions loader", () => {
it("Fails to resolve module with no resolution path when given false for a required module", () => { it("Fails to resolve module with no resolution path when given false for a required module", () => {
expect.assertions(1) expect.assertions(1)
MODULE_DEFINITIONS.push({ ...defaultDefinition, isRequired: true }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: { ...defaultDefinition, isRequired: true },
})
try { try {
registerModules({ [defaultDefinition.key]: false }) registerMedusaModule(defaultDefinition.key, false)
} catch (err) { } catch (err) {
expect(err.message).toEqual( expect(err.message).toEqual(
`Module: ${defaultDefinition.label} is required` `Module: ${defaultDefinition.label} is required`
@@ -87,9 +96,11 @@ describe("module definitions loader", () => {
isRequired: true, isRequired: true,
} }
MODULE_DEFINITIONS.push(definition) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: definition,
})
const res = registerModules({}) const res = registerMedusaModule(defaultDefinition.key)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({ expect.objectContaining({
@@ -106,12 +117,15 @@ describe("module definitions loader", () => {
describe("string config", () => { describe("string config", () => {
it("Resolves module with default definition given empty config", () => { it("Resolves module with default definition given empty config", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
const res = registerModules({
[defaultDefinition.key]: defaultDefinition.defaultPackage,
}) })
const res = registerMedusaModule(
defaultDefinition.key,
defaultDefinition.defaultPackage
)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({ expect.objectContaining({
resolutionPath: RESOLVED_PACKAGE, resolutionPath: RESOLVED_PACKAGE,
@@ -128,16 +142,16 @@ describe("module definitions loader", () => {
describe("object config", () => { describe("object config", () => {
it("Resolves resolution path and provides empty options when none are provided", () => { it("Resolves resolution path and provides empty options when none are provided", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
const res = registerModules({
[defaultDefinition.key]: {
scope: MODULE_SCOPE.INTERNAL,
resolve: defaultDefinition.defaultPackage,
resources: MODULE_RESOURCE_TYPE.ISOLATED,
} as InternalModuleDeclaration,
}) })
const res = registerMedusaModule(defaultDefinition.key, {
scope: MODULE_SCOPE.INTERNAL,
resolve: defaultDefinition.defaultPackage,
resources: MODULE_RESOURCE_TYPE.ISOLATED,
} as InternalModuleDeclaration)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(
expect.objectContaining({ expect.objectContaining({
resolutionPath: RESOLVED_PACKAGE, resolutionPath: RESOLVED_PACKAGE,
@@ -153,12 +167,12 @@ describe("module definitions loader", () => {
}) })
it("Resolves default resolution path and provides options when only options are provided", () => { it("Resolves default resolution path and provides options when only options are provided", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({ const res = registerMedusaModule(defaultDefinition.key, {
[defaultDefinition.key]: { options: { test: 123 },
options: { test: 123 },
},
} as any) } as any)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(
@@ -176,15 +190,15 @@ describe("module definitions loader", () => {
}) })
it("Resolves resolution path and provides options when only options are provided", () => { it("Resolves resolution path and provides options when only options are provided", () => {
MODULE_DEFINITIONS.push({ ...defaultDefinition }) Object.assign(ModulesDefinition, {
[defaultDefinition.key]: defaultDefinition,
})
const res = registerModules({ const res = registerMedusaModule(defaultDefinition.key, {
[defaultDefinition.key]: { resolve: defaultDefinition.defaultPackage,
resolve: defaultDefinition.defaultPackage, options: { test: 123 },
options: { test: 123 }, scope: "internal",
scope: "internal", resources: "isolated",
resources: "isolated",
},
} as any) } as any)
expect(res[defaultDefinition.key]).toEqual( expect(res[defaultDefinition.key]).toEqual(

View File

@@ -1,17 +1,14 @@
import { import {
Logger, Logger,
MODULE_SCOPE,
MedusaContainer, MedusaContainer,
MODULE_SCOPE,
ModuleResolution, ModuleResolution,
} from "@medusajs/types" } from "@medusajs/types"
import { asValue } from "awilix" import { asValue } from "awilix"
import { EOL } from "os" import { EOL } from "os"
import { ModulesHelper } from "../module-helper"
import { loadInternalModule } from "./utils" import { loadInternalModule } from "./utils"
export const moduleHelper = new ModulesHelper()
export const moduleLoader = async ({ export const moduleLoader = async ({
container, container,
moduleResolutions, moduleResolutions,
@@ -38,17 +35,6 @@ export const moduleLoader = async ({
) )
} }
} }
moduleHelper.setModules(
Object.entries(moduleResolutions).reduce((acc, [k, v]) => {
if (v.resolutionPath) {
acc[k] = v
}
return acc
}, {})
)
container.register("modulesHelper", asValue(moduleHelper))
} }
async function loadModule( async function loadModule(

View File

@@ -9,57 +9,11 @@ import {
import { isObject } from "@medusajs/utils" import { isObject } from "@medusajs/utils"
import resolveCwd from "resolve-cwd" import resolveCwd from "resolve-cwd"
import { MODULE_DEFINITIONS, ModulesDefinition } from "../definitions" import { ModulesDefinition } from "../definitions"
/**
*
* @param modules
* @param isolatedModules Will be removed once the isolated flag is being removed
*/
// TODO: Remove once we have all modules migrated + rename to something like getResolutions
export const registerModules = (
modules?: Record<
string,
| false
| string
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
>,
{ loadLegacyOnly } = { loadLegacyOnly: false }
): Record<string, ModuleResolution> => {
const moduleResolutions = {} as Record<string, ModuleResolution>
const projectModules = modules ?? {}
for (const definition of MODULE_DEFINITIONS) {
// Skip non legacy modules
if (loadLegacyOnly && !definition.isLegacy) {
continue
}
const customConfig = projectModules[definition.key]
const canSkip =
!customConfig && !definition.isRequired && !definition.defaultPackage
const isObj = isObject(customConfig)
if (isObj && customConfig.scope === MODULE_SCOPE.EXTERNAL) {
// TODO: getExternalModuleResolution(...)
if (!canSkip) {
throw new Error("External Modules are not supported yet.")
}
}
moduleResolutions[definition.key] = getInternalModuleResolution(
definition,
customConfig as InternalModuleDeclaration
)
}
return moduleResolutions
}
export const registerMedusaModule = ( export const registerMedusaModule = (
moduleKey: string, moduleKey: string,
moduleDeclaration: moduleDeclaration?:
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration> | Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
| string | string
| false, | false,
@@ -74,9 +28,17 @@ export const registerMedusaModule = (
throw new Error(`Module: ${moduleKey} is not defined.`) throw new Error(`Module: ${moduleKey} is not defined.`)
} }
const modDeclaration =
moduleDeclaration ??
(modDefinition?.defaultModuleDeclaration as InternalModuleDeclaration)
if (modDeclaration !== false && !modDeclaration) {
throw new Error(`Module: ${moduleKey} has no declaration.`)
}
if ( if (
isObject(moduleDeclaration) && isObject(modDeclaration) &&
moduleDeclaration?.scope === MODULE_SCOPE.EXTERNAL modDeclaration?.scope === MODULE_SCOPE.EXTERNAL
) { ) {
// TODO: getExternalModuleResolution(...) // TODO: getExternalModuleResolution(...)
throw new Error("External Modules are not supported yet.") throw new Error("External Modules are not supported yet.")

View File

@@ -1,10 +1,8 @@
import { import {
Constructor,
InternalModuleDeclaration, InternalModuleDeclaration,
Logger, Logger,
MODULE_RESOURCE_TYPE,
MODULE_SCOPE,
MedusaContainer, MedusaContainer,
MODULE_RESOURCE_TYPE,
ModuleExports, ModuleExports,
ModuleResolution, ModuleResolution,
} from "@medusajs/types" } from "@medusajs/types"
@@ -65,18 +63,6 @@ export async function loadInternalModule(
} }
} }
if (
scope === MODULE_SCOPE.INTERNAL &&
resources === MODULE_RESOURCE_TYPE.SHARED
) {
const moduleModels = loadedModule?.models || null
if (moduleModels) {
moduleModels.map((val: Constructor<unknown>) => {
container.registerAdd("db_entities", asValue(val))
})
}
}
const localContainer = createMedusaContainer() const localContainer = createMedusaContainer()
const dependencies = resolution?.dependencies ?? [] const dependencies = resolution?.dependencies ?? []

View File

@@ -40,8 +40,8 @@ export type RunMigrationFn = (
export type MedusaModuleConfig = { export type MedusaModuleConfig = {
[key: string | Modules]: [key: string | Modules]:
| boolean
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration> | Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
| true
} }
export type SharedResources = { export type SharedResources = {

View File

@@ -1,16 +0,0 @@
import { ModuleResolution, ModulesResponse } from "@medusajs/types"
export class ModulesHelper {
private modules_: Record<string, ModuleResolution> = {}
setModules(modules: Record<string, ModuleResolution>) {
this.modules_ = modules
}
get modules(): ModulesResponse {
return Object.values(this.modules_ || {}).map((value) => ({
module: value.definition.key,
resolution: value.resolutionPath,
}))
}
}

View File

@@ -152,6 +152,23 @@ export class RemoteJoiner {
service.alias = [service.alias] service.alias = [service.alias]
} }
// handle alias.name as array
for (let idx = 0; idx < service.alias.length; idx++) {
const alias = service.alias[idx]
if (!Array.isArray(alias.name)) {
continue
}
for (const name of alias.name) {
service.alias.push({
name,
args: alias.args,
})
}
service.alias.splice(idx, 1)
idx--
}
// self-reference // self-reference
for (const alias of service.alias) { for (const alias of service.alias) {
if (this.serviceConfigCache.has(`alias_${alias.name}}`)) { if (this.serviceConfigCache.has(`alias_${alias.name}}`)) {
@@ -167,7 +184,7 @@ export class RemoteJoiner {
: undefined : undefined
service.relationships?.push({ service.relationships?.push({
alias: alias.name, alias: alias.name as string,
foreignKey: alias.name + "_id", foreignKey: alias.name + "_id",
primaryKey: "id", primaryKey: "id",
serviceName: service.serviceName!, serviceName: service.serviceName!,
@@ -250,7 +267,7 @@ export class RemoteJoiner {
private cacheServiceConfig( private cacheServiceConfig(
serviceConfigs, serviceConfigs,
serviceName?: string, serviceName?: string,
serviceAlias?: string serviceAlias?: string | string[]
): void { ): void {
if (serviceAlias) { if (serviceAlias) {
const name = `alias_${serviceAlias}` const name = `alias_${serviceAlias}`

View File

@@ -33,7 +33,13 @@ export async function runMigrations({
const migrator = orm.getMigrator() const migrator = orm.getMigrator()
const pendingMigrations = await migrator.getPendingMigrations() const pendingMigrations = await migrator.getPendingMigrations()
logger.info(`Running pending migrations: ${pendingMigrations}`) logger.info(
`Running pending migrations: ${JSON.stringify(
pendingMigrations,
null,
2
)}`
)
await migrator.up({ await migrator.up({
migrations: pendingMigrations.map((m) => m.name), migrations: pendingMigrations.map((m) => m.name),

View File

@@ -2,89 +2,101 @@ import { Migration } from "@mikro-orm/migrations"
export class Migration20230719100648 extends Migration { export class Migration20230719100648 extends Migration {
async up(): Promise<void> { async up(): Promise<void> {
try {
// Prevent from crashing if for some reason the migration is re run (example, typeorm and mikro orm does not have the same migration table)
await this.execute('SELECT 1 FROM "product" LIMIT 1;')
return
} catch {
// noop
}
this.addSql( this.addSql(
'create table "product_category" ("id" text not null, "name" text not null, "description" text not null default \'\', "handle" text not null, "mpath" text not null, "is_active" boolean not null default false, "is_internal" boolean not null default false, "rank" numeric not null default 0, "parent_category_id" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, constraint "product_category_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_category" ("id" text not null, "name" text not null, "description" text not null default \'\', "handle" text not null, "mpath" text not null, "is_active" boolean not null default false, "is_internal" boolean not null default false, "rank" numeric not null default 0, "parent_category_id" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, constraint "product_category_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_category_path" on "product_category" ("mpath");' 'create index IF NOT EXISTS "IDX_product_category_path" on "product_category" ("mpath");'
) )
this.addSql( this.addSql(
'alter table "product_category" add constraint "IDX_product_category_handle" unique ("handle");' 'alter table "product_category" add constraint "IDX_product_category_handle" unique ("handle");'
) )
this.addSql( this.addSql(
'create table "product_collection" ("id" text not null, "title" text not null, "handle" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_collection_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_collection" ("id" text not null, "title" text not null, "handle" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_collection_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_collection_deleted_at" on "product_collection" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_collection_deleted_at" on "product_collection" ("deleted_at");'
) )
this.addSql( this.addSql(
'alter table "product_collection" add constraint "IDX_product_collection_handle_unique" unique ("handle");' 'alter table "product_collection" add constraint "IDX_product_collection_handle_unique" unique ("handle");'
) )
this.addSql( this.addSql(
'create table "image" ("id" text not null, "url" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "image_pkey" primary key ("id"));' 'create table IF NOT EXISTS "image" ("id" text not null, "url" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "image_pkey" primary key ("id"));'
) )
this.addSql('create index "IDX_product_image_url" on "image" ("url");')
this.addSql( this.addSql(
'create index "IDX_product_image_deleted_at" on "image" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_image_url" on "image" ("url");'
)
this.addSql(
'create index IF NOT EXISTS "IDX_product_image_deleted_at" on "image" ("deleted_at");'
) )
this.addSql( this.addSql(
'create table "product_tag" ("id" text not null, "value" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_tag_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_tag" ("id" text not null, "value" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_tag_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_tag_deleted_at" on "product_tag" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_tag_deleted_at" on "product_tag" ("deleted_at");'
) )
this.addSql( this.addSql(
'create table "product_type" ("id" text not null, "value" text not null, "metadata" json null, "deleted_at" timestamptz null, constraint "product_type_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_type" ("id" text not null, "value" text not null, "metadata" json null, "deleted_at" timestamptz null, constraint "product_type_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_type_deleted_at" on "product_type" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_type_deleted_at" on "product_type" ("deleted_at");'
) )
this.addSql( this.addSql(
'create table "product" ("id" text not null, "title" text not null, "handle" text not null, "subtitle" text null, "description" text null, "is_giftcard" boolean not null default false, "status" text check ("status" in (\'draft\', \'proposed\', \'published\', \'rejected\')) not null, "thumbnail" text null, "weight" text null, "length" text null, "height" text null, "width" text null, "origin_country" text null, "hs_code" text null, "mid_code" text null, "material" text null, "collection_id" text null, "type_id" text null, "discountable" boolean not null default true, "external_id" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, "metadata" jsonb null, constraint "product_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product" ("id" text not null, "title" text not null, "handle" text not null, "subtitle" text null, "description" text null, "is_giftcard" boolean not null default false, "status" text check ("status" in (\'draft\', \'proposed\', \'published\', \'rejected\')) not null, "thumbnail" text null, "weight" text null, "length" text null, "height" text null, "width" text null, "origin_country" text null, "hs_code" text null, "mid_code" text null, "material" text null, "collection_id" text null, "type_id" text null, "discountable" boolean not null default true, "external_id" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, "metadata" jsonb null, constraint "product_pkey" primary key ("id"));'
) )
this.addSql('create index "IDX_product_type_id" on "product" ("type_id");')
this.addSql( this.addSql(
'create index "IDX_product_deleted_at" on "product" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_type_id" on "product" ("type_id");'
)
this.addSql(
'create index IF NOT EXISTS "IDX_product_deleted_at" on "product" ("deleted_at");'
) )
this.addSql( this.addSql(
'alter table "product" add constraint "IDX_product_handle_unique" unique ("handle");' 'alter table "product" add constraint "IDX_product_handle_unique" unique ("handle");'
) )
this.addSql( this.addSql(
'create table "product_option" ("id" text not null, "title" text not null, "product_id" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_option_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_option" ("id" text not null, "title" text not null, "product_id" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_option_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_option_product_id" on "product_option" ("product_id");' 'create index IF NOT EXISTS "IDX_product_option_product_id" on "product_option" ("product_id");'
) )
this.addSql( this.addSql(
'create index "IDX_product_option_deleted_at" on "product_option" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_option_deleted_at" on "product_option" ("deleted_at");'
) )
this.addSql( this.addSql(
'create table "product_tags" ("product_id" text not null, "product_tag_id" text not null, constraint "product_tags_pkey" primary key ("product_id", "product_tag_id"));' 'create table IF NOT EXISTS "product_tags" ("product_id" text not null, "product_tag_id" text not null, constraint "product_tags_pkey" primary key ("product_id", "product_tag_id"));'
) )
this.addSql( this.addSql(
'create table "product_images" ("product_id" text not null, "image_id" text not null, constraint "product_images_pkey" primary key ("product_id", "image_id"));' 'create table IF NOT EXISTS "product_images" ("product_id" text not null, "image_id" text not null, constraint "product_images_pkey" primary key ("product_id", "image_id"));'
) )
this.addSql( this.addSql(
'create table "product_category_product" ("product_id" text not null, "product_category_id" text not null, constraint "product_category_product_pkey" primary key ("product_id", "product_category_id"));' 'create table IF NOT EXISTS "product_category_product" ("product_id" text not null, "product_category_id" text not null, constraint "product_category_product_pkey" primary key ("product_id", "product_category_id"));'
) )
this.addSql( this.addSql(
'create table "product_variant" ("id" text not null, "title" text not null, "sku" text null, "barcode" text null, "ean" text null, "upc" text null, "inventory_quantity" numeric not null default 100, "allow_backorder" boolean not null default false, "manage_inventory" boolean not null default true, "hs_code" text null, "origin_country" text null, "mid_code" text null, "material" text null, "weight" numeric null, "length" numeric null, "height" numeric null, "width" numeric null, "metadata" jsonb null, "variant_rank" numeric null default 0, "product_id" text not null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "product_variant_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_variant" ("id" text not null, "title" text not null, "sku" text null, "barcode" text null, "ean" text null, "upc" text null, "inventory_quantity" numeric not null default 100, "allow_backorder" boolean not null default false, "manage_inventory" boolean not null default true, "hs_code" text null, "origin_country" text null, "mid_code" text null, "material" text null, "weight" numeric null, "length" numeric null, "height" numeric null, "width" numeric null, "metadata" jsonb null, "variant_rank" numeric null default 0, "product_id" text not null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, constraint "product_variant_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_variant_deleted_at" on "product_variant" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_variant_deleted_at" on "product_variant" ("deleted_at");'
) )
this.addSql( this.addSql(
'create index "IDX_product_variant_product_id" on "product_variant" ("product_id");' 'create index IF NOT EXISTS "IDX_product_variant_product_id" on "product_variant" ("product_id");'
) )
this.addSql( this.addSql(
'alter table "product_variant" add constraint "IDX_product_variant_sku_unique" unique ("sku");' 'alter table "product_variant" add constraint "IDX_product_variant_sku_unique" unique ("sku");'
@@ -100,16 +112,16 @@ export class Migration20230719100648 extends Migration {
) )
this.addSql( this.addSql(
'create table "product_option_value" ("id" text not null, "value" text not null, "option_id" text not null, "variant_id" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_option_value_pkey" primary key ("id"));' 'create table IF NOT EXISTS "product_option_value" ("id" text not null, "value" text not null, "option_id" text not null, "variant_id" text not null, "metadata" jsonb null, "deleted_at" timestamptz null, constraint "product_option_value_pkey" primary key ("id"));'
) )
this.addSql( this.addSql(
'create index "IDX_product_option_value_option_id" on "product_option_value" ("option_id");' 'create index IF NOT EXISTS "IDX_product_option_value_option_id" on "product_option_value" ("option_id");'
) )
this.addSql( this.addSql(
'create index "IDX_product_option_value_variant_id" on "product_option_value" ("variant_id");' 'create index IF NOT EXISTS "IDX_product_option_value_variant_id" on "product_option_value" ("variant_id");'
) )
this.addSql( this.addSql(
'create index "IDX_product_option_value_deleted_at" on "product_option_value" ("deleted_at");' 'create index IF NOT EXISTS "IDX_product_option_value_deleted_at" on "product_option_value" ("deleted_at");'
) )
this.addSql( this.addSql(

View File

@@ -1,69 +1,123 @@
import { Migration } from '@mikro-orm/migrations'; import { Migration } from "@mikro-orm/migrations"
export class Migration20230908084537 extends Migration { export class Migration20230908084537 extends Migration {
async up(): Promise<void> { async up(): Promise<void> {
this.addSql('alter table "product_category" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); this.addSql(
this.addSql('alter table "product_category" alter column "created_at" set default now();'); 'alter table "product_category" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'
this.addSql('alter table "product_category" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'); )
this.addSql('alter table "product_category" alter column "updated_at" set default now();'); this.addSql(
'alter table "product_category" alter column "created_at" set default now();'
)
this.addSql(
'alter table "product_category" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'
)
this.addSql(
'alter table "product_category" alter column "updated_at" set default now();'
)
this.addSql('alter table "product_collection" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now();'); this.addSql(
'alter table "product_collection" add column IF NOT EXISTS "created_at" timestamptz not null default now(), add column IF NOT EXISTS "updated_at" timestamptz not null default now();'
)
this.addSql('alter table "image" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now();'); this.addSql(
'alter table "image" add column IF NOT EXISTS "created_at" timestamptz not null default now(), add column IF NOT EXISTS "updated_at" timestamptz not null default now();'
)
this.addSql('alter table "product_tag" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now();'); this.addSql(
'alter table "product_tag" add column IF NOT EXISTS "created_at" timestamptz not null default now(), add column IF NOT EXISTS "updated_at" timestamptz not null default now();'
)
this.addSql('alter table "product_type" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now();'); this.addSql(
'alter table "product_type" add column IF NOT EXISTS "created_at" timestamptz not null default now(), add column IF NOT EXISTS "updated_at" timestamptz not null default now();'
)
this.addSql('alter table "product" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); this.addSql(
this.addSql('alter table "product" alter column "created_at" set default now();'); 'alter table "product" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'
this.addSql('alter table "product" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'); )
this.addSql('alter table "product" alter column "updated_at" set default now();'); this.addSql(
'alter table "product" alter column "created_at" set default now();'
)
this.addSql(
'alter table "product" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'
)
this.addSql(
'alter table "product" alter column "updated_at" set default now();'
)
this.addSql('alter table "product_option" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now();'); this.addSql(
'alter table "product_option" add column IF NOT EXISTS "created_at" timestamptz not null default now(), add column IF NOT EXISTS "updated_at" timestamptz not null default now();'
)
this.addSql('alter table "product_variant" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); this.addSql(
this.addSql('alter table "product_variant" alter column "created_at" set default now();'); 'alter table "product_variant" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'
this.addSql('alter table "product_variant" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'); )
this.addSql('alter table "product_variant" alter column "updated_at" set default now();'); this.addSql(
'alter table "product_variant" alter column "created_at" set default now();'
)
this.addSql(
'alter table "product_variant" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'
)
this.addSql(
'alter table "product_variant" alter column "updated_at" set default now();'
)
this.addSql('alter table "product_option_value" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now();'); this.addSql(
'alter table "product_option_value" add column IF NOT EXISTS "created_at" timestamptz not null default now(), add column IF NOT EXISTS "updated_at" timestamptz not null default now();'
)
} }
async down(): Promise<void> { async down(): Promise<void> {
this.addSql('alter table "product_category" alter column "created_at" drop default;'); this.addSql(
this.addSql('alter table "product_category" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); 'alter table "product_category" alter column "created_at" drop default;'
this.addSql('alter table "product_category" alter column "updated_at" drop default;'); )
this.addSql('alter table "product_category" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'); this.addSql(
'alter table "product_category" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'
)
this.addSql(
'alter table "product_category" alter column "updated_at" drop default;'
)
this.addSql(
'alter table "product_category" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'
)
this.addSql('alter table "product_collection" drop column "created_at";'); this.addSql('alter table "product_collection" drop column "created_at";')
this.addSql('alter table "product_collection" drop column "updated_at";'); this.addSql('alter table "product_collection" drop column "updated_at";')
this.addSql('alter table "image" drop column "created_at";'); this.addSql('alter table "image" drop column "created_at";')
this.addSql('alter table "image" drop column "updated_at";'); this.addSql('alter table "image" drop column "updated_at";')
this.addSql('alter table "product_tag" drop column "created_at";'); this.addSql('alter table "product_tag" drop column "created_at";')
this.addSql('alter table "product_tag" drop column "updated_at";'); this.addSql('alter table "product_tag" drop column "updated_at";')
this.addSql('alter table "product_type" drop column "created_at";'); this.addSql('alter table "product_type" drop column "created_at";')
this.addSql('alter table "product_type" drop column "updated_at";'); this.addSql('alter table "product_type" drop column "updated_at";')
this.addSql('alter table "product" alter column "created_at" drop default;'); this.addSql('alter table "product" alter column "created_at" drop default;')
this.addSql('alter table "product" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); this.addSql(
this.addSql('alter table "product" alter column "updated_at" drop default;'); 'alter table "product" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'
this.addSql('alter table "product" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'); )
this.addSql('alter table "product" alter column "updated_at" drop default;')
this.addSql(
'alter table "product" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'
)
this.addSql('alter table "product_option" drop column "created_at";'); this.addSql('alter table "product_option" drop column "created_at";')
this.addSql('alter table "product_option" drop column "updated_at";'); this.addSql('alter table "product_option" drop column "updated_at";')
this.addSql('alter table "product_variant" alter column "created_at" drop default;'); this.addSql(
this.addSql('alter table "product_variant" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); 'alter table "product_variant" alter column "created_at" drop default;'
this.addSql('alter table "product_variant" alter column "updated_at" drop default;'); )
this.addSql('alter table "product_variant" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'); this.addSql(
'alter table "product_variant" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'
)
this.addSql(
'alter table "product_variant" alter column "updated_at" drop default;'
)
this.addSql(
'alter table "product_variant" alter column "updated_at" type timestamptz using ("updated_at"::timestamptz);'
)
this.addSql('alter table "product_option_value" drop column "created_at";'); this.addSql('alter table "product_option_value" drop column "created_at";')
this.addSql('alter table "product_option_value" drop column "updated_at";'); this.addSql('alter table "product_option_value" drop column "updated_at";')
} }
} }

View File

@@ -33,7 +33,13 @@ export async function runMigrations({
const migrator = orm.getMigrator() const migrator = orm.getMigrator()
const pendingMigrations = await migrator.getPendingMigrations() const pendingMigrations = await migrator.getPendingMigrations()
logger.info(`Running pending migrations: ${pendingMigrations}`) logger.info(
`Running pending migrations: ${JSON.stringify(
pendingMigrations,
null,
2
)}`
)
await migrator.up({ await migrator.up({
migrations: pendingMigrations.map((m) => m.name), migrations: pendingMigrations.map((m) => m.name),

View File

@@ -1,17 +1,22 @@
import { ModuleJoinerConfig } from "@medusajs/types" import { ModuleJoinerConfig } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk" import { Modules } from "@medusajs/modules-sdk"
import { StockLocation } from "./models" import { StockLocation } from "./models"
import moduleSchema from "./schema"
export const joinerConfig: ModuleJoinerConfig = { export const joinerConfig: ModuleJoinerConfig = {
serviceName: Modules.STOCK_LOCATION, serviceName: Modules.STOCK_LOCATION,
primaryKeys: ["id"], primaryKeys: ["id"],
linkableKeys: { stock_location_id: StockLocation.name }, linkableKeys: {
stock_location_id: StockLocation.name,
location_id: StockLocation.name,
},
schema: moduleSchema,
alias: [ alias: [
{ {
name: "stock_location", name: ["stock_location", "stock_locations"],
}, args: {
{ entity: "StockLocation",
name: "stock_locations", },
}, },
], ],
} }

View File

@@ -0,0 +1,29 @@
export default `
scalar DateTime
scalar JSON
type StockLocation {
id: ID!
created_at: DateTime!
updated_at: DateTime!
deleted_at: DateTime
name: String!
address_id: String
address: StockLocationAddress
metadata: JSON
}
type StockLocationAddress {
id: ID!
created_at: DateTime!
updated_at: DateTime!
deleted_at: DateTime
address_1: String!
address_2: String
company: String
city: String
country_code: String!
phone: String
province: String
postal_code: String
metadata: JSON
}
`

View File

@@ -53,9 +53,7 @@ export type ConfigModule = {
featureFlags: Record<string, boolean | string> featureFlags: Record<string, boolean | string>
modules?: Record< modules?: Record<
string, string,
| false boolean | Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
| string
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
> >
plugins: ( plugins: (
| { | {

View File

@@ -23,7 +23,7 @@ export type JoinerRelationship = {
} }
export interface JoinerServiceConfigAlias { export interface JoinerServiceConfigAlias {
name: string name: string | string[]
/** /**
* Extra arguments to pass to the remoteFetchData callback * Extra arguments to pass to the remoteFetchData callback
*/ */

View File

@@ -3,4 +3,6 @@ export const ContainerRegistrationKeys = {
MANAGER: "manager", MANAGER: "manager",
CONFIG_MODULE: "configModule", CONFIG_MODULE: "configModule",
LOGGER: "logger", LOGGER: "logger",
REMOTE_QUERY: "remoteQuery",
REMOTE_LINK: "remoteLink",
} }