@medusajs/utils
Version:
Medusa utilities functions shared by Medusa core and Modules
334 lines • 14.4 kB
JavaScript
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
;