Fix/load medusa proj (#6639)
**What** - Runs loadMedusaV2 when v2 flag is enabled. - V2 loader loads only project-level framework features. E.g., project APIs, subscribers, jobs, and workflows. - No plugin support yet.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export * from "./auth"
|
||||
export * from "./api-key"
|
||||
export * from "./customer"
|
||||
export * from "./customer-group"
|
||||
|
||||
@@ -35,6 +35,7 @@ import searchIndexLoader from "./search-index"
|
||||
import servicesLoader from "./services"
|
||||
import strategiesLoader from "./strategies"
|
||||
import subscribersLoader from "./subscribers"
|
||||
import medusaProjectApisLoader from "./load-medusa-project-apis"
|
||||
|
||||
type Options = {
|
||||
directory: string
|
||||
@@ -81,7 +82,12 @@ async function loadLegacyModulesEntities(configModules, container) {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMedusaV2({ configModule, featureFlagRouter, expressApp }) {
|
||||
async function loadMedusaV2({
|
||||
rootDirectory,
|
||||
configModule,
|
||||
featureFlagRouter,
|
||||
expressApp,
|
||||
}) {
|
||||
const container = createMedusaContainer()
|
||||
|
||||
// Add additional information to context of request
|
||||
@@ -124,6 +130,14 @@ async function loadMedusaV2({ configModule, featureFlagRouter, expressApp }) {
|
||||
featureFlagRouter,
|
||||
})
|
||||
|
||||
medusaProjectApisLoader({
|
||||
rootDirectory,
|
||||
container,
|
||||
app: expressApp,
|
||||
configModule,
|
||||
activityId: "medusa-project-apis",
|
||||
})
|
||||
|
||||
return {
|
||||
container,
|
||||
app: expressApp,
|
||||
@@ -146,7 +160,12 @@ export default async ({
|
||||
track("FEATURE_FLAGS_LOADED")
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
return await loadMedusaV2({ configModule, featureFlagRouter, expressApp })
|
||||
return await loadMedusaV2({
|
||||
rootDirectory,
|
||||
configModule,
|
||||
featureFlagRouter,
|
||||
expressApp,
|
||||
})
|
||||
}
|
||||
|
||||
const container = createMedusaContainer()
|
||||
|
||||
200
packages/medusa/src/loaders/load-medusa-project-apis.ts
Normal file
200
packages/medusa/src/loaders/load-medusa-project-apis.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
import { Express } from "express"
|
||||
import glob from "glob"
|
||||
import _ from "lodash"
|
||||
import { trackInstallation } from "medusa-telemetry"
|
||||
import { EOL } from "os"
|
||||
import path from "path"
|
||||
import { ConfigModule, Logger, MedusaContainer } from "../types/global"
|
||||
import ScheduledJobsLoader from "./helpers/jobs"
|
||||
import { RoutesLoader } from "./helpers/routing"
|
||||
import { SubscriberLoader } from "./helpers/subscribers"
|
||||
import logger from "./logger"
|
||||
|
||||
type Options = {
|
||||
rootDirectory: string
|
||||
container: MedusaContainer
|
||||
configModule: ConfigModule
|
||||
app: Express
|
||||
activityId: string
|
||||
}
|
||||
|
||||
type PluginDetails = {
|
||||
resolve: string
|
||||
name: string
|
||||
id: string
|
||||
options: Record<string, unknown>
|
||||
version: string
|
||||
}
|
||||
|
||||
export const MEDUSA_PROJECT_NAME = "project-plugin"
|
||||
|
||||
/**
|
||||
* Registers all services in the services directory
|
||||
*/
|
||||
export default async ({
|
||||
rootDirectory,
|
||||
container,
|
||||
app,
|
||||
configModule,
|
||||
activityId,
|
||||
}: Options): Promise<void> => {
|
||||
const resolved = getResolvedPlugins(rootDirectory, configModule) || []
|
||||
|
||||
await promiseAll(
|
||||
resolved.map(async (pluginDetails) => {
|
||||
await registerApi(pluginDetails, app, container, configModule, activityId)
|
||||
await registerSubscribers(pluginDetails, container, activityId)
|
||||
await registerWorkflows(pluginDetails)
|
||||
})
|
||||
)
|
||||
|
||||
await promiseAll(
|
||||
resolved.map(async (pluginDetails) => runLoaders(pluginDetails, container))
|
||||
)
|
||||
|
||||
if (configModule.projectConfig.redis_url) {
|
||||
await Promise.all(
|
||||
resolved.map(async (pluginDetails) => {
|
||||
await registerScheduledJobs(pluginDetails, container)
|
||||
})
|
||||
)
|
||||
} else {
|
||||
logger.warn(
|
||||
"You don't have Redis configured. Scheduled jobs will not be enabled."
|
||||
)
|
||||
}
|
||||
|
||||
resolved.forEach((plugin) => trackInstallation(plugin.name, "plugin"))
|
||||
}
|
||||
|
||||
function getResolvedPlugins(
|
||||
rootDirectory: string,
|
||||
configModule: ConfigModule,
|
||||
extensionDirectoryPath = "dist"
|
||||
): undefined | PluginDetails[] {
|
||||
const extensionDirectory = path.join(rootDirectory, extensionDirectoryPath)
|
||||
return [
|
||||
{
|
||||
resolve: extensionDirectory,
|
||||
name: MEDUSA_PROJECT_NAME,
|
||||
id: createPluginId(MEDUSA_PROJECT_NAME),
|
||||
options: configModule,
|
||||
version: createFileContentHash(process.cwd(), `**`),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
async function runLoaders(
|
||||
pluginDetails: PluginDetails,
|
||||
container: MedusaContainer
|
||||
): Promise<void> {
|
||||
const loaderFiles = glob.sync(
|
||||
`${pluginDetails.resolve}/loaders/[!__]*.js`,
|
||||
{}
|
||||
)
|
||||
await promiseAll(
|
||||
loaderFiles.map(async (loader) => {
|
||||
try {
|
||||
const module = require(loader).default
|
||||
if (typeof module === "function") {
|
||||
await module(container, pluginDetails.options)
|
||||
}
|
||||
} catch (err) {
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
logger.warn(`Running loader failed: ${err.message}`)
|
||||
return Promise.resolve()
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async function registerScheduledJobs(
|
||||
pluginDetails: PluginDetails,
|
||||
container: MedusaContainer
|
||||
): Promise<void> {
|
||||
await new ScheduledJobsLoader(
|
||||
path.join(pluginDetails.resolve, "jobs"),
|
||||
container,
|
||||
pluginDetails.options
|
||||
).load()
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the plugin's api routes.
|
||||
*/
|
||||
async function registerApi(
|
||||
pluginDetails: PluginDetails,
|
||||
app: Express,
|
||||
container: MedusaContainer,
|
||||
configmodule: ConfigModule,
|
||||
activityId: string
|
||||
): Promise<Express> {
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
const projectName =
|
||||
pluginDetails.name === MEDUSA_PROJECT_NAME
|
||||
? "your Medusa project"
|
||||
: `${pluginDetails.name}`
|
||||
|
||||
logger.progress(activityId, `Registering custom endpoints for ${projectName}`)
|
||||
|
||||
try {
|
||||
/**
|
||||
* Register the plugin's API routes using the file based routing.
|
||||
*/
|
||||
await new RoutesLoader({
|
||||
app,
|
||||
rootDir: path.join(pluginDetails.resolve, "api"),
|
||||
activityId: activityId,
|
||||
configModule: configmodule,
|
||||
}).load()
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
`An error occurred while registering API Routes in ${projectName}${
|
||||
err.stack ? EOL + err.stack : ""
|
||||
}`
|
||||
)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a plugin's subscribers at the right location in our container.
|
||||
* Subscribers are registered directly in the container.
|
||||
* @param {object} pluginDetails - the plugin details including plugin options,
|
||||
* version, id, resolved path, etc. See resolvePlugin
|
||||
* @param {object} container - the container where the services will be
|
||||
* registered
|
||||
* @return {void}
|
||||
*/
|
||||
async function registerSubscribers(
|
||||
pluginDetails: PluginDetails,
|
||||
container: MedusaContainer,
|
||||
activityId: string
|
||||
): Promise<void> {
|
||||
await new SubscriberLoader(
|
||||
path.join(pluginDetails.resolve, "subscribers"),
|
||||
container,
|
||||
pluginDetails.options,
|
||||
activityId
|
||||
).load()
|
||||
}
|
||||
|
||||
/**
|
||||
* import files from the workflows directory to run the registration of the wofklows
|
||||
* @param pluginDetails
|
||||
*/
|
||||
async function registerWorkflows(pluginDetails: PluginDetails): Promise<void> {
|
||||
const files = glob.sync(`${pluginDetails.resolve}/workflows/*.js`, {})
|
||||
await Promise.all(files.map(async (file) => import(file)))
|
||||
}
|
||||
|
||||
// TODO: Create unique id for each plugin
|
||||
function createPluginId(name: string): string {
|
||||
return name
|
||||
}
|
||||
|
||||
function createFileContentHash(path, files): string {
|
||||
return path + files
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ExternalModuleDeclaration,
|
||||
InternalModuleDeclaration,
|
||||
MODULE_RESOURCE_TYPE,
|
||||
MODULE_SCOPE,
|
||||
ModuleDefinition,
|
||||
ModuleExports,
|
||||
@@ -25,7 +26,11 @@ export const registerMedusaModule = (
|
||||
const modDefinition = definition ?? ModulesDefinition[moduleKey]
|
||||
|
||||
if (modDefinition === undefined) {
|
||||
throw new Error(`Module: ${moduleKey} is not defined.`)
|
||||
moduleResolutions[moduleKey] = getCustomModuleResolution(
|
||||
moduleKey,
|
||||
moduleDeclaration as InternalModuleDeclaration
|
||||
)
|
||||
return moduleResolutions
|
||||
}
|
||||
|
||||
const modDeclaration =
|
||||
@@ -53,6 +58,38 @@ export const registerMedusaModule = (
|
||||
return moduleResolutions
|
||||
}
|
||||
|
||||
function getCustomModuleResolution(
|
||||
key: string,
|
||||
moduleConfig: InternalModuleDeclaration | string
|
||||
): ModuleResolution {
|
||||
const isString = typeof moduleConfig === "string"
|
||||
const resolutionPath = resolveCwd(
|
||||
isString ? moduleConfig : (moduleConfig.resolve as string)
|
||||
)
|
||||
|
||||
return {
|
||||
resolutionPath,
|
||||
definition: {
|
||||
key,
|
||||
label: `Custom: ${key}`,
|
||||
isRequired: false,
|
||||
defaultPackage: "",
|
||||
dependencies: [],
|
||||
registrationName: key,
|
||||
defaultModuleDeclaration: {
|
||||
resources: MODULE_RESOURCE_TYPE.SHARED,
|
||||
scope: MODULE_SCOPE.INTERNAL,
|
||||
},
|
||||
},
|
||||
moduleDeclaration: {
|
||||
resources: MODULE_RESOURCE_TYPE.SHARED,
|
||||
scope: MODULE_SCOPE.INTERNAL,
|
||||
},
|
||||
dependencies: [],
|
||||
options: {},
|
||||
}
|
||||
}
|
||||
|
||||
export const registerMedusaLinkModule = (
|
||||
definition: ModuleDefinition,
|
||||
moduleDeclaration: Partial<InternalModuleDeclaration>,
|
||||
|
||||
Reference in New Issue
Block a user