From a40b6aef6ddbc0ca250f6f57152783b647de3520 Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Wed, 29 May 2024 17:10:15 +0530 Subject: [PATCH] Add defineConfig helper (#7517) --- .../core/types/src/common/config-module.ts | 2 +- .../common/__tests__/define-config.spec.ts | 259 ++++++++++++++++++ .../core/utils/src/common/define-config.ts | 127 +++++++++ packages/core/utils/src/common/index.ts | 1 + 4 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 packages/core/utils/src/common/__tests__/define-config.spec.ts create mode 100644 packages/core/utils/src/common/define-config.ts diff --git a/packages/core/types/src/common/config-module.ts b/packages/core/types/src/common/config-module.ts index e90bc1e617..e672be344c 100644 --- a/packages/core/types/src/common/config-module.ts +++ b/packages/core/types/src/common/config-module.ts @@ -213,7 +213,7 @@ export type ProjectConfigOptions = { * } * ``` */ - databaseLogging: LoggerOptions + databaseLogging?: LoggerOptions /** * @ignore diff --git a/packages/core/utils/src/common/__tests__/define-config.spec.ts b/packages/core/utils/src/common/__tests__/define-config.spec.ts new file mode 100644 index 0000000000..7a6b4b6ac6 --- /dev/null +++ b/packages/core/utils/src/common/__tests__/define-config.spec.ts @@ -0,0 +1,259 @@ +import { defineConfig } from "../define-config" + +describe("defineConfig", function () { + it("should merge empty config with the defaults", function () { + expect(defineConfig()).toMatchInlineSnapshot(` + { + "admin": { + "backendUrl": "http://localhost:9000", + }, + "featureFlags": {}, + "modules": { + "apiKey": true, + "auth": true, + "cacheService": true, + "cart": true, + "currency": true, + "customer": true, + "eventBus": true, + "file": { + "options": { + "providers": [ + { + "options": { + "config": { + "local": {}, + }, + }, + "resolve": "@medusajs/file-local-next", + }, + ], + }, + "resolve": "@medusajs/file", + }, + "fulfillment": { + "options": { + "providers": [ + { + "options": { + "config": { + "manual": {}, + }, + }, + "resolve": "@medusajs/fulfillment-manual", + }, + ], + }, + "resolve": "@medusajs/fulfillment", + }, + "inventoryService": true, + "order": true, + "payment": true, + "pricingService": true, + "productService": true, + "promotion": true, + "region": true, + "salesChannel": true, + "stockLocationService": true, + "store": true, + "tax": true, + "user": { + "options": { + "jwt_secret": "supersecret", + }, + "resolve": "@medusajs/user", + }, + "workflows": true, + }, + "plugins": [], + "projectConfig": { + "databaseUrl": "postgres://localhost/medusa-starter-default", + "http": { + "adminCors": "http://localhost:7000,http://localhost:7001,http://localhost:5173", + "authCors": "http://localhost:7000,http://localhost:7001,http://localhost:5173", + "cookieSecret": "supersecret", + "jwtSecret": "supersecret", + "storeCors": "http://localhost:8000", + }, + }, + } + `) + }) + + it("should merge custom modules", function () { + expect( + defineConfig({ + modules: { + githubModuleService: { + resolve: "./modules/github", + }, + }, + }) + ).toMatchInlineSnapshot(` + { + "admin": { + "backendUrl": "http://localhost:9000", + }, + "featureFlags": {}, + "modules": { + "apiKey": true, + "auth": true, + "cacheService": true, + "cart": true, + "currency": true, + "customer": true, + "eventBus": true, + "file": { + "options": { + "providers": [ + { + "options": { + "config": { + "local": {}, + }, + }, + "resolve": "@medusajs/file-local-next", + }, + ], + }, + "resolve": "@medusajs/file", + }, + "fulfillment": { + "options": { + "providers": [ + { + "options": { + "config": { + "manual": {}, + }, + }, + "resolve": "@medusajs/fulfillment-manual", + }, + ], + }, + "resolve": "@medusajs/fulfillment", + }, + "githubModuleService": { + "resolve": "./modules/github", + }, + "inventoryService": true, + "order": true, + "payment": true, + "pricingService": true, + "productService": true, + "promotion": true, + "region": true, + "salesChannel": true, + "stockLocationService": true, + "store": true, + "tax": true, + "user": { + "options": { + "jwt_secret": "supersecret", + }, + "resolve": "@medusajs/user", + }, + "workflows": true, + }, + "plugins": [], + "projectConfig": { + "databaseUrl": "postgres://localhost/medusa-starter-default", + "http": { + "adminCors": "http://localhost:7000,http://localhost:7001,http://localhost:5173", + "authCors": "http://localhost:7000,http://localhost:7001,http://localhost:5173", + "cookieSecret": "supersecret", + "jwtSecret": "supersecret", + "storeCors": "http://localhost:8000", + }, + }, + } + `) + }) + + it("should merge custom project.http config", function () { + expect( + defineConfig({ + projectConfig: { + http: { + adminCors: "http://localhost:3000", + } as any, + }, + }) + ).toMatchInlineSnapshot(` + { + "admin": { + "backendUrl": "http://localhost:9000", + }, + "featureFlags": {}, + "modules": { + "apiKey": true, + "auth": true, + "cacheService": true, + "cart": true, + "currency": true, + "customer": true, + "eventBus": true, + "file": { + "options": { + "providers": [ + { + "options": { + "config": { + "local": {}, + }, + }, + "resolve": "@medusajs/file-local-next", + }, + ], + }, + "resolve": "@medusajs/file", + }, + "fulfillment": { + "options": { + "providers": [ + { + "options": { + "config": { + "manual": {}, + }, + }, + "resolve": "@medusajs/fulfillment-manual", + }, + ], + }, + "resolve": "@medusajs/fulfillment", + }, + "inventoryService": true, + "order": true, + "payment": true, + "pricingService": true, + "productService": true, + "promotion": true, + "region": true, + "salesChannel": true, + "stockLocationService": true, + "store": true, + "tax": true, + "user": { + "options": { + "jwt_secret": "supersecret", + }, + "resolve": "@medusajs/user", + }, + "workflows": true, + }, + "plugins": [], + "projectConfig": { + "databaseUrl": "postgres://localhost/medusa-starter-default", + "http": { + "adminCors": "http://localhost:3000", + "authCors": "http://localhost:7000,http://localhost:7001,http://localhost:5173", + "cookieSecret": "supersecret", + "jwtSecret": "supersecret", + "storeCors": "http://localhost:8000", + }, + }, + } + `) + }) +}) diff --git a/packages/core/utils/src/common/define-config.ts b/packages/core/utils/src/common/define-config.ts new file mode 100644 index 0000000000..ca6e875898 --- /dev/null +++ b/packages/core/utils/src/common/define-config.ts @@ -0,0 +1,127 @@ +import { ConfigModule } from "@medusajs/types" +import { Modules } from "../modules-sdk" + +const DEFAULT_SECRET = "supersecret" +const DEFAULT_ADMIN_URL = "http://localhost:9000" +const DEFAULT_STORE_CORS = "http://localhost:8000" +const DEFAULT_DATABASE_URL = "postgres://localhost/medusa-starter-default" +const DEFAULT_ADMIN_CORS = + "http://localhost:7000,http://localhost:7001,http://localhost:5173" + +/** + * The "defineConfig" helper can be used to define the configuration + * of a medusa application. + * + * The helper under the hood merges your config with a set of defaults to + * make an application work seamlessly, but still provide you the ability + * to override configuration as needed. + */ +export function defineConfig(config: Partial = {}): ConfigModule { + const { http, ...restOfProjectConfig } = config.projectConfig || {} + + /** + * The defaults to use for the project config. They are shallow merged + * with the user defined config. However, + */ + const projectConfig: ConfigModule["projectConfig"] = { + databaseUrl: process.env.DATABASE_URL || DEFAULT_DATABASE_URL, + http: { + storeCors: process.env.STORE_CORS || DEFAULT_STORE_CORS, + adminCors: process.env.ADMIN_CORS || DEFAULT_ADMIN_CORS, + authCors: process.env.AUTH_CORS || DEFAULT_ADMIN_CORS, + jwtSecret: process.env.JWT_SECRET || DEFAULT_SECRET, + cookieSecret: process.env.COOKIE_SECRET || DEFAULT_SECRET, + ...http, + }, + ...restOfProjectConfig, + } + + /** + * The defaults to use for the admin config. They are shallow merged + * with the user defined config + */ + const admin: ConfigModule["admin"] = { + backendUrl: DEFAULT_ADMIN_URL, + ...config.admin, + } + + /** + * The defaults to use for the feature flags config. They are shallow merged + * with the user defined config + */ + const featureFlags: ConfigModule["featureFlags"] = { + ...config.featureFlags, + } + + /** + * The default set of modules to always use. The end user can swap + * the modules by providing an alternate implementation via their + * config. But they can never remove a module from this list. + */ + const modules: ConfigModule["modules"] = { + [Modules.CACHE]: true, + [Modules.EVENT_BUS]: true, + [Modules.AUTH]: true, + [Modules.WORKFLOW_ENGINE]: true, + [Modules.STOCK_LOCATION]: true, + [Modules.INVENTORY]: true, + [Modules.PRODUCT]: true, + [Modules.PRICING]: true, + [Modules.PROMOTION]: true, + [Modules.CUSTOMER]: true, + [Modules.SALES_CHANNEL]: true, + [Modules.CART]: true, + [Modules.REGION]: true, + [Modules.API_KEY]: true, + [Modules.STORE]: true, + [Modules.TAX]: true, + [Modules.CURRENCY]: true, + [Modules.PAYMENT]: true, + [Modules.ORDER]: true, + [Modules.USER]: { + resolve: "@medusajs/user", + options: { + jwt_secret: process.env.JWT_SECRET ?? DEFAULT_SECRET, + }, + }, + [Modules.FILE]: { + resolve: "@medusajs/file", + options: { + providers: [ + { + resolve: "@medusajs/file-local-next", + options: { + config: { + local: {}, + }, + }, + }, + ], + }, + }, + [Modules.FULFILLMENT]: { + resolve: "@medusajs/fulfillment", + options: { + providers: [ + { + resolve: "@medusajs/fulfillment-manual", + options: { + config: { + manual: {}, + }, + }, + }, + ], + }, + }, + ...config.modules, + } + + return { + projectConfig, + featureFlags, + plugins: config.plugins || [], + admin, + modules, + } +} diff --git a/packages/core/utils/src/common/index.ts b/packages/core/utils/src/common/index.ts index 8d89b4496a..95977c4cee 100644 --- a/packages/core/utils/src/common/index.ts +++ b/packages/core/utils/src/common/index.ts @@ -62,5 +62,6 @@ export * from "./validate-handle" export * from "./parse-cors-origins" export * from "./build-regexp-if-valid" export * from "./load-env" +export * from "./define-config" export * from "./file-system" export * from "./graceful-shutdown-server"