From ad7f56506f320979a97e1707b836ec02b65a0ecd Mon Sep 17 00:00:00 2001 From: "Carlos R. L. Rodrigues" <37986729+carlos-r-l-rodrigues@users.noreply.github.com> Date: Thu, 23 Feb 2023 13:09:35 -0300 Subject: [PATCH] Feat(medusa,modules-sdk): Modules SDK package (#3294) --- .gitignore | 3 +- packages/inventory/package.json | 3 + packages/inventory/src/index.ts | 2 +- packages/inventory/src/loaders/connection.ts | 5 +- packages/inventory/src/services/inventory.ts | 5 +- packages/medusa/package.json | 1 + .../src/api/routes/admin/store/get-store.ts | 2 +- .../src/commands/utils/get-migrations.js | 4 +- packages/medusa/src/helpers/test-request.js | 10 +- packages/medusa/src/loaders/config.ts | 4 +- packages/medusa/src/loaders/index.ts | 3 +- packages/medusa/src/types/global.ts | 65 +---------- packages/medusa/src/types/modules.ts | 20 ---- packages/medusa/src/types/store.ts | 19 +++- packages/medusa/tsconfig.json | 10 +- packages/modules-sdk/jest.config.js | 13 +++ packages/modules-sdk/package.json | 37 +++++++ .../src}/definitions.ts | 6 +- packages/modules-sdk/src/index.ts | 6 + .../__mocks__/@modules/brokenloader.ts | 0 .../src/loaders/__mocks__/@modules/default.ts | 0 .../loaders/__mocks__/@modules/no-service.ts | 0 .../src/loaders/__mocks__/medusa-telemetry.ts | 0 .../loaders/__tests__/module-definitions.ts} | 22 ++-- .../src/loaders/__tests__/module-loader.ts} | 42 +++---- packages/modules-sdk/src/loaders/index.ts | 3 + .../src/loaders/module-definition.ts} | 6 +- .../src/loaders/module-loader.ts} | 10 +- .../src}/module-helper.ts | 3 +- packages/modules-sdk/src/types/index.ts | 1 + packages/modules-sdk/src/types/module.ts | 103 ++++++++++++++++++ packages/modules-sdk/tsconfig.json | 32 ++++++ packages/stock-location/package.json | 3 + packages/stock-location/src/index.ts | 2 +- .../stock-location/src/loaders/connection.ts | 5 +- .../src/services/stock-location.ts | 10 +- yarn.lock | 17 +++ 37 files changed, 317 insertions(+), 160 deletions(-) delete mode 100644 packages/medusa/src/types/modules.ts create mode 100644 packages/modules-sdk/jest.config.js create mode 100644 packages/modules-sdk/package.json rename packages/{medusa/src/loaders/module-definitions => modules-sdk/src}/definitions.ts (88%) create mode 100644 packages/modules-sdk/src/index.ts rename packages/{medusa => modules-sdk}/src/loaders/__mocks__/@modules/brokenloader.ts (100%) rename packages/{medusa => modules-sdk}/src/loaders/__mocks__/@modules/default.ts (100%) rename packages/{medusa => modules-sdk}/src/loaders/__mocks__/@modules/no-service.ts (100%) rename packages/{medusa => modules-sdk}/src/loaders/__mocks__/medusa-telemetry.ts (100%) rename packages/{medusa/src/loaders/__tests__/module-definitions.spec.ts => modules-sdk/src/loaders/__tests__/module-definitions.ts} (91%) rename packages/{medusa/src/loaders/__tests__/module.spec.ts => modules-sdk/src/loaders/__tests__/module-loader.ts} (90%) create mode 100644 packages/modules-sdk/src/loaders/index.ts rename packages/{medusa/src/loaders/module-definitions/index.ts => modules-sdk/src/loaders/module-definition.ts} (90%) rename packages/{medusa/src/loaders/module.ts => modules-sdk/src/loaders/module-loader.ts} (95%) rename packages/{medusa/src/utils => modules-sdk/src}/module-helper.ts (78%) create mode 100644 packages/modules-sdk/src/types/index.ts create mode 100644 packages/modules-sdk/src/types/module.ts create mode 100644 packages/modules-sdk/tsconfig.json diff --git a/.gitignore b/.gitignore index 789159e5e9..eb87687bd3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ www/**/.yarn/* .idea .turbo -build/** \ No newline at end of file +build/** +**/dist \ No newline at end of file diff --git a/packages/inventory/package.json b/packages/inventory/package.json index 7784ad2227..342f772beb 100644 --- a/packages/inventory/package.json +++ b/packages/inventory/package.json @@ -24,6 +24,9 @@ "typeorm": "^0.3.11", "typescript": "^4.4.4" }, + "dependencies": { + "@medusajs/modules-sdk": "*" + }, "scripts": { "watch": "tsc --build --watch", "prepare": "cross-env NODE_ENV=production yarn run build", diff --git a/packages/inventory/src/index.ts b/packages/inventory/src/index.ts index 7e4d161f33..3e84682758 100644 --- a/packages/inventory/src/index.ts +++ b/packages/inventory/src/index.ts @@ -2,7 +2,7 @@ import ConnectionLoader from "./loaders/connection" import InventoryService from "./services/inventory" import * as InventoryModels from "./models" import * as SchemaMigration from "./migrations/schema-migrations/1665748086258-inventory_setup" -import { ModuleExports } from "@medusajs/medusa" +import { ModuleExports } from "@medusajs/modules-sdk" const service = InventoryService const migrations = [SchemaMigration] diff --git a/packages/inventory/src/loaders/connection.ts b/packages/inventory/src/loaders/connection.ts index 87dc6fa7d2..09d777bae8 100644 --- a/packages/inventory/src/loaders/connection.ts +++ b/packages/inventory/src/loaders/connection.ts @@ -1,4 +1,7 @@ -import { ConfigurableModuleDeclaration, LoaderOptions } from "@medusajs/medusa" +import { + ConfigurableModuleDeclaration, + LoaderOptions, +} from "@medusajs/modules-sdk" export default async ( { configModule }: LoaderOptions, diff --git a/packages/inventory/src/services/inventory.ts b/packages/inventory/src/services/inventory.ts index f4d2116adf..ef13449298 100644 --- a/packages/inventory/src/services/inventory.ts +++ b/packages/inventory/src/services/inventory.ts @@ -1,5 +1,9 @@ import { ConfigurableModuleDeclaration, + MODULE_RESOURCE_TYPE, +} from "@medusajs/modules-sdk" + +import { CreateInventoryItemInput, CreateInventoryLevelInput, CreateReservationItemInput, @@ -11,7 +15,6 @@ import { IInventoryService, InventoryItemDTO, InventoryLevelDTO, - MODULE_RESOURCE_TYPE, ReservationItemDTO, TransactionBaseService, UpdateInventoryLevelInput, diff --git a/packages/medusa/package.json b/packages/medusa/package.json index e3ee6f2096..5a58d3d47f 100644 --- a/packages/medusa/package.json +++ b/packages/medusa/package.json @@ -49,6 +49,7 @@ }, "dependencies": { "@medusajs/medusa-cli": "^1.3.8", + "@medusajs/modules-sdk": "*", "@types/ioredis": "^4.28.10", "@types/lodash": "^4.14.191", "awilix": "^8.0.0", 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 aa31519326..b47e2293b1 100644 --- a/packages/medusa/src/api/routes/admin/store/get-store.ts +++ b/packages/medusa/src/api/routes/admin/store/get-store.ts @@ -5,7 +5,7 @@ import { } from "../../../../services" import { ExtendedStoreDTO } from "../../../../types/store" import { FlagRouter } from "../../../../utils/flag-router" -import { ModulesHelper } from "../../../../utils/module-helper" +import { ModulesHelper } from "@medusajs/modules-sdk" /** * @oas [get] /admin/store diff --git a/packages/medusa/src/commands/utils/get-migrations.js b/packages/medusa/src/commands/utils/get-migrations.js index d6449f7bbf..3baf1641d6 100644 --- a/packages/medusa/src/commands/utils/get-migrations.js +++ b/packages/medusa/src/commands/utils/get-migrations.js @@ -5,7 +5,7 @@ import { isString } from "lodash" import { sync as existsSync } from "fs-exists-cached" import { getConfigFile, createRequireFromPath } from "medusa-core-utils" import { handleConfigError } from "../../loaders/config" -import registerModuleDefinitions from "../../loaders/module-definitions" +import { registerModules } from "@medusajs/modules-sdk" function createFileContentHash(path, files) { return path + files @@ -92,7 +92,7 @@ function resolvePlugin(pluginName) { export function getInternalModules(configModule) { const modules = [] - const moduleResolutions = registerModuleDefinitions(configModule) + const moduleResolutions = registerModules(configModule) 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 9201a9848c..0923744925 100644 --- a/packages/medusa/src/helpers/test-request.js +++ b/packages/medusa/src/helpers/test-request.js @@ -7,12 +7,14 @@ import "reflect-metadata" import supertest from "supertest" import apiLoader from "../loaders/api" import featureFlagLoader, { featureFlagRouter } from "../loaders/feature-flags" -import { moduleHelper } from "../loaders/module" +import { + moduleLoader, + moduleHelper, + registerModules, +} from "@medusajs/modules-sdk" import passportLoader from "../loaders/passport" import servicesLoader from "../loaders/services" import strategiesLoader from "../loaders/strategies" -import registerModuleDefinitions from "../loaders/module-definitions" -import moduleLoader from "../loaders/module" const adminSessionOpts = { cookieName: "session", @@ -26,7 +28,7 @@ const clientSessionOpts = { secret: "test", } -const moduleResolutions = registerModuleDefinitions({}) +const moduleResolutions = registerModules({}) const config = { projectConfig: { jwt_secret: "supersecret", diff --git a/packages/medusa/src/loaders/config.ts b/packages/medusa/src/loaders/config.ts index ad9f2c5f9f..a6b82d7a82 100644 --- a/packages/medusa/src/loaders/config.ts +++ b/packages/medusa/src/loaders/config.ts @@ -1,7 +1,7 @@ import { getConfigFile } from "medusa-core-utils" import { ConfigModule } from "../types/global" import logger from "./logger" -import registerModuleDefinitions from "./module-definitions" +import { registerModules } from "@medusajs/modules-sdk" const isProduction = ["production", "prod"].includes(process.env.NODE_ENV || "") @@ -65,7 +65,7 @@ export default (rootDirectory: string): ConfigModule => { ) } - const moduleResolutions = registerModuleDefinitions(configModule) + const moduleResolutions = registerModules(configModule) return { projectConfig: { diff --git a/packages/medusa/src/loaders/index.ts b/packages/medusa/src/loaders/index.ts index 469b2d1d45..216b47aa54 100644 --- a/packages/medusa/src/loaders/index.ts +++ b/packages/medusa/src/loaders/index.ts @@ -21,7 +21,6 @@ import expressLoader from "./express" import featureFlagsLoader from "./feature-flags" import Logger from "./logger" import modelsLoader from "./models" -import moduleLoader from "./module" import passportLoader from "./passport" import pluginsLoader, { registerPluginModels } from "./plugins" import redisLoader from "./redis" @@ -31,6 +30,8 @@ import servicesLoader from "./services" import strategiesLoader from "./strategies" import subscribersLoader from "./subscribers" +import { moduleLoader } from "@medusajs/modules-sdk" + type Options = { directory: string expressApp: Express diff --git a/packages/medusa/src/types/global.ts b/packages/medusa/src/types/global.ts index eee037ac01..fcd3dfc3f7 100644 --- a/packages/medusa/src/types/global.ts +++ b/packages/medusa/src/types/global.ts @@ -1,3 +1,7 @@ +import { + ConfigurableModuleDeclaration, + ModuleResolution, +} from "@medusajs/modules-sdk" import { AwilixContainer } from "awilix" import { Request } from "express" import { LoggerOptions } from "typeorm" @@ -38,69 +42,8 @@ export type Logger = _Logger & { warn: (msg: string) => void } -export enum MODULE_SCOPE { - INTERNAL = "internal", - EXTERNAL = "external", -} - -export enum MODULE_RESOURCE_TYPE { - SHARED = "shared", - ISOLATED = "isolated", -} - -export type ConfigurableModuleDeclaration = { - scope: MODULE_SCOPE.INTERNAL - resources: MODULE_RESOURCE_TYPE - resolve?: string - options?: Record -} -/* -| { - scope: MODULE_SCOPE.external - server: { - type: "built-in" | "rest" | "tsrpc" | "grpc" | "gql" - url: string - options?: Record - } - } -*/ - -export type ModuleResolution = { - resolutionPath: string | false - definition: ModuleDefinition - options?: Record - moduleDeclaration?: ConfigurableModuleDeclaration -} - -export type ModuleDefinition = { - key: string - registrationName: string - defaultPackage: string | false - label: string - canOverride?: boolean - isRequired?: boolean - defaultModuleDeclaration: ConfigurableModuleDeclaration -} - -export type LoaderOptions = { - container: MedusaContainer - configModule: ConfigModule - options?: Record - logger?: Logger -} - export type Constructor = new (...args: any[]) => T -export type ModuleExports = { - loaders: (( - options: LoaderOptions, - moduleDeclaration?: ConfigurableModuleDeclaration - ) => Promise)[] - service: Constructor - migrations?: any[] // TODO: revisit migrations type - models?: Constructor[] -} - type SessionOptions = { name?: string resave?: boolean diff --git a/packages/medusa/src/types/modules.ts b/packages/medusa/src/types/modules.ts deleted file mode 100644 index 262b10cd01..0000000000 --- a/packages/medusa/src/types/modules.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @schema ModulesResponse - * type: array - * items: - * type: object - * required: - * - module - * - resolution - * properties: - * module: - * description: The key of the module. - * type: string - * resolution: - * description: The resolution path of the module or false if module is not installed. - * type: string - */ -export type ModulesResponse = { - module: string - resolution: string | false -}[] diff --git a/packages/medusa/src/types/store.ts b/packages/medusa/src/types/store.ts index eae26cb85e..20a9580121 100644 --- a/packages/medusa/src/types/store.ts +++ b/packages/medusa/src/types/store.ts @@ -1,6 +1,6 @@ import { Store, PaymentProvider, FulfillmentProvider } from "../models" import { FeatureFlagsResponse } from "./feature-flags" -import { ModulesResponse } from "./modules" +import { ModulesResponse } from "@medusajs/modules-sdk" export type UpdateStoreInput = { name?: string @@ -13,6 +13,23 @@ export type UpdateStoreInput = { default_sales_channel_id?: string } +/** + * @schema ModulesResponse + * type: array + * items: + * type: object + * required: + * - module + * - resolution + * properties: + * module: + * description: The key of the module. + * type: string + * resolution: + * description: The resolution path of the module or false if module is not installed. + * type: string + */ + /** * @schema ExtendedStoreDTO * allOf: diff --git a/packages/medusa/tsconfig.json b/packages/medusa/tsconfig.json index e5d942d558..83f3f06043 100644 --- a/packages/medusa/tsconfig.json +++ b/packages/medusa/tsconfig.json @@ -1,10 +1,6 @@ { "compilerOptions": { - "lib": [ - "es5", - "es6", - "es2019" - ], + "lib": ["es5", "es6", "es2019"], "target": "es5", "outDir": "./dist", "esModuleInterop": true, @@ -21,7 +17,7 @@ "allowJs": true, "skipLibCheck": true, "downlevelIteration": true, // to use ES5 specific tooling - "resolveJsonModule": true, + "resolveJsonModule": true }, "include": ["./src/**/*", "index.d.ts"], "exclude": [ @@ -31,4 +27,4 @@ "./src/**/__fixtures__", "node_modules" ] -} \ No newline at end of file +} diff --git a/packages/modules-sdk/jest.config.js b/packages/modules-sdk/jest.config.js new file mode 100644 index 0000000000..7de5bf104a --- /dev/null +++ b/packages/modules-sdk/jest.config.js @@ -0,0 +1,13 @@ +module.exports = { + globals: { + "ts-jest": { + tsConfig: "tsconfig.json", + isolatedModules: false, + }, + }, + transform: { + "^.+\\.[jt]s?$": "ts-jest", + }, + testEnvironment: `node`, + moduleFileExtensions: [`js`, `ts`], +} diff --git a/packages/modules-sdk/package.json b/packages/modules-sdk/package.json new file mode 100644 index 0000000000..da41257d04 --- /dev/null +++ b/packages/modules-sdk/package.json @@ -0,0 +1,37 @@ +{ + "name": "@medusajs/modules-sdk", + "version": "0.0.1", + "description": "SDK for medusa modules", + "main": "dist/index.js", + "repository": { + "type": "git", + "url": "https://github.com/medusajs/medusa", + "directory": "packages/modules-sdk" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist" + ], + "author": "Medusa", + "license": "MIT", + "devDependencies": { + "cross-env": "^5.2.1", + "jest": "^25.5.4", + "ts-jest": "^25.5.1", + "typescript": "^4.4.4" + }, + "dependencies": { + "awilix": "^8.0.0", + "medusa-telemetry": "^0.0.16", + "resolve-cwd": "^3.0.0" + }, + "scripts": { + "prepare": "cross-env NODE_ENV=production yarn run build", + "build": "tsc --build", + "test": "jest", + "test:unit": "jest" + }, + "peerDependencies": {} +} diff --git a/packages/medusa/src/loaders/module-definitions/definitions.ts b/packages/modules-sdk/src/definitions.ts similarity index 88% rename from packages/medusa/src/loaders/module-definitions/definitions.ts rename to packages/modules-sdk/src/definitions.ts index d532d36443..b9c848bc1c 100644 --- a/packages/medusa/src/loaders/module-definitions/definitions.ts +++ b/packages/modules-sdk/src/definitions.ts @@ -1,8 +1,4 @@ -import { - ModuleDefinition, - MODULE_RESOURCE_TYPE, - MODULE_SCOPE, -} from "../../types/global" +import { ModuleDefinition, MODULE_RESOURCE_TYPE, MODULE_SCOPE } from "./types" export const MODULE_DEFINITIONS: ModuleDefinition[] = [ { diff --git a/packages/modules-sdk/src/index.ts b/packages/modules-sdk/src/index.ts new file mode 100644 index 0000000000..0f105816bb --- /dev/null +++ b/packages/modules-sdk/src/index.ts @@ -0,0 +1,6 @@ +export * from "./types" +export * from "./loaders" + +export * from "./module-helper" + +export * from "./definitions" diff --git a/packages/medusa/src/loaders/__mocks__/@modules/brokenloader.ts b/packages/modules-sdk/src/loaders/__mocks__/@modules/brokenloader.ts similarity index 100% rename from packages/medusa/src/loaders/__mocks__/@modules/brokenloader.ts rename to packages/modules-sdk/src/loaders/__mocks__/@modules/brokenloader.ts diff --git a/packages/medusa/src/loaders/__mocks__/@modules/default.ts b/packages/modules-sdk/src/loaders/__mocks__/@modules/default.ts similarity index 100% rename from packages/medusa/src/loaders/__mocks__/@modules/default.ts rename to packages/modules-sdk/src/loaders/__mocks__/@modules/default.ts diff --git a/packages/medusa/src/loaders/__mocks__/@modules/no-service.ts b/packages/modules-sdk/src/loaders/__mocks__/@modules/no-service.ts similarity index 100% rename from packages/medusa/src/loaders/__mocks__/@modules/no-service.ts rename to packages/modules-sdk/src/loaders/__mocks__/@modules/no-service.ts diff --git a/packages/medusa/src/loaders/__mocks__/medusa-telemetry.ts b/packages/modules-sdk/src/loaders/__mocks__/medusa-telemetry.ts similarity index 100% rename from packages/medusa/src/loaders/__mocks__/medusa-telemetry.ts rename to packages/modules-sdk/src/loaders/__mocks__/medusa-telemetry.ts diff --git a/packages/medusa/src/loaders/__tests__/module-definitions.spec.ts b/packages/modules-sdk/src/loaders/__tests__/module-definitions.ts similarity index 91% rename from packages/medusa/src/loaders/__tests__/module-definitions.spec.ts rename to packages/modules-sdk/src/loaders/__tests__/module-definitions.ts index 300ae6259a..7b5ec35383 100644 --- a/packages/medusa/src/loaders/__tests__/module-definitions.spec.ts +++ b/packages/modules-sdk/src/loaders/__tests__/module-definitions.ts @@ -3,9 +3,9 @@ import { ModuleDefinition, MODULE_RESOURCE_TYPE, MODULE_SCOPE, -} from "../../types/global" -import ModuleDefinitionLoader from "../module-definitions" -import MODULE_DEFINITIONS from "../module-definitions/definitions" +} from "../../types" +import { registerModules } from "../module-definition" +import MODULE_DEFINITIONS from "../../definitions" const RESOLVED_PACKAGE = "@medusajs/test-service-resolved" jest.mock("resolve-cwd", () => jest.fn(() => RESOLVED_PACKAGE)) @@ -35,7 +35,7 @@ describe("module definitions loader", () => { it("Resolves module with default definition given empty config", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition }) - const res = ModuleDefinitionLoader({ modules: {} } as ConfigModule) + const res = registerModules({ modules: {} } as ConfigModule) expect(res[defaultDefinition.key]).toEqual({ resolutionPath: defaultDefinition.defaultPackage, @@ -52,7 +52,7 @@ describe("module definitions loader", () => { it("Resolves module with no resolution path when given false", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition }) - const res = ModuleDefinitionLoader({ + const res = registerModules({ modules: { [defaultDefinition.key]: false }, } as ConfigModule) @@ -68,7 +68,7 @@ describe("module definitions loader", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition, isRequired: true }) try { - ModuleDefinitionLoader({ + registerModules({ modules: { [defaultDefinition.key]: false }, } as ConfigModule) } catch (err) { @@ -86,7 +86,7 @@ describe("module definitions loader", () => { MODULE_DEFINITIONS.push(definition) - const res = ModuleDefinitionLoader({ + const res = registerModules({ modules: {}, } as ConfigModule) @@ -106,7 +106,7 @@ describe("module definitions loader", () => { it("Resolves module with default definition given empty config", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition }) - const res = ModuleDefinitionLoader({ + const res = registerModules({ modules: { [defaultDefinition.key]: defaultDefinition.defaultPackage, }, @@ -128,7 +128,7 @@ describe("module definitions loader", () => { it("Resolves resolution path and provides empty options when none are provided", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition }) - const res = ModuleDefinitionLoader({ + const res = registerModules({ modules: { [defaultDefinition.key]: { resolve: defaultDefinition.defaultPackage, @@ -152,7 +152,7 @@ describe("module definitions loader", () => { it("Resolves default resolution path and provides options when only options are provided", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition }) - const res = ModuleDefinitionLoader({ + const res = registerModules({ modules: { [defaultDefinition.key]: { options: { test: 123 }, @@ -175,7 +175,7 @@ describe("module definitions loader", () => { it("Resolves resolution path and provides options when only options are provided", () => { MODULE_DEFINITIONS.push({ ...defaultDefinition }) - const res = ModuleDefinitionLoader({ + const res = registerModules({ modules: { [defaultDefinition.key]: { resolve: defaultDefinition.defaultPackage, diff --git a/packages/medusa/src/loaders/__tests__/module.spec.ts b/packages/modules-sdk/src/loaders/__tests__/module-loader.ts similarity index 90% rename from packages/medusa/src/loaders/__tests__/module.spec.ts rename to packages/modules-sdk/src/loaders/__tests__/module-loader.ts index f74b69b5f7..7833308b25 100644 --- a/packages/medusa/src/loaders/__tests__/module.spec.ts +++ b/packages/modules-sdk/src/loaders/__tests__/module-loader.ts @@ -4,17 +4,17 @@ import { AwilixContainer, ClassOrFunctionReturning, createContainer, - Resolver + Resolver, } from "awilix" import { ConfigModule, MedusaContainer, ModuleResolution, MODULE_RESOURCE_TYPE, - MODULE_SCOPE -} from "../../types/global" -import Logger from "../logger" -import registerModules from "../module" + MODULE_SCOPE, +} from "../../types" + +import { moduleLoader } from "../module-loader" import { trackInstallation } from "../__mocks__/medusa-telemetry" function asArray( @@ -26,18 +26,16 @@ function asArray( } } +const logger = { + warn: jest.fn(), +} as any + const buildConfigModule = ( configParts: Partial ): ConfigModule => { return { - projectConfig: { - database_type: "sqlite", - database_logging: "all", - }, - featureFlags: {}, modules: {}, moduleResolutions: {}, - plugins: [], ...configParts, } } @@ -105,7 +103,7 @@ describe("modules loader", () => { const configModule = buildConfigModule({ moduleResolutions, }) - await registerModules({ container, configModule, logger: Logger }) + await moduleLoader({ container, configModule, logger }) const testService = container.resolve( moduleResolutions.testService.definition.key @@ -138,7 +136,7 @@ describe("modules loader", () => { moduleResolutions, }) - await registerModules({ container, configModule, logger: Logger }) + await moduleLoader({ container, configModule, logger }) const testService = container.resolve( moduleResolutions.testService.definition.key, @@ -177,15 +175,11 @@ describe("modules loader", () => { }, } - const logger: typeof Logger = { - warn: jest.fn(), - } - const configModule = buildConfigModule({ moduleResolutions, }) - await registerModules({ container, configModule, logger }) + await moduleLoader({ container, configModule, logger }) expect(logger.warn).toHaveBeenCalledWith( "Could not resolve module: TestService. Error: Loaders for module TestService failed: loader" @@ -213,15 +207,11 @@ describe("modules loader", () => { }, } - const logger: typeof Logger = { - warn: jest.fn(), - } - const configModule = buildConfigModule({ moduleResolutions, }) - await registerModules({ container, configModule, logger }) + await moduleLoader({ container, configModule, logger }) expect(logger.warn).toHaveBeenCalledWith( "Could not resolve module: TestService. Error: No service found in module. Make sure that your module exports a service." @@ -255,7 +245,7 @@ describe("modules loader", () => { moduleResolutions, }) try { - await registerModules({ container, configModule, logger: Logger }) + await moduleLoader({ container, configModule, logger }) } catch (err) { expect(err.message).toEqual( "No service found in module. Make sure that your module exports a service." @@ -290,7 +280,7 @@ describe("modules loader", () => { moduleResolutions, }) try { - await registerModules({ container, configModule, logger: Logger }) + await moduleLoader({ container, configModule, logger }) } catch (err) { expect(err.message).toEqual( "The module TestService has to define its scope (internal | external)" @@ -325,7 +315,7 @@ describe("modules loader", () => { moduleResolutions, }) try { - await registerModules({ container, configModule, logger: Logger }) + await moduleLoader({ container, configModule, logger }) } catch (err) { expect(err.message).toEqual( "The module TestService is missing its resources config" diff --git a/packages/modules-sdk/src/loaders/index.ts b/packages/modules-sdk/src/loaders/index.ts new file mode 100644 index 0000000000..bc82711793 --- /dev/null +++ b/packages/modules-sdk/src/loaders/index.ts @@ -0,0 +1,3 @@ +export * from "./module-loader" + +export * from "./module-definition" diff --git a/packages/medusa/src/loaders/module-definitions/index.ts b/packages/modules-sdk/src/loaders/module-definition.ts similarity index 90% rename from packages/medusa/src/loaders/module-definitions/index.ts rename to packages/modules-sdk/src/loaders/module-definition.ts index 68fb66aed1..be3f1957aa 100644 --- a/packages/medusa/src/loaders/module-definitions/index.ts +++ b/packages/modules-sdk/src/loaders/module-definition.ts @@ -1,9 +1,9 @@ import resolveCwd from "resolve-cwd" -import { ConfigModule, ModuleResolution } from "../../types/global" -import MODULE_DEFINITIONS from "./definitions" +import { ConfigModule, ModuleResolution } from "../types" +import MODULE_DEFINITIONS from "../definitions" -export default ({ modules }: ConfigModule) => { +export const registerModules = ({ modules }: ConfigModule) => { const moduleResolutions = {} as Record const projectModules = modules ?? {} diff --git a/packages/medusa/src/loaders/module.ts b/packages/modules-sdk/src/loaders/module-loader.ts similarity index 95% rename from packages/medusa/src/loaders/module.ts rename to packages/modules-sdk/src/loaders/module-loader.ts index f7c4ab8066..fb8ebef322 100644 --- a/packages/medusa/src/loaders/module.ts +++ b/packages/modules-sdk/src/loaders/module-loader.ts @@ -1,6 +1,5 @@ -import { asClass, asFunction, asValue } from "awilix" +import { asFunction, asValue } from "awilix" import { trackInstallation } from "medusa-telemetry" -import { EntitySchema } from "typeorm" import { ClassConstructor, ConfigModule, @@ -11,8 +10,9 @@ import { ModuleResolution, MODULE_RESOURCE_TYPE, MODULE_SCOPE, -} from "../types/global" -import { ModulesHelper } from "../utils/module-helper" +} from "../types/module" + +import { ModulesHelper } from "../module-helper" export const moduleHelper = new ModulesHelper() @@ -118,7 +118,7 @@ const registerModule = async ( ) } -export default async ({ +export const moduleLoader = async ({ container, configModule, logger, diff --git a/packages/medusa/src/utils/module-helper.ts b/packages/modules-sdk/src/module-helper.ts similarity index 78% rename from packages/medusa/src/utils/module-helper.ts rename to packages/modules-sdk/src/module-helper.ts index 2e4df1bae5..e76c1e0e84 100644 --- a/packages/medusa/src/utils/module-helper.ts +++ b/packages/modules-sdk/src/module-helper.ts @@ -1,5 +1,4 @@ -import { ModuleResolution } from "../types/global" -import { ModulesResponse } from "../types/modules" +import { ModuleResolution, ModulesResponse } from "./types/module" export class ModulesHelper { private modules_: Record = {} diff --git a/packages/modules-sdk/src/types/index.ts b/packages/modules-sdk/src/types/index.ts new file mode 100644 index 0000000000..a7f4654100 --- /dev/null +++ b/packages/modules-sdk/src/types/index.ts @@ -0,0 +1 @@ +export * from "./module" diff --git a/packages/modules-sdk/src/types/module.ts b/packages/modules-sdk/src/types/module.ts new file mode 100644 index 0000000000..b29868d93a --- /dev/null +++ b/packages/modules-sdk/src/types/module.ts @@ -0,0 +1,103 @@ +import { AwilixContainer } from "awilix" +import { Logger as _Logger } from "winston" + +export type LogLevel = + | "query" + | "schema" + | "error" + | "warn" + | "info" + | "log" + | "migration" +export type LoggerOptions = boolean | "all" | LogLevel[] + +export type ClassConstructor = { + new (...args: unknown[]): T +} + +export type MedusaContainer = AwilixContainer & { + registerAdd: (name: string, registration: T) => MedusaContainer +} + +export type Logger = _Logger & { + progress: (activityId: string, msg: string) => void + info: (msg: string) => void + warn: (msg: string) => void +} + +export enum MODULE_SCOPE { + INTERNAL = "internal", + EXTERNAL = "external", +} + +export enum MODULE_RESOURCE_TYPE { + SHARED = "shared", + ISOLATED = "isolated", +} + +export type ConfigurableModuleDeclaration = { + scope: MODULE_SCOPE.INTERNAL + resources: MODULE_RESOURCE_TYPE + resolve?: string + options?: Record +} +/* +| { + scope: MODULE_SCOPE.external + server: { + type: "built-in" | "rest" | "tsrpc" | "grpc" | "gql" + url: string + options?: Record + } + } +*/ + +export type ModuleResolution = { + resolutionPath: string | false + definition: ModuleDefinition + options?: Record + moduleDeclaration?: ConfigurableModuleDeclaration +} + +export type ModuleDefinition = { + key: string + registrationName: string + defaultPackage: string | false + label: string + canOverride?: boolean + isRequired?: boolean + defaultModuleDeclaration: ConfigurableModuleDeclaration +} + +export type LoaderOptions = { + container: MedusaContainer + configModule: ConfigModule + options?: Record + logger?: Logger +} + +export type Constructor = new (...args: any[]) => T + +export type ModuleExports = { + loaders: (( + options: LoaderOptions, + moduleDeclaration?: ConfigurableModuleDeclaration + ) => Promise)[] + service: Constructor + migrations?: any[] + models?: Constructor[] +} + +export type ConfigModule = { + options?: Record + modules?: Record< + string, + false | string | Partial + > + moduleResolutions?: Record +} + +export type ModulesResponse = { + module: string + resolution: string | false +}[] diff --git a/packages/modules-sdk/tsconfig.json b/packages/modules-sdk/tsconfig.json new file mode 100644 index 0000000000..0fc6130e78 --- /dev/null +++ b/packages/modules-sdk/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "lib": [ + "es5", + "es6", + "es2019" + ], + "target": "es5", + "outDir": "./dist", + "esModuleInterop": true, + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "allowJs": true, + "skipLibCheck": true, + "downlevelIteration": true // to use ES5 specific tooling + }, + "include": ["./src/**/*", "index.d.ts"], + "exclude": [ + "./dist/**/*", + "./src/**/__tests__", + "./src/**/__mocks__", + "node_modules" + ] +} \ No newline at end of file diff --git a/packages/stock-location/package.json b/packages/stock-location/package.json index 6a0fec7a44..499dca62d2 100644 --- a/packages/stock-location/package.json +++ b/packages/stock-location/package.json @@ -24,6 +24,9 @@ "typeorm": "^0.3.11", "typescript": "^4.4.4" }, + "dependencies": { + "@medusajs/modules-sdk": "*" + }, "scripts": { "watch": "tsc --build --watch", "prepare": "cross-env NODE_ENV=production yarn run build", diff --git a/packages/stock-location/src/index.ts b/packages/stock-location/src/index.ts index 955d114b77..f804b8af91 100644 --- a/packages/stock-location/src/index.ts +++ b/packages/stock-location/src/index.ts @@ -2,7 +2,7 @@ import ConnectionLoader from "./loaders/connection" import StockLocationService from "./services/stock-location" import * as SchemaMigration from "./migrations/schema-migrations/1665749860179-setup" import * as StockLocationModels from "./models" -import { ModuleExports } from "@medusajs/medusa" +import { ModuleExports } from "@medusajs/modules-sdk" const service = StockLocationService const migrations = [SchemaMigration] diff --git a/packages/stock-location/src/loaders/connection.ts b/packages/stock-location/src/loaders/connection.ts index 87dc6fa7d2..09d777bae8 100644 --- a/packages/stock-location/src/loaders/connection.ts +++ b/packages/stock-location/src/loaders/connection.ts @@ -1,4 +1,7 @@ -import { ConfigurableModuleDeclaration, LoaderOptions } from "@medusajs/medusa" +import { + ConfigurableModuleDeclaration, + LoaderOptions, +} from "@medusajs/modules-sdk" export default async ( { configModule }: LoaderOptions, diff --git a/packages/stock-location/src/services/stock-location.ts b/packages/stock-location/src/services/stock-location.ts index 6ed9c35e71..6ba222836e 100644 --- a/packages/stock-location/src/services/stock-location.ts +++ b/packages/stock-location/src/services/stock-location.ts @@ -1,16 +1,20 @@ import { buildQuery, - ConfigurableModuleDeclaration, CreateStockLocationInput, FilterableStockLocationProps, FindConfig, IEventBusService, - MODULE_RESOURCE_TYPE, setMetadata, StockLocationAddressInput, TransactionBaseService, UpdateStockLocationInput, } from "@medusajs/medusa" + +import { + ConfigurableModuleDeclaration, + MODULE_RESOURCE_TYPE, +} from "@medusajs/modules-sdk" + import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" @@ -232,7 +236,7 @@ export default class StockLocationService extends TransactionBaseService { const locationAddressRepo = manager.getRepository(StockLocationAddress) const existingAddress = await locationAddressRepo.findOne({ - where: { id: addressId } + where: { id: addressId }, }) if (!existingAddress) { throw new MedusaError( diff --git a/yarn.lock b/yarn.lock index 5707dcf83a..62b04a1bef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5219,6 +5219,7 @@ __metadata: resolution: "@medusajs/inventory@workspace:packages/inventory" dependencies: "@medusajs/medusa": "*" + "@medusajs/modules-sdk": "*" cross-env: ^5.2.1 jest: ^25.5.4 ts-jest: ^25.5.1 @@ -5322,6 +5323,7 @@ __metadata: "@babel/core": ^7.14.3 "@babel/preset-typescript": ^7.13.0 "@medusajs/medusa-cli": ^1.3.8 + "@medusajs/modules-sdk": "*" "@types/express": ^4.17.17 "@types/ioredis": ^4.28.10 "@types/jest": ^27.5.2 @@ -5385,6 +5387,20 @@ __metadata: languageName: unknown linkType: soft +"@medusajs/modules-sdk@*, @medusajs/modules-sdk@workspace:packages/modules-sdk": + version: 0.0.0-use.local + resolution: "@medusajs/modules-sdk@workspace:packages/modules-sdk" + dependencies: + awilix: ^8.0.0 + cross-env: ^5.2.1 + jest: ^25.5.4 + medusa-telemetry: ^0.0.16 + resolve-cwd: ^3.0.0 + ts-jest: ^25.5.1 + typescript: ^4.4.4 + languageName: unknown + linkType: soft + "@medusajs/openapi-typescript-codegen@*, @medusajs/openapi-typescript-codegen@workspace:packages/oas/openapi-typescript-codegen": version: 0.0.0-use.local resolution: "@medusajs/openapi-typescript-codegen@workspace:packages/oas/openapi-typescript-codegen" @@ -5427,6 +5443,7 @@ __metadata: resolution: "@medusajs/stock-location@workspace:packages/stock-location" dependencies: "@medusajs/medusa": ^1.7.7 + "@medusajs/modules-sdk": "*" cross-env: ^5.2.1 jest: ^25.5.4 ts-jest: ^25.5.1