UNPKG

@medusajs/utils

Version:

Medusa utilities functions shared by Medusa core and Modules

334 lines • 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_STORE_RESTRICTED_FIELDS = void 0; exports.defineConfig = defineConfig; exports.transformModules = transformModules; const modules_sdk_1 = require("../modules-sdk"); const is_object_1 = require("./is-object"); const is_string_1 = require("./is-string"); const try_convert_to_number_1 = require("./try-convert-to-number"); const normalize_import_path_with_source_1 = require("./normalize-import-path-with-source"); const resolve_exports_1 = require("./resolve-exports"); const MEDUSA_CLOUD_EXECUTION_CONTEXT = "medusa-cloud"; const DEFAULT_SECRET = "supersecret"; const DEFAULT_ADMIN_URL = "/"; 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"; exports.DEFAULT_STORE_RESTRICTED_FIELDS = [ "order", "orders", /*"customer", "customers", "payment_collection", "payment_collections"*/ ]; /** * 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. */ function defineConfig(config = {}) { const options = { isCloud: process.env.EXECUTION_CONTEXT === MEDUSA_CLOUD_EXECUTION_CONTEXT, }; const projectConfig = normalizeProjectConfig(config.projectConfig, options); const adminConfig = normalizeAdminConfig(config.admin); const modules = resolveModules(config.modules, options, config.projectConfig); return { projectConfig, featureFlags: (config.featureFlags ?? {}), plugins: config.plugins || [], admin: adminConfig, modules: modules, }; } /** * Transforms an array of modules into an object. The last module will * take precedence in case of duplicate modules */ function transformModules(modules) { const remappedModules = modules.reduce((acc, moduleConfig) => { if (moduleConfig.scope === "external" && !moduleConfig.key) { throw new Error("External modules configuration must have a 'key'. Please provide a key for the module."); } if ("disable" in moduleConfig && "key" in moduleConfig) { acc[moduleConfig.key] = moduleConfig; } // TODO: handle external modules later let serviceName = "key" in moduleConfig && moduleConfig.key ? moduleConfig.key : ""; delete moduleConfig.key; if (!serviceName && "resolve" in moduleConfig) { if ((0, is_string_1.isString)(moduleConfig.resolve) && modules_sdk_1.REVERSED_MODULE_PACKAGE_NAMES[moduleConfig.resolve]) { serviceName = modules_sdk_1.REVERSED_MODULE_PACKAGE_NAMES[moduleConfig.resolve]; acc[serviceName] = moduleConfig; return acc; } let resolution = (0, is_string_1.isString)(moduleConfig.resolve) ? (0, normalize_import_path_with_source_1.normalizeImportPathWithSource)(moduleConfig.resolve) : moduleConfig.resolve; const moduleExport = (0, is_string_1.isString)(resolution) ? require(resolution) : resolution; const defaultExport = (0, resolve_exports_1.resolveExports)(moduleExport).default; const joinerConfig = typeof defaultExport.service.prototype.__joinerConfig === "function" ? defaultExport.service.prototype.__joinerConfig() ?? {} : defaultExport.service.prototype.__joinerConfig ?? {}; serviceName = joinerConfig.serviceName; if (!serviceName) { throw new Error(`Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.`); } } acc[serviceName] = moduleConfig; return acc; }, {}); return remappedModules; } /** * The user API allow to use array of modules configuration. This method manage the loading of the * user modules along side the default modules and re map them to an object. * * @param configModules */ function resolveModules(configModules, { isCloud }, projectConfig) { const sharedModules = [ { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.STOCK_LOCATION] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.INVENTORY] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.PRODUCT] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.PRICING] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.PROMOTION] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.CUSTOMER] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.SALES_CHANNEL] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.CART] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.REGION] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.API_KEY] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.STORE] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.TAX] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.CURRENCY] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.PAYMENT] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.ORDER] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.AUTH], options: { providers: [ { resolve: "@medusajs/medusa/auth-emailpass", id: "emailpass", }, ], }, }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.USER], options: { jwt_secret: projectConfig?.http?.jwtSecret ?? DEFAULT_SECRET, jwt_options: projectConfig?.http?.jwtOptions, jwt_verify_options: projectConfig?.http?.jwtVerifyOptions, jwt_public_key: projectConfig?.http?.jwtPublicKey, }, }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.FULFILLMENT], options: { providers: [ { resolve: "@medusajs/medusa/fulfillment-manual", id: "manual", }, ], }, }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.NOTIFICATION], options: { providers: [ { resolve: "@medusajs/medusa/notification-local", id: "local", options: { name: "Local Notification Provider", channels: ["feed"], }, }, ], }, }, ]; const defaultModules = [ ...sharedModules, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.CACHE] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.EVENT_BUS] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.WORKFLOW_ENGINE] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.LOCKING] }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.FILE], options: { providers: [ { resolve: "@medusajs/medusa/file-local", id: "local", }, ], }, }, ]; const cloudModules = [ ...sharedModules, { resolve: modules_sdk_1.TEMPORARY_REDIS_MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.WORKFLOW_ENGINE], options: { redis: { url: process.env.REDIS_URL }, }, }, { resolve: modules_sdk_1.TEMPORARY_REDIS_MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.CACHE], options: { redisUrl: process.env.REDIS_URL }, }, { resolve: modules_sdk_1.TEMPORARY_REDIS_MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.EVENT_BUS], options: { redisUrl: process.env.REDIS_URL }, }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.LOCKING], options: { providers: [ { id: "locking-redis", resolve: modules_sdk_1.TEMPORARY_REDIS_MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.LOCKING], is_default: true, options: { redisUrl: process.env.REDIS_URL, }, }, ], }, }, { resolve: modules_sdk_1.MODULE_PACKAGE_NAMES[modules_sdk_1.Modules.FILE], options: { providers: [ { id: "s3", resolve: "@medusajs/medusa/file-s3", options: { authentication_method: "s3-iam-role", file_url: process.env.S3_FILE_URL, prefix: process.env.S3_PREFIX, region: process.env.S3_REGION, bucket: process.env.S3_BUCKET, endpoint: process.env.S3_ENDPOINT, }, }, ], }, }, ]; /** * 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 = isCloud ? cloudModules : defaultModules; /** * Backward compatibility for the old way of defining modules (object vs array) */ if (configModules) { if ((0, is_object_1.isObject)(configModules)) { const modules_ = (configModules ?? {}); Object.entries(modules_).forEach(([key, moduleConfig]) => { modules.push({ key, ...((0, is_object_1.isObject)(moduleConfig) ? moduleConfig : { disable: !moduleConfig }), }); }); } else if (Array.isArray(configModules)) { const modules_ = (configModules ?? []); modules.push(...modules_); } else { throw new Error("Invalid modules configuration. Should be an array or object."); } } return transformModules(modules); } function normalizeProjectConfig(projectConfig, { isCloud }) { const { http, redisOptions, sessionOptions, ...restOfProjectConfig } = projectConfig || {}; /** * The defaults to use for the project config. They are shallow merged * with the user defined config. */ const config = { ...(isCloud ? { redisUrl: process.env.REDIS_URL } : {}), 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, jwtPublicKey: process.env.JWT_PUBLIC_KEY, cookieSecret: process.env.COOKIE_SECRET || DEFAULT_SECRET, restrictedFields: { store: exports.DEFAULT_STORE_RESTRICTED_FIELDS, }, ...http, }, redisOptions: { retryStrategy(retries) { /** * Exponentially increase delay with every retry * attempt. Max to 4s */ const delay = Math.min(Math.pow(2, retries) * 50, 4000); /** * Add a random jitter to not choke the server when multiple * clients are retrying at the same time */ const jitter = Math.floor(Math.random() * 200); return delay + jitter; }, ...redisOptions, }, sessionOptions: { ...(isCloud && process.env.SESSION_STORE === "dynamodb" ? { dynamodbOptions: { prefix: process.env.DYNAMO_DB_SESSIONS_PREFIX ?? "sess:", hashKey: process.env.DYNAMO_DB_SESSIONS_HASH_KEY ?? "id", initialized: process.env.DYNAMO_DB_SESSIONS_CREATE_TABLE ? false : true, table: process.env.DYNAMO_DB_SESSIONS_TABLE ?? "medusa-sessions", readCapacityUnits: (0, try_convert_to_number_1.tryConvertToNumber)(process.env.DYNAMO_DB_SESSIONS_READ_UNITS, 5), writeCapacityUnits: (0, try_convert_to_number_1.tryConvertToNumber)(process.env.DYNAMO_DB_SESSIONS_WRITE_UNITS, 5), skipThrowMissingSpecialKeys: true, }, } : {}), ...sessionOptions, }, ...restOfProjectConfig, }; return config; } function normalizeAdminConfig(adminConfig) { /** * The defaults to use for the admin config. They are shallow merged * with the user defined config */ return { backendUrl: process.env.MEDUSA_BACKEND_URL || DEFAULT_ADMIN_URL, path: "/app", ...adminConfig, }; } //# sourceMappingURL=define-config.js.map