Feat(modules-sdk,inventory,stock-location): modules isolated connection (#3329)

* feat: scoped container for modules
This commit is contained in:
Carlos R. L. Rodrigues
2023-03-15 12:09:45 -03:00
committed by GitHub
parent 8e78c533c4
commit 77d46220c2
65 changed files with 1116 additions and 1011 deletions

View File

@@ -1,38 +1,41 @@
import { asFunction, asValue } from "awilix"
import { trackInstallation } from "medusa-telemetry"
import { asValue } from "awilix"
import { EOL } from "os"
import { loadInternalModule } from "./utils"
import {
ClassConstructor,
ConfigModule,
LoaderOptions,
Logger,
MedusaContainer,
ModuleExports,
ModuleResolution,
MODULE_RESOURCE_TYPE,
MODULE_SCOPE,
} from "../types/module"
} from "../types"
import { ModulesHelper } from "../module-helper"
export const moduleHelper = new ModulesHelper()
const registerModule = async (
async function loadModule(
container: MedusaContainer,
resolution: ModuleResolution,
configModule: ConfigModule,
logger: Logger
): Promise<{ error?: Error } | void> => {
const constainerName = resolution.definition.registrationName
): Promise<{ error?: Error } | void> {
const registrationName = resolution.definition.registrationName
const { scope, resources } = resolution.moduleDeclaration ?? ({} as any)
if (scope === MODULE_SCOPE.EXTERNAL) {
// TODO: implement external Resolvers
// return loadExternalModule(...)
throw new Error("External Modules are not supported yet.")
}
const { scope, resources } = resolution.moduleDeclaration ?? {}
if (!scope || (scope === MODULE_SCOPE.INTERNAL && !resources)) {
let message = `The module ${resolution.definition.label} has to define its scope (internal | external)`
if (scope && !resources) {
if (scope === MODULE_SCOPE.INTERNAL && !resources) {
message = `The module ${resolution.definition.label} is missing its resources config`
}
container.register({
[constainerName]: asValue(undefined),
[registrationName]: asValue(undefined),
})
return {
@@ -42,107 +45,38 @@ const registerModule = async (
if (!resolution.resolutionPath) {
container.register({
[constainerName]: asValue(undefined),
[registrationName]: asValue(undefined),
})
return
}
let loadedModule: ModuleExports
try {
loadedModule = (await import(resolution.resolutionPath!)).default
} catch (error) {
return { error }
}
const moduleService = loadedModule?.service || null
if (!moduleService) {
return {
error: new Error(
"No service found in module. Make sure that your module exports a service."
),
}
}
if (
scope === MODULE_SCOPE.INTERNAL &&
resources === MODULE_RESOURCE_TYPE.SHARED
) {
const moduleModels = loadedModule?.models || null
if (moduleModels) {
moduleModels.map((val: ClassConstructor<unknown>) => {
container.registerAdd("db_entities", asValue(val))
})
}
}
// TODO: "cradle" should only contain dependent Modules and the EntityManager if module scope is shared
container.register({
[constainerName]: asFunction((cradle) => {
return new moduleService(
cradle,
resolution.options,
resolution.moduleDeclaration
)
}).singleton(),
})
const moduleLoaders = loadedModule?.loaders || []
try {
for (const loader of moduleLoaders) {
await loader(
{
container,
configModule,
logger,
options: resolution.options,
},
resolution.moduleDeclaration
)
}
} catch (err) {
return {
error: new Error(
`Loaders for module ${resolution.definition.label} failed: ${err.message}`
),
}
}
trackInstallation(
{
module: resolution.definition.key,
resolution: resolution.resolutionPath,
},
"module"
)
return await loadInternalModule(container, resolution, logger)
}
export const moduleLoader = async ({
container,
configModule,
moduleResolutions,
logger,
}: LoaderOptions): Promise<void> => {
const moduleResolutions = configModule?.moduleResolutions ?? {}
}: {
container: MedusaContainer
moduleResolutions: Record<string, ModuleResolution>
logger: Logger
}): Promise<void> => {
for (const resolution of Object.values(moduleResolutions ?? {})) {
const registrationResult = await loadModule(container, resolution, logger!)
for (const resolution of Object.values(moduleResolutions)) {
const registrationResult = await registerModule(
container,
resolution,
configModule,
logger!
)
if (registrationResult?.error) {
const { error } = registrationResult
if (resolution.definition.isRequired) {
logger?.warn(
`Could not resolve required module: ${resolution.definition.label}. Error: ${error.message}`
logger?.error(
`Could not resolve required module: ${resolution.definition.label}. Error: ${error.message}${EOL}`
)
throw error
}
logger?.warn(
`Could not resolve module: ${resolution.definition.label}. Error: ${error.message}`
`Could not resolve module: ${resolution.definition.label}. Error: ${error.message}${EOL}`
)
}
}