diff --git a/.changeset/rich-dragons-roll.md b/.changeset/rich-dragons-roll.md new file mode 100644 index 0000000000000..bde6ef98589ec --- /dev/null +++ b/.changeset/rich-dragons-roll.md @@ -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 diff --git a/integration-tests/environment-helpers/bootstrap-app.js b/integration-tests/environment-helpers/bootstrap-app.js index 13a1ce01501a7..1ea6169a42f76 100644 --- a/integration-tests/environment-helpers/bootstrap-app.js +++ b/integration-tests/environment-helpers/bootstrap-app.js @@ -14,15 +14,17 @@ async function bootstrapApp({ cwd, env = {} } = {}) { const loaders = require("@medusajs/medusa/dist/loaders").default - const { container, dbConnection, pgConnection } = await loaders({ - directory: path.resolve(cwd || process.cwd()), - expressApp: app, - isTest: false, - }) + const { container, dbConnection, pgConnection, disposeResources } = + await loaders({ + directory: path.resolve(cwd || process.cwd()), + expressApp: app, + isTest: false, + }) const PORT = await getPort() return { + disposeResources, container, db: dbConnection, pgConnection, @@ -55,6 +57,7 @@ module.exports = { expressServer.close(), db?.destroy(), pgConnection?.context?.destroy(), + container.dispose(), ]) if (typeof global !== "undefined" && global?.gc) { diff --git a/integration-tests/plugins/jest.config.js b/integration-tests/plugins/jest.config.js index 298282f80931f..0134f98931790 100644 --- a/integration-tests/plugins/jest.config.js +++ b/integration-tests/plugins/jest.config.js @@ -9,6 +9,7 @@ module.exports = { `/www/`, `/dist/`, `/node_modules/`, + "/node_modules", `__tests__/fixtures`, `__testfixtures__`, `.cache`, diff --git a/packages/event-bus-local/src/services/event-bus-local.ts b/packages/event-bus-local/src/services/event-bus-local.ts index e45b3a57a2533..418ba6cd3b9a5 100644 --- a/packages/event-bus-local/src/services/event-bus-local.ts +++ b/packages/event-bus-local/src/services/event-bus-local.ts @@ -13,7 +13,7 @@ eventEmitter.setMaxListeners(Infinity) // eslint-disable-next-line max-len export default class LocalEventBusService extends AbstractEventBusModuleService { - protected readonly logger_: Logger + protected readonly logger_?: Logger protected readonly eventEmitter_: EventEmitter constructor({ logger }: MedusaContainer & InjectedDependencies) { @@ -53,7 +53,7 @@ export default class LocalEventBusService extends AbstractEventBusModuleService event.eventName ) - this.logger_.info( + this.logger_?.info( `Processing ${event.eventName} which has ${eventListenersCount} subscribers` ) @@ -73,7 +73,7 @@ export default class LocalEventBusService extends AbstractEventBusModuleService // @ts-ignore await subscriber(...args) } catch (e) { - this.logger_.error( + this.logger_?.error( `An error occurred while processing ${event.toString()}: ${e}` ) } diff --git a/packages/link-modules/src/migration/index.ts b/packages/link-modules/src/migration/index.ts index 7f70784727a98..1e71cb4c0a900 100644 --- a/packages/link-modules/src/migration/index.ts +++ b/packages/link-modules/src/migration/index.ts @@ -46,7 +46,7 @@ export function getMigration( const generator = orm.getSchemaGenerator() if (hasTable) { - const updateSql = await generator.getUpdateSchemaSQL() + /* const updateSql = await generator.getUpdateSchemaSQL() const entityUpdates = updateSql .split(";") .map((sql) => sql.trim()) @@ -65,7 +65,10 @@ export function getMigration( } } else { 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 { try { await generator.createSchema() diff --git a/packages/link-modules/src/utils/generate-schema.ts b/packages/link-modules/src/utils/generate-schema.ts index 410b523d71d6d..bb8dd23aa1a85 100644 --- a/packages/link-modules/src/utils/generate-schema.ts +++ b/packages/link-modules/src/utils/generate-schema.ts @@ -6,20 +6,72 @@ import { composeTableName } from "./compose-link-name" export function generateGraphQLSchema( joinerConfig: ModuleJoinerConfig, primary: ModuleJoinerRelationship, - foreign: ModuleJoinerRelationship + foreign: ModuleJoinerRelationship, + { logger }: { logger } = { logger: console } ) { - const fieldNames = primary.foreignKey.split(",").concat(foreign.foreignKey) - - const entityName = toPascalCase( - "Link_" + - (joinerConfig.databaseConfig?.tableName ?? - composeTableName( - primary.serviceName, - primary.foreignKey, - foreign.serviceName, - foreign.foreignKey - )) - ) + let fieldNames!: string[] + let entityName!: string + + if (!joinerConfig.isReadOnlyLink) { + fieldNames = primary.foreignKey.split(",").concat(foreign.foreignKey) + + entityName = toPascalCase( + "Link_" + + (joinerConfig.databaseConfig?.tableName ?? + composeTableName( + 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 const fields = fieldNames.reduce((acc, curr) => { @@ -48,7 +100,7 @@ export function generateGraphQLSchema( composeTableName(foreign.serviceName) )}` - let typeDef = ` + typeDef += ` type ${entityName} { ${(Object.entries(fields) as any) .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 } diff --git a/packages/medusa-core-utils/src/parse-cors-origins.ts b/packages/medusa-core-utils/src/parse-cors-origins.ts index 86ea1a7df666c..db5201a7d0fec 100644 --- a/packages/medusa-core-utils/src/parse-cors-origins.ts +++ b/packages/medusa-core-utils/src/parse-cors-origins.ts @@ -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)[] { - return str.split(",").map((subStr) => { - return buildRegexpIfValid(subStr) ?? subStr - }) + return !str + ? [] + : str.split(",").map((subStr) => { + return buildRegexpIfValid(subStr) ?? subStr + }) } diff --git a/packages/medusa/src/api/routes/admin/store/get-store.ts b/packages/medusa/src/api/routes/admin/store/get-store.ts index 64b6e1af091f0..2ea3b28e75e11 100644 --- a/packages/medusa/src/api/routes/admin/store/get-store.ts +++ b/packages/medusa/src/api/routes/admin/store/get-store.ts @@ -1,4 +1,3 @@ -import { ModulesHelper } from "@medusajs/modules-sdk" import { FlagRouter } from "@medusajs/utils" import { defaultRelationsExtended } from "." import { @@ -7,6 +6,7 @@ import { StoreService, } from "../../../../services" import { ExtendedStoreDTO } from "../../../../types/store" +import { MedusaModule } from "@medusajs/modules-sdk" /** * @oas [get] /admin/store @@ -62,7 +62,6 @@ export default async (req, res) => { const storeService: StoreService = req.scope.resolve("storeService") const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - const modulesHelper: ModulesHelper = req.scope.resolve("modulesHelper") const paymentProviderService: PaymentProviderService = req.scope.resolve( "paymentProviderService" @@ -80,7 +79,16 @@ export default async (req, res) => { })) as ExtendedStoreDTO 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 fulfillmentProviders = await fulfillmentProviderService.list() diff --git a/packages/medusa/src/commands/seed.ts b/packages/medusa/src/commands/seed.ts index 5cc4a5ea110d1..6d4809dec4d62 100644 --- a/packages/medusa/src/commands/seed.ts +++ b/packages/medusa/src/commands/seed.ts @@ -12,23 +12,24 @@ import { } from "../services" 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 IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain" -import Logger from "../loaders/logger" -import PublishableApiKeyService from "../services/publishable-api-key" -import { SalesChannel } from "../models" -import { sync as existsSync } from "fs-exists-cached" import express from "express" -import featureFlagLoader from "../loaders/feature-flags" import fs from "fs" +import { sync as existsSync } from "fs-exists-cached" import { getConfigFile } from "medusa-core-utils" -import { handleConfigError } from "../loaders/config" -import loaders from "../loaders" -import path from "path" 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 Logger from "../loaders/logger" +import { SalesChannel } from "../models" +import PublishableApiKeyService from "../services/publishable-api-key" +import { ConfigModule } from "../types/global" +import { CreateProductInput } from "../types/product" +import { CreateProductCategoryInput } from "../types/product-category" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" type SeedOptions = { directory: string @@ -122,7 +123,7 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) { "shippingProfileService" ) const pricingModuleService: IPricingModuleService = container.resolve( - "pricingModuleService" + ModuleRegistrationName.PRICING ) /* eslint-enable */ diff --git a/packages/medusa/src/commands/utils/get-migrations.js b/packages/medusa/src/commands/utils/get-migrations.js index c4dc61e219d17..ee9898f2f1668 100644 --- a/packages/medusa/src/commands/utils/get-migrations.js +++ b/packages/medusa/src/commands/utils/get-migrations.js @@ -1,4 +1,4 @@ -import { MedusaModule, registerModules } from "@medusajs/modules-sdk" +import { MedusaModule, registerMedusaModule } from "@medusajs/modules-sdk" import fs from "fs" import { sync as existsSync } from "fs-exists-cached" import glob from "glob" @@ -96,8 +96,13 @@ function resolvePlugin(pluginName) { export function getInternalModules(configModule) { 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)) { if ( @@ -256,7 +261,12 @@ export const getModuleSharedResources = (configModule, featureFlagsRouter) => { } 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)) { if ( @@ -276,7 +286,12 @@ export const runIsolatedModulesMigration = 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)) { if ( diff --git a/packages/medusa/src/helpers/test-request.js b/packages/medusa/src/helpers/test-request.js index d83fe71518b29..201b2e14316b3 100644 --- a/packages/medusa/src/helpers/test-request.js +++ b/packages/medusa/src/helpers/test-request.js @@ -3,7 +3,6 @@ import { moduleLoader, ModulesDefinition, registerMedusaModule, - registerModules, } from "@medusajs/modules-sdk" import { asValue, createContainer } from "awilix" import express from "express" @@ -19,7 +18,6 @@ import passportLoader from "../loaders/passport" import repositories from "../loaders/repositories" import servicesLoader from "../loaders/services" import strategiesLoader from "../loaders/strategies" -import modules from "../modules-config" const adminSessionOpts = { cookieName: "session", @@ -33,12 +31,13 @@ const clientSessionOpts = { secret: "test", } -const moduleResolutions = registerModules({}) -// Load non legacy modules -Object.keys(modules).map((moduleKey) => { +const moduleResolutions = {} +Object.entries(ModulesDefinition).forEach(([moduleKey, module]) => { moduleResolutions[moduleKey] = registerMedusaModule( moduleKey, - ModulesDefinition[moduleKey] + module.defaultModuleDeclaration, + undefined, + module )[moduleKey] }) @@ -84,7 +83,7 @@ container.register("modulesHelper", asValue(moduleHelper)) container.register("configModule", asValue(config)) container.register({ logger: asValue({ - error: () => { }, + error: () => {}, }), manager: asValue(MockManager), }) @@ -146,7 +145,10 @@ export async function request(method, url, opts = {}) { headers.Cookie = headers.Cookie || "" if (opts.adminSession) { 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 ) @@ -154,7 +156,11 @@ export async function request(method, url, opts = {}) { } if (opts.clientSession) { 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 ) diff --git a/packages/medusa/src/loaders/index.ts b/packages/medusa/src/loaders/index.ts index d2e8904900f24..5fa4c390027ad 100644 --- a/packages/medusa/src/loaders/index.ts +++ b/packages/medusa/src/loaders/index.ts @@ -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 databaseLoader, { dataSource } from "./database" @@ -17,10 +21,8 @@ import loadConfig from "./config" import defaultsLoader from "./defaults" import expressLoader from "./express" 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 loadMedusaApp from "./medusa-app" +import loadMedusaApp, { mergeDefaultModules } from "./medusa-app" import modelsLoader from "./models" import passportLoader from "./passport" import pgConnectionLoader from "./pg-connection" @@ -37,6 +39,34 @@ type Options = { 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 ({ directory: rootDirectory, expressApp, @@ -98,16 +128,8 @@ export default async ({ const pgConnection = await pgConnectionLoader({ container, configModule }) - const modulesActivity = Logger.activity(`Initializing modules${EOL}`) - - 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 configModules = mergeDefaultModules(configModule.modules) + await loadLegacyModulesEntities(configModules, container) const dbActivity = Logger.activity(`Initializing database${EOL}`) track("DATABASE_INIT_STARTED") @@ -129,13 +151,6 @@ export default async ({ }) 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}`) track("SERVICES_INIT_STARTED") @@ -143,6 +158,18 @@ export default async ({ const servAct = Logger.success(servicesActivity, "Services initialized") || {} 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}`) track("EXPRESS_INIT_STARTED") await expressLoader({ app: expressApp, configModule }) @@ -196,5 +223,10 @@ export default async ({ Logger.success(searchActivity, "Indexing event emitted") || {} track("SEARCH_ENGINE_INDEXING_COMPLETED", { duration: searchAct.duration }) - return { container, dbConnection, app: expressApp, pgConnection } + return { + container, + dbConnection, + app: expressApp, + pgConnection, + } } diff --git a/packages/medusa/src/loaders/medusa-app.ts b/packages/medusa/src/loaders/medusa-app.ts index 27c5c95176a16..adc221a5555cc 100644 --- a/packages/medusa/src/loaders/medusa-app.ts +++ b/packages/medusa/src/loaders/medusa-app.ts @@ -1,26 +1,51 @@ -import { CommonTypes, MedusaContainer } from "@medusajs/types" +import { + CommonTypes, + InternalModuleDeclaration, + MedusaContainer, + ModuleDefinition, +} from "@medusajs/types" import { MedusaApp, MedusaAppOutput, ModulesDefinition, } from "@medusajs/modules-sdk" -import { ContainerRegistrationKeys } from "@medusajs/utils" +import { ContainerRegistrationKeys, isObject } from "@medusajs/utils" import { asValue } from "awilix" import { joinerConfig } from "../joiner-config" -import { mergeModulesConfig } from "../utils/merge-modules-config" -import modulesConfig from "../modules-config" 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 ( { configModule, container, - }: { configModule: CommonTypes.ConfigModule; container: MedusaContainer }, + }: { + configModule: { + modules?: CommonTypes.ConfigModule["modules"] + projectConfig: CommonTypes.ConfigModule["projectConfig"] + } + container: MedusaContainer + }, config = { registerInContainer: true } ): Promise => { - mergeModulesConfig(configModule.modules ?? {}, modulesConfig) - const injectedDependencies = { [ContainerRegistrationKeys.PG_CONNECTION]: container.resolve( 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 + ).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({ - modulesConfig, + modulesConfig: configModules, servicesConfig: joinerConfig, remoteFetchData: remoteQueryFetchData(container), sharedContainer: container, @@ -48,18 +99,25 @@ export const loadMedusaApp = async ( } container.register("remoteLink", asValue(medusaApp.link)) + container.register( + ContainerRegistrationKeys.REMOTE_QUERY, + asValue(medusaApp.query) + ) - const { query, modules } = medusaApp - - // 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)) { + for (const [serviceKey, moduleService] of Object.entries(medusaApp.modules)) { container.register( ModulesDefinition[serviceKey].registrationName, 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 } diff --git a/packages/medusa/src/loaders/pg-connection.ts b/packages/medusa/src/loaders/pg-connection.ts index cfd6ac3068320..e86cb1567dfba 100644 --- a/packages/medusa/src/loaders/pg-connection.ts +++ b/packages/medusa/src/loaders/pg-connection.ts @@ -1,5 +1,5 @@ import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils" -import { AwilixContainer, asValue } from "awilix" +import { asValue, AwilixContainer } from "awilix" import { ConfigModule } from "../types/global" type Options = { @@ -9,7 +9,7 @@ type Options = { export default async ({ container, configModule }: Options): Promise => { if (container.hasRegistration(ContainerRegistrationKeys.PG_CONNECTION)) { - return + return container.resolve(ContainerRegistrationKeys.PG_CONNECTION) } // Share a knex connection to be consumed by the shared modules diff --git a/packages/medusa/src/modules-config.ts b/packages/medusa/src/modules-config.ts index 59c6f0361908b..19887336a30b0 100644 --- a/packages/medusa/src/modules-config.ts +++ b/packages/medusa/src/modules-config.ts @@ -2,6 +2,7 @@ import { MedusaModuleConfig, Modules } from "@medusajs/modules-sdk" const modules: MedusaModuleConfig = { [Modules.PRODUCT]: true, + [Modules.PRICING]: true, } export default modules diff --git a/packages/medusa/src/services/event-bus.ts b/packages/medusa/src/services/event-bus.ts index b5411ecafb612..15d572ae24c95 100644 --- a/packages/medusa/src/services/event-bus.ts +++ b/packages/medusa/src/services/event-bus.ts @@ -27,14 +27,17 @@ export default class EventBusService protected readonly config_: ConfigModule protected readonly stagedJobService_: StagedJobService // 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 shouldEnqueuerRun: boolean protected enqueue_: Promise constructor( - { stagedJobService, eventBusModuleService, logger }: InjectedDependencies, + { stagedJobService, logger }: InjectedDependencies, config, isSingleton = true ) { @@ -43,7 +46,6 @@ export default class EventBusService this.logger_ = logger this.config_ = config - this.eventBusModuleService_ = eventBusModuleService this.stagedJobService_ = stagedJobService if (process.env.NODE_ENV !== "test" && isSingleton) { diff --git a/packages/medusa/src/services/order-edit.ts b/packages/medusa/src/services/order-edit.ts index c6a01430eb0a9..78610f4789814 100644 --- a/packages/medusa/src/services/order-edit.ts +++ b/packages/medusa/src/services/order-edit.ts @@ -70,7 +70,10 @@ export default class OrderEditService extends TransactionBaseService { protected readonly taxProviderService_: TaxProviderService protected readonly lineItemAdjustmentService_: LineItemAdjustmentService protected readonly orderEditItemChangeService_: OrderEditItemChangeService - protected readonly inventoryService_: IInventoryService | undefined + + protected get inventoryService_(): IInventoryService | undefined { + return this.__container__.inventoryService + } constructor({ orderEditRepository, @@ -82,7 +85,6 @@ export default class OrderEditService extends TransactionBaseService { orderEditItemChangeService, lineItemAdjustmentService, taxProviderService, - inventoryService, }: InjectedDependencies) { // eslint-disable-next-line prefer-rest-params super(arguments[0]) @@ -96,7 +98,6 @@ export default class OrderEditService extends TransactionBaseService { this.orderEditItemChangeService_ = orderEditItemChangeService this.lineItemAdjustmentService_ = lineItemAdjustmentService this.taxProviderService_ = taxProviderService - this.inventoryService_ = inventoryService } async retrieve( diff --git a/packages/medusa/src/services/pricing.ts b/packages/medusa/src/services/pricing.ts index 891db6674176d..928eff746ca44 100644 --- a/packages/medusa/src/services/pricing.ts +++ b/packages/medusa/src/services/pricing.ts @@ -2,7 +2,6 @@ import { CalculatedPriceSetDTO, IPricingModuleService, PriceSetMoneyAmountDTO, - RemoteJoinerQuery, RemoteQueryFunction, } from "@medusajs/types" import { FlagRouter, removeNullish } from "@medusajs/utils" @@ -56,8 +55,13 @@ class PricingService extends TransactionBaseService { protected readonly priceSelectionStrategy: IPriceSelectionStrategy protected readonly productVariantService: ProductVariantService 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({ productVariantService, @@ -65,8 +69,6 @@ class PricingService extends TransactionBaseService { regionService, priceSelectionStrategy, featureFlagRouter, - remoteQuery, - pricingModuleService, }: InjectedDependencies) { // eslint-disable-next-line prefer-rest-params super(arguments[0]) @@ -76,8 +78,6 @@ class PricingService extends TransactionBaseService { this.priceSelectionStrategy = priceSelectionStrategy this.productVariantService = productVariantService this.featureFlagRouter = featureFlagRouter - this.pricingModuleService = pricingModuleService - this.remoteQuery = remoteQuery } /** diff --git a/packages/medusa/src/services/product-variant-inventory.ts b/packages/medusa/src/services/product-variant-inventory.ts index 1900c0a3cae3f..4a24c40cf39cd 100644 --- a/packages/medusa/src/services/product-variant-inventory.ts +++ b/packages/medusa/src/services/product-variant-inventory.ts @@ -1,6 +1,5 @@ import { EntityManager, In } from "typeorm" import { - ICacheService, IEventBusService, IInventoryService, InventoryItemDTO, @@ -42,17 +41,20 @@ class ProductVariantInventoryService extends TransactionBaseService { protected readonly salesChannelLocationService_: SalesChannelLocationService protected readonly salesChannelInventoryService_: SalesChannelInventoryService protected readonly productVariantService_: ProductVariantService - protected readonly stockLocationService_: IStockLocationService - protected readonly inventoryService_: IInventoryService 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({ - stockLocationService, salesChannelLocationService, salesChannelInventoryService, productVariantService, - inventoryService, eventBusService, }: InjectedDependencies) { // eslint-disable-next-line prefer-rest-params @@ -60,9 +62,7 @@ class ProductVariantInventoryService extends TransactionBaseService { this.salesChannelLocationService_ = salesChannelLocationService this.salesChannelInventoryService_ = salesChannelInventoryService - this.stockLocationService_ = stockLocationService this.productVariantService_ = productVariantService - this.inventoryService_ = inventoryService this.eventBusService_ = eventBusService } diff --git a/packages/medusa/src/services/sales-channel-inventory.ts b/packages/medusa/src/services/sales-channel-inventory.ts index b4479ee1f4f22..b38d23f2ec8e1 100644 --- a/packages/medusa/src/services/sales-channel-inventory.ts +++ b/packages/medusa/src/services/sales-channel-inventory.ts @@ -13,11 +13,13 @@ type InjectedDependencies = { class SalesChannelInventoryService extends TransactionBaseService { protected readonly salesChannelLocationService_: SalesChannelLocationService protected readonly eventBusService_: EventBusTypes.IEventBusService - protected readonly inventoryService_: IInventoryService + + protected get inventoryService_(): IInventoryService { + return this.__container__.inventoryService + } constructor({ salesChannelLocationService, - inventoryService, eventBusService, }: InjectedDependencies) { // eslint-disable-next-line prefer-rest-params @@ -25,7 +27,6 @@ class SalesChannelInventoryService extends TransactionBaseService { this.salesChannelLocationService_ = salesChannelLocationService this.eventBusService_ = eventBusService - this.inventoryService_ = inventoryService } /** diff --git a/packages/medusa/src/services/sales-channel-location.ts b/packages/medusa/src/services/sales-channel-location.ts index 9241cb99f2d4a..c15147dffd60c 100644 --- a/packages/medusa/src/services/sales-channel-location.ts +++ b/packages/medusa/src/services/sales-channel-location.ts @@ -19,19 +19,17 @@ type InjectedDependencies = { class SalesChannelLocationService extends TransactionBaseService { protected readonly salesChannelService_: SalesChannelService protected readonly eventBusService_: IEventBusService - protected readonly stockLocationService_: IStockLocationService - constructor({ - salesChannelService, - stockLocationService, - eventBusService, - }: InjectedDependencies) { + protected get stockLocationService_(): IStockLocationService { + return this.__container__.stockLocationService + } + + constructor({ salesChannelService, eventBusService }: InjectedDependencies) { // eslint-disable-next-line prefer-rest-params super(arguments[0]) this.salesChannelService_ = salesChannelService this.eventBusService_ = eventBusService - this.stockLocationService_ = stockLocationService } /** diff --git a/packages/medusa/src/utils/merge-modules-config.ts b/packages/medusa/src/utils/merge-modules-config.ts index cd238cc400afa..e6f6793faec46 100644 --- a/packages/medusa/src/utils/merge-modules-config.ts +++ b/packages/medusa/src/utils/merge-modules-config.ts @@ -1,11 +1,6 @@ -import { - ConfigModule, - ExternalModuleDeclaration, - InternalModuleDeclaration, -} from "@medusajs/types" +import { ConfigModule } from "@medusajs/types" 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 @@ -13,24 +8,30 @@ import { isObject } from "./is-object" * @param medusaInternalModulesConfig */ export function mergeModulesConfig( - modules: ConfigModule["modules"], - medusaInternalModulesConfig + modules: ConfigModule["modules"] = {}, + 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] if (moduleDefinition?.isLegacy) { continue } - const isModuleEnabled = moduleConfig === true || isObject(moduleConfig) - - if (!isModuleEnabled) { - delete medusaInternalModulesConfig[moduleName] - } else { - medusaInternalModulesConfig[moduleName] = moduleConfig as Partial< - InternalModuleDeclaration | ExternalModuleDeclaration - > - } + modules_[moduleName] ??= internalModuleConfig } + + return modules_ } diff --git a/packages/modules-sdk/src/index.ts b/packages/modules-sdk/src/index.ts index 5c27d7aebdb13..62b018aa42211 100644 --- a/packages/modules-sdk/src/index.ts +++ b/packages/modules-sdk/src/index.ts @@ -3,6 +3,5 @@ export * from "./definitions" export * from "./loaders" export * from "./medusa-app" export * from "./medusa-module" -export * from "./module-helper" export * from "./remote-link" export * from "./remote-query" diff --git a/packages/modules-sdk/src/loaders/__tests__/register-modules.ts b/packages/modules-sdk/src/loaders/__tests__/register-modules.ts index 1b71534323e30..147d95562749e 100644 --- a/packages/modules-sdk/src/loaders/__tests__/register-modules.ts +++ b/packages/modules-sdk/src/loaders/__tests__/register-modules.ts @@ -4,8 +4,8 @@ import { MODULE_SCOPE, ModuleDefinition, } from "@medusajs/types" -import MODULE_DEFINITIONS from "../../definitions" -import { registerModules } from "../register-modules" +import { ModulesDefinition } from "../../definitions" +import { registerMedusaModule } from "../register-modules" const RESOLVED_PACKAGE = "@medusajs/test-service-resolved" jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE)) @@ -30,13 +30,18 @@ describe("module definitions loader", () => { jest.clearAllMocks() // 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", () => { - MODULE_DEFINITIONS.push({ ...defaultDefinition }) + Object.assign(ModulesDefinition, { + [defaultDefinition.key]: defaultDefinition, + }) - const res = registerModules({}) + const res = registerMedusaModule(defaultDefinition.key) expect(res[defaultDefinition.key]).toEqual( expect.objectContaining({ @@ -53,9 +58,11 @@ describe("module definitions loader", () => { describe("boolean config", () => { 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.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", () => { expect.assertions(1) - MODULE_DEFINITIONS.push({ ...defaultDefinition, isRequired: true }) + Object.assign(ModulesDefinition, { + [defaultDefinition.key]: { ...defaultDefinition, isRequired: true }, + }) try { - registerModules({ [defaultDefinition.key]: false }) + registerMedusaModule(defaultDefinition.key, false) } catch (err) { expect(err.message).toEqual( `Module: ${defaultDefinition.label} is required` @@ -87,9 +96,11 @@ describe("module definitions loader", () => { 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.objectContaining({ @@ -106,12 +117,15 @@ describe("module definitions loader", () => { describe("string config", () => { it("Resolves module with default definition given empty config", () => { - MODULE_DEFINITIONS.push({ ...defaultDefinition }) - - const res = registerModules({ - [defaultDefinition.key]: defaultDefinition.defaultPackage, + Object.assign(ModulesDefinition, { + [defaultDefinition.key]: defaultDefinition, }) + const res = registerMedusaModule( + defaultDefinition.key, + defaultDefinition.defaultPackage + ) + expect(res[defaultDefinition.key]).toEqual( expect.objectContaining({ resolutionPath: RESOLVED_PACKAGE, @@ -128,16 +142,16 @@ describe("module definitions loader", () => { describe("object config", () => { it("Resolves resolution path and provides empty options when none are provided", () => { - MODULE_DEFINITIONS.push({ ...defaultDefinition }) - - const res = registerModules({ - [defaultDefinition.key]: { - scope: MODULE_SCOPE.INTERNAL, - resolve: defaultDefinition.defaultPackage, - resources: MODULE_RESOURCE_TYPE.ISOLATED, - } as InternalModuleDeclaration, + Object.assign(ModulesDefinition, { + [defaultDefinition.key]: defaultDefinition, }) + 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.objectContaining({ resolutionPath: RESOLVED_PACKAGE, @@ -153,12 +167,12 @@ describe("module definitions loader", () => { }) 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({ - [defaultDefinition.key]: { - options: { test: 123 }, - }, + const res = registerMedusaModule(defaultDefinition.key, { + options: { test: 123 }, } as any) 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", () => { - MODULE_DEFINITIONS.push({ ...defaultDefinition }) + Object.assign(ModulesDefinition, { + [defaultDefinition.key]: defaultDefinition, + }) - const res = registerModules({ - [defaultDefinition.key]: { - resolve: defaultDefinition.defaultPackage, - options: { test: 123 }, - scope: "internal", - resources: "isolated", - }, + const res = registerMedusaModule(defaultDefinition.key, { + resolve: defaultDefinition.defaultPackage, + options: { test: 123 }, + scope: "internal", + resources: "isolated", } as any) expect(res[defaultDefinition.key]).toEqual( diff --git a/packages/modules-sdk/src/loaders/module-loader.ts b/packages/modules-sdk/src/loaders/module-loader.ts index 0b04f7406249c..e590c881beeb7 100644 --- a/packages/modules-sdk/src/loaders/module-loader.ts +++ b/packages/modules-sdk/src/loaders/module-loader.ts @@ -1,17 +1,14 @@ import { Logger, - MODULE_SCOPE, MedusaContainer, + MODULE_SCOPE, ModuleResolution, } from "@medusajs/types" import { asValue } from "awilix" import { EOL } from "os" -import { ModulesHelper } from "../module-helper" import { loadInternalModule } from "./utils" -export const moduleHelper = new ModulesHelper() - export const moduleLoader = async ({ container, 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( diff --git a/packages/modules-sdk/src/loaders/register-modules.ts b/packages/modules-sdk/src/loaders/register-modules.ts index f49ce3c8a1d51..af0ebdc6092f1 100644 --- a/packages/modules-sdk/src/loaders/register-modules.ts +++ b/packages/modules-sdk/src/loaders/register-modules.ts @@ -9,57 +9,11 @@ import { import { isObject } from "@medusajs/utils" import resolveCwd from "resolve-cwd" -import { MODULE_DEFINITIONS, 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 - >, - { loadLegacyOnly } = { loadLegacyOnly: false } -): Record => { - const moduleResolutions = {} as Record - 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 -} +import { ModulesDefinition } from "../definitions" export const registerMedusaModule = ( moduleKey: string, - moduleDeclaration: + moduleDeclaration?: | Partial | string | false, @@ -74,9 +28,17 @@ export const registerMedusaModule = ( 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 ( - isObject(moduleDeclaration) && - moduleDeclaration?.scope === MODULE_SCOPE.EXTERNAL + isObject(modDeclaration) && + modDeclaration?.scope === MODULE_SCOPE.EXTERNAL ) { // TODO: getExternalModuleResolution(...) throw new Error("External Modules are not supported yet.") diff --git a/packages/modules-sdk/src/loaders/utils/load-internal.ts b/packages/modules-sdk/src/loaders/utils/load-internal.ts index d7ff0dd009961..57f695cd78d7e 100644 --- a/packages/modules-sdk/src/loaders/utils/load-internal.ts +++ b/packages/modules-sdk/src/loaders/utils/load-internal.ts @@ -1,10 +1,8 @@ import { - Constructor, InternalModuleDeclaration, Logger, - MODULE_RESOURCE_TYPE, - MODULE_SCOPE, MedusaContainer, + MODULE_RESOURCE_TYPE, ModuleExports, ModuleResolution, } 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) => { - container.registerAdd("db_entities", asValue(val)) - }) - } - } - const localContainer = createMedusaContainer() const dependencies = resolution?.dependencies ?? [] diff --git a/packages/modules-sdk/src/medusa-app.ts b/packages/modules-sdk/src/medusa-app.ts index 6521e06e1768b..9ba593ab93d3d 100644 --- a/packages/modules-sdk/src/medusa-app.ts +++ b/packages/modules-sdk/src/medusa-app.ts @@ -40,8 +40,8 @@ export type RunMigrationFn = ( export type MedusaModuleConfig = { [key: string | Modules]: + | boolean | Partial - | true } export type SharedResources = { diff --git a/packages/modules-sdk/src/module-helper.ts b/packages/modules-sdk/src/module-helper.ts deleted file mode 100644 index a20c0410d2b5c..0000000000000 --- a/packages/modules-sdk/src/module-helper.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ModuleResolution, ModulesResponse } from "@medusajs/types" - -export class ModulesHelper { - private modules_: Record = {} - - setModules(modules: Record) { - this.modules_ = modules - } - - get modules(): ModulesResponse { - return Object.values(this.modules_ || {}).map((value) => ({ - module: value.definition.key, - resolution: value.resolutionPath, - })) - } -} diff --git a/packages/orchestration/src/joiner/remote-joiner.ts b/packages/orchestration/src/joiner/remote-joiner.ts index 47b9da14d600b..a84aada83da3d 100644 --- a/packages/orchestration/src/joiner/remote-joiner.ts +++ b/packages/orchestration/src/joiner/remote-joiner.ts @@ -152,6 +152,23 @@ export class RemoteJoiner { 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 for (const alias of service.alias) { if (this.serviceConfigCache.has(`alias_${alias.name}}`)) { @@ -167,7 +184,7 @@ export class RemoteJoiner { : undefined service.relationships?.push({ - alias: alias.name, + alias: alias.name as string, foreignKey: alias.name + "_id", primaryKey: "id", serviceName: service.serviceName!, @@ -250,7 +267,7 @@ export class RemoteJoiner { private cacheServiceConfig( serviceConfigs, serviceName?: string, - serviceAlias?: string + serviceAlias?: string | string[] ): void { if (serviceAlias) { const name = `alias_${serviceAlias}` diff --git a/packages/pricing/src/scripts/migration-up.ts b/packages/pricing/src/scripts/migration-up.ts index 93b4b9e6f4408..adf128bed5dc4 100644 --- a/packages/pricing/src/scripts/migration-up.ts +++ b/packages/pricing/src/scripts/migration-up.ts @@ -33,7 +33,13 @@ export async function runMigrations({ const migrator = orm.getMigrator() const pendingMigrations = await migrator.getPendingMigrations() - logger.info(`Running pending migrations: ${pendingMigrations}`) + logger.info( + `Running pending migrations: ${JSON.stringify( + pendingMigrations, + null, + 2 + )}` + ) await migrator.up({ migrations: pendingMigrations.map((m) => m.name), diff --git a/packages/product/src/migrations/Migration20230719100648.ts b/packages/product/src/migrations/Migration20230719100648.ts index cc5f853733b77..5f46f17f0fde2 100644 --- a/packages/product/src/migrations/Migration20230719100648.ts +++ b/packages/product/src/migrations/Migration20230719100648.ts @@ -2,89 +2,101 @@ import { Migration } from "@mikro-orm/migrations" export class Migration20230719100648 extends Migration { async up(): Promise { + 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( - '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( - '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( 'alter table "product_category" add constraint "IDX_product_category_handle" unique ("handle");' ) 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( - '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( 'alter table "product_collection" add constraint "IDX_product_collection_handle_unique" unique ("handle");' ) 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 IF NOT EXISTS "IDX_product_image_url" on "image" ("url");' ) - this.addSql('create index "IDX_product_image_url" on "image" ("url");') this.addSql( - 'create index "IDX_product_image_deleted_at" on "image" ("deleted_at");' + 'create index IF NOT EXISTS "IDX_product_image_deleted_at" on "image" ("deleted_at");' ) 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( - '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( - '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( - '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( - '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 IF NOT EXISTS "IDX_product_type_id" on "product" ("type_id");' ) - this.addSql('create index "IDX_product_type_id" on "product" ("type_id");') this.addSql( - 'create index "IDX_product_deleted_at" on "product" ("deleted_at");' + 'create index IF NOT EXISTS "IDX_product_deleted_at" on "product" ("deleted_at");' ) this.addSql( 'alter table "product" add constraint "IDX_product_handle_unique" unique ("handle");' ) 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( - '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( - '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( - '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( - '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( - '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( - '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( - '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( - '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( 'alter table "product_variant" add constraint "IDX_product_variant_sku_unique" unique ("sku");' @@ -100,16 +112,16 @@ export class Migration20230719100648 extends Migration { ) 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( - '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( - '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( - '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( diff --git a/packages/product/src/migrations/Migration20230908084537.ts b/packages/product/src/migrations/Migration20230908084537.ts index ed3c55220bb66..b020b6022786d 100644 --- a/packages/product/src/migrations/Migration20230908084537.ts +++ b/packages/product/src/migrations/Migration20230908084537.ts @@ -1,69 +1,123 @@ -import { Migration } from '@mikro-orm/migrations'; +import { Migration } from "@mikro-orm/migrations" export class Migration20230908084537 extends Migration { - async up(): Promise { - this.addSql('alter table "product_category" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); - 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 "image" 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 "created_at" timestamptz not null default now(), add column "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" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); - 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_variant" alter column "created_at" type timestamptz using ("created_at"::timestamptz);'); - 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_category" alter column "created_at" type timestamptz using ("created_at"::timestamptz);' + ) + 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 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 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 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 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( + '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 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( + '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 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 { - this.addSql('alter table "product_category" alter column "created_at" drop default;'); - 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 "updated_at";'); - - this.addSql('alter table "image" drop column "created_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 "updated_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" alter column "created_at" drop default;'); - this.addSql('alter table "product" alter column "created_at" type timestamptz using ("created_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 "updated_at";'); - - this.addSql('alter table "product_variant" alter column "created_at" drop default;'); - 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 "updated_at";'); + this.addSql( + 'alter table "product_category" alter column "created_at" drop default;' + ) + 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 "updated_at";') + + this.addSql('alter table "image" drop column "created_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 "updated_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" alter column "created_at" drop default;') + this.addSql( + 'alter table "product" alter column "created_at" type timestamptz using ("created_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 "updated_at";') + + this.addSql( + 'alter table "product_variant" alter column "created_at" drop default;' + ) + 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 "updated_at";') } - } diff --git a/packages/product/src/scripts/migration-up.ts b/packages/product/src/scripts/migration-up.ts index 021c573706236..ec73d90f614cb 100644 --- a/packages/product/src/scripts/migration-up.ts +++ b/packages/product/src/scripts/migration-up.ts @@ -33,7 +33,13 @@ export async function runMigrations({ const migrator = orm.getMigrator() const pendingMigrations = await migrator.getPendingMigrations() - logger.info(`Running pending migrations: ${pendingMigrations}`) + logger.info( + `Running pending migrations: ${JSON.stringify( + pendingMigrations, + null, + 2 + )}` + ) await migrator.up({ migrations: pendingMigrations.map((m) => m.name), diff --git a/packages/stock-location/src/joiner-config.ts b/packages/stock-location/src/joiner-config.ts index 07c709d943e42..ebe7fe4a7663d 100644 --- a/packages/stock-location/src/joiner-config.ts +++ b/packages/stock-location/src/joiner-config.ts @@ -1,17 +1,22 @@ import { ModuleJoinerConfig } from "@medusajs/types" import { Modules } from "@medusajs/modules-sdk" import { StockLocation } from "./models" +import moduleSchema from "./schema" export const joinerConfig: ModuleJoinerConfig = { serviceName: Modules.STOCK_LOCATION, primaryKeys: ["id"], - linkableKeys: { stock_location_id: StockLocation.name }, + linkableKeys: { + stock_location_id: StockLocation.name, + location_id: StockLocation.name, + }, + schema: moduleSchema, alias: [ { - name: "stock_location", - }, - { - name: "stock_locations", + name: ["stock_location", "stock_locations"], + args: { + entity: "StockLocation", + }, }, ], } diff --git a/packages/stock-location/src/schema/index.ts b/packages/stock-location/src/schema/index.ts new file mode 100644 index 0000000000000..9a7b198d621b1 --- /dev/null +++ b/packages/stock-location/src/schema/index.ts @@ -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 +} +` diff --git a/packages/types/src/common/config-module.ts b/packages/types/src/common/config-module.ts index ba41fa3c4cd12..452ac03d76e44 100644 --- a/packages/types/src/common/config-module.ts +++ b/packages/types/src/common/config-module.ts @@ -53,9 +53,7 @@ export type ConfigModule = { featureFlags: Record modules?: Record< string, - | false - | string - | Partial + boolean | Partial > plugins: ( | { diff --git a/packages/types/src/joiner/index.ts b/packages/types/src/joiner/index.ts index 40f6583d97874..9d33ae069fd35 100644 --- a/packages/types/src/joiner/index.ts +++ b/packages/types/src/joiner/index.ts @@ -23,7 +23,7 @@ export type JoinerRelationship = { } export interface JoinerServiceConfigAlias { - name: string + name: string | string[] /** * Extra arguments to pass to the remoteFetchData callback */ diff --git a/packages/utils/src/common/container.ts b/packages/utils/src/common/container.ts index 8d5099d518593..6ca0cd173c79c 100644 --- a/packages/utils/src/common/container.ts +++ b/packages/utils/src/common/container.ts @@ -3,4 +3,6 @@ export const ContainerRegistrationKeys = { MANAGER: "manager", CONFIG_MODULE: "configModule", LOGGER: "logger", + REMOTE_QUERY: "remoteQuery", + REMOTE_LINK: "remoteLink", }