chore(framework): Initial commit (#8221)
**What** - Initiate the framework package (which is just a place to move things around for now) - move the config loader and related resources as well as the `ConfigModule` type - Create a ConfigManager singleton which prepare and store the config (later can be stored entirely in the container) and allow for easier test override - re export the logger from the framework - replace medusa config loader with the framework one - `build` run type check on tests as well but `prepublishOnly` will not fail on build if tests are typed broken FIXES FRMW-2607 FIXES FRMW-2609 FIXES FRMW-2614 FIXES FRMW-2618
This commit is contained in:
committed by
GitHub
parent
97f64a5cfe
commit
47dde05517
@@ -33,6 +33,8 @@ packages/*
|
|||||||
!packages/fulfillment
|
!packages/fulfillment
|
||||||
!packages/fulfillment-manual
|
!packages/fulfillment-manual
|
||||||
|
|
||||||
|
!packages/framework
|
||||||
|
|
||||||
|
|
||||||
**/models/*
|
**/models/*
|
||||||
**/scripts/*
|
**/scripts/*
|
||||||
|
|||||||
19
.eslintrc.js
19
.eslintrc.js
@@ -86,23 +86,18 @@ module.exports = {
|
|||||||
"./packages/admin-next/admin-shared/tsconfig.json",
|
"./packages/admin-next/admin-shared/tsconfig.json",
|
||||||
"./packages/admin-next/admin-vite-plugin/tsconfig.json",
|
"./packages/admin-next/admin-vite-plugin/tsconfig.json",
|
||||||
|
|
||||||
"./packages/inventory/tsconfig.spec.json",
|
"./packages/cli/create-medusa-app/tsconfig.json",
|
||||||
"./packages/stock-location/tsconfig.spec.json",
|
"./packages/cli/medusa-cli/tsconfig.spec.json",
|
||||||
|
|
||||||
"./packages/core-flows/tsconfig.spec.json",
|
|
||||||
|
|
||||||
"./packages/cli/create-medusa-app/tsconfig.spec.json",
|
|
||||||
"./packages/cli/medusa-cli/tsconfig.spec/json",
|
|
||||||
"./packages/cli/medusa-dev-cli/tsconfig.spec.json",
|
"./packages/cli/medusa-dev-cli/tsconfig.spec.json",
|
||||||
"./packages/cli/oas/medusa-oas-cli/tsconfig.spec.json",
|
"./packages/cli/oas/medusa-oas-cli/tsconfig.spec.json",
|
||||||
|
|
||||||
"./packages/core/orchestration/tsconfig.json",
|
"./packages/core/orchestration/tsconfig.json",
|
||||||
"./packages/core/workflows-sdk/tsconfig.spec.json",
|
"./packages/core/workflows-sdk/tsconfig.spec.json",
|
||||||
"./packages/core/modules-sdk/tsconfig.spec.json",
|
"./packages/core/modules-sdk/tsconfig.json",
|
||||||
"./packages/core/js-sdk/tsconfig.spec.json",
|
"./packages/core/js-sdk/tsconfig.json",
|
||||||
"./packages/core/types/tsconfig.spec.json",
|
"./packages/core/types/tsconfig.json",
|
||||||
"./packages/core/utils/tsconfig.spec.json",
|
"./packages/core/utils/tsconfig.spec.json",
|
||||||
"./packages/core/medusa-test-utils/tsconfig.spec.json",
|
"./packages/core/medusa-test-utils/tsconfig.json",
|
||||||
|
|
||||||
"./packages/modules/product/tsconfig.json",
|
"./packages/modules/product/tsconfig.json",
|
||||||
"./packages/modules/event-bus-local/tsconfig.spec.json",
|
"./packages/modules/event-bus-local/tsconfig.spec.json",
|
||||||
@@ -137,6 +132,8 @@ module.exports = {
|
|||||||
"./packages/modules/providers/file-s3/tsconfig.spec.json",
|
"./packages/modules/providers/file-s3/tsconfig.spec.json",
|
||||||
"./packages/modules/providers/fulfillment-manual/tsconfig.spec.json",
|
"./packages/modules/providers/fulfillment-manual/tsconfig.spec.json",
|
||||||
"./packages/modules/providers/payment-stripe/tsconfig.spec.json",
|
"./packages/modules/providers/payment-stripe/tsconfig.spec.json",
|
||||||
|
|
||||||
|
"./packages/framework/framework/tsconfig.json",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:integration": "jest --silent=false --no-cache --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage",
|
"test:integration": "NODE_OPTIONS=--experimental-vm-modules jest --silent=false --no-cache --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage",
|
||||||
"test:integration:chunk": "jest --silent --no-cache --bail --maxWorkers=50% --forceExit --detectOpenHandles --testPathPattern=$(echo $CHUNKS | jq -r \".[${CHUNK}] | .[]\")",
|
"test:integration:chunk": "NODE_OPTIONS=--experimental-vm-modules jest --silent --no-cache --bail --maxWorkers=50% --forceExit --detectOpenHandles --testPathPattern=$(echo $CHUNKS | jq -r \".[${CHUNK}] | .[]\")",
|
||||||
"build": "tsc ./src/* --allowJs --outDir ./dist"
|
"build": "tsc ./src/* --allowJs --outDir ./dist"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ module.exports = {
|
|||||||
jsc: {
|
jsc: {
|
||||||
parser: { syntax: "typescript", decorators: true },
|
parser: { syntax: "typescript", decorators: true },
|
||||||
transform: { decoratorMetadata: true },
|
transform: { decoratorMetadata: true },
|
||||||
|
target: "es2021",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:integration": "jest --no-cache --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage",
|
"test:integration": "NODE_OPTIONS=--experimental-vm-modules jest --no-cache --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage -- __tests__/payment-collection/admin/payment-sessions.spec.ts",
|
||||||
"test:integration:chunk": "jest --silent --no-cache --bail --maxWorkers=50% --forceExit --testPathPattern=$(echo $CHUNKS | jq -r \".[${CHUNK}] | .[]\")",
|
"test:integration:chunk": "NODE_OPTIONS=--experimental-vm-modules jest --silent --no-cache --bail --maxWorkers=50% --forceExit --testPathPattern=$(echo $CHUNKS | jq -r \".[${CHUNK}] | .[]\")",
|
||||||
"build": "tsc ./src/* --allowJs --outDir ./dist"
|
"build": "tsc ./src/* --allowJs --outDir ./dist"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:integration": "jest --silent=false --no-cache --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage",
|
"test:integration": "NODE_OPTIONS=--experimental-vm-modules jest --silent=false --no-cache --maxWorkers=50% --bail --detectOpenHandles --forceExit --logHeapUsage",
|
||||||
"test:integration:chunk": "jest --silent --no-cache --bail --maxWorkers=50% --forceExit --testPathPattern=$(echo $CHUNKS | jq -r \".[${CHUNK}] | .[]\")",
|
"test:integration:chunk": "NODE_OPTIONS=--experimental-vm-modules jest --silent --no-cache --bail --maxWorkers=50% --forceExit --testPathPattern=$(echo $CHUNKS | jq -r \".[${CHUNK}] | .[]\")",
|
||||||
"build": "tsc --allowJs --outDir ./dist"
|
"build": "tsc --allowJs --outDir ./dist"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"packages/modules/*",
|
"packages/modules/*",
|
||||||
"packages/modules/providers/*",
|
"packages/modules/providers/*",
|
||||||
"packages/core/*",
|
"packages/core/*",
|
||||||
|
"packages/framework/*",
|
||||||
"packages/cli/*",
|
"packages/cli/*",
|
||||||
"packages/cli/oas/*",
|
"packages/cli/oas/*",
|
||||||
"packages/*",
|
"packages/*",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
import { IAuthModuleService } from "@medusajs/types"
|
import { IAuthModuleService } from "@medusajs/types"
|
||||||
import { ModuleRegistrationName, isDefined } from "@medusajs/utils"
|
import { isDefined, ModuleRegistrationName } from "@medusajs/utils"
|
||||||
|
|
||||||
type StepInput = {
|
type StepInput = {
|
||||||
authIdentityId: string
|
authIdentityId: string
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"author": "Sebastian Rindom",
|
"author": "Medusa",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@medusajs/types": "^1.11.16",
|
"@medusajs/types": "^1.11.16",
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
"@medusajs/framework": "workspace:^",
|
||||||
"@medusajs/medusa": ">1.19",
|
"@medusajs/medusa": ">1.19",
|
||||||
"@medusajs/modules-sdk": "^1.12.10",
|
"@medusajs/modules-sdk": "^1.12.10",
|
||||||
"axios": "^0.28.0",
|
"axios": "^0.28.0",
|
||||||
@@ -39,6 +40,9 @@
|
|||||||
"pg-god": "^1.0.12"
|
"pg-god": "^1.0.12"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
|
"@medusajs/framework": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"@medusajs/medusa": {
|
"@medusajs/medusa": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { getConfigFile } from "@medusajs/utils"
|
||||||
|
|
||||||
|
export async function configLoaderOverride(
|
||||||
|
entryDirectory: string,
|
||||||
|
override: { clientUrl: string; debug?: boolean }
|
||||||
|
) {
|
||||||
|
// in case it is not install as it is optional and required only when using this util
|
||||||
|
// @ts-ignore
|
||||||
|
const { configManager } = await import("@medusajs/framework/config")
|
||||||
|
const { configModule, error } = getConfigFile<
|
||||||
|
ReturnType<typeof configManager.loadConfig>
|
||||||
|
>(entryDirectory, "medusa-config.js")
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw new Error(error.message || "Error during config loading")
|
||||||
|
}
|
||||||
|
|
||||||
|
configModule.projectConfig.databaseUrl = override.clientUrl
|
||||||
|
configModule.projectConfig.databaseLogging = !!override.debug
|
||||||
|
configModule.projectConfig.databaseDriverOptions =
|
||||||
|
override.clientUrl.includes("localhost")
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
connection: {
|
||||||
|
ssl: { rejectUnauthorized: false },
|
||||||
|
},
|
||||||
|
idle_in_transaction_session_timeout: 20000,
|
||||||
|
}
|
||||||
|
|
||||||
|
configManager.loadConfig(configModule)
|
||||||
|
}
|
||||||
@@ -5,21 +5,17 @@ import {
|
|||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
|
|
||||||
export async function initDb({
|
export async function initDb({ env = {} }: { env?: Record<any, any> }) {
|
||||||
cwd,
|
|
||||||
env = {},
|
|
||||||
}: {
|
|
||||||
cwd: string
|
|
||||||
env?: Record<any, any>
|
|
||||||
}) {
|
|
||||||
if (isObject(env)) {
|
if (isObject(env)) {
|
||||||
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
|
Object.entries(env).forEach(([k, v]) => (process.env[k] = v))
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = createMedusaContainer()
|
const container = createMedusaContainer()
|
||||||
|
|
||||||
const configModule =
|
// in case it is not install as it is optional and required only when using this util
|
||||||
await require("@medusajs/medusa/dist/loaders/config").default(cwd)
|
// @ts-ignore
|
||||||
|
const { configManager } = await import("@medusajs/framework/config")
|
||||||
|
const configModule = configManager.config
|
||||||
|
|
||||||
const pgConnection =
|
const pgConnection =
|
||||||
await require("@medusajs/medusa/dist/loaders/pg-connection").default({
|
await require("@medusajs/medusa/dist/loaders/pg-connection").default({
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { createDatabase, dropDatabase } from "pg-god"
|
|||||||
import { getDatabaseURL } from "./database"
|
import { getDatabaseURL } from "./database"
|
||||||
import { startApp } from "./medusa-test-runner-utils/bootstrap-app"
|
import { startApp } from "./medusa-test-runner-utils/bootstrap-app"
|
||||||
import { initDb } from "./medusa-test-runner-utils/use-db"
|
import { initDb } from "./medusa-test-runner-utils/use-db"
|
||||||
|
import { configLoaderOverride } from "./medusa-test-runner-utils/config"
|
||||||
|
|
||||||
const axios = require("axios").default
|
const axios = require("axios").default
|
||||||
|
|
||||||
@@ -102,27 +103,6 @@ export function medusaIntegrationTestRunner({
|
|||||||
debug,
|
debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalConfigLoader =
|
|
||||||
require("@medusajs/medusa/dist/loaders/config").default
|
|
||||||
require("@medusajs/medusa/dist/loaders/config").default = (
|
|
||||||
rootDirectory: string
|
|
||||||
) => {
|
|
||||||
const config = originalConfigLoader(rootDirectory)
|
|
||||||
config.projectConfig.databaseUrl = dbConfig.clientUrl
|
|
||||||
config.projectConfig.databaseLogging = !!dbConfig.debug
|
|
||||||
config.projectConfig.databaseDriverOptions = dbConfig.clientUrl.includes(
|
|
||||||
"localhost"
|
|
||||||
)
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
connection: {
|
|
||||||
ssl: { rejectUnauthorized: false },
|
|
||||||
},
|
|
||||||
idle_in_transaction_session_timeout: 20000,
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
const cwd = process.cwd()
|
const cwd = process.cwd()
|
||||||
|
|
||||||
let shutdown = async () => void 0
|
let shutdown = async () => void 0
|
||||||
@@ -159,12 +139,13 @@ export function medusaIntegrationTestRunner({
|
|||||||
let isFirstTime = true
|
let isFirstTime = true
|
||||||
|
|
||||||
const beforeAll_ = async () => {
|
const beforeAll_ = async () => {
|
||||||
|
await configLoaderOverride(cwd, dbConfig)
|
||||||
|
|
||||||
console.log(`Creating database ${dbName}`)
|
console.log(`Creating database ${dbName}`)
|
||||||
await dbUtils.create(dbName)
|
await dbUtils.create(dbName)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dbUtils.pgConnection_ = await initDb({
|
dbUtils.pgConnection_ = await initDb({
|
||||||
cwd,
|
|
||||||
env,
|
env,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"module": "commonjs",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "NodeNext",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { isObject } from "./is-object"
|
|||||||
*
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
export function deepCopy<T extends Record<any, any> = Record<any, any>>(
|
export function deepCopy<
|
||||||
obj: T | T[]
|
T extends Record<any, any> | Record<any, any>[] = Record<any, any>,
|
||||||
): T | T[] {
|
TOutput = T extends [] ? T[] : T
|
||||||
|
>(obj: T): TOutput {
|
||||||
if (obj === null || typeof obj !== "object") {
|
if (obj === null || typeof obj !== "object") {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@@ -18,14 +19,14 @@ export function deepCopy<T extends Record<any, any> = Record<any, any>>(
|
|||||||
for (let i = 0; i < obj.length; i++) {
|
for (let i = 0; i < obj.length; i++) {
|
||||||
copy[i] = deepCopy(obj[i])
|
copy[i] = deepCopy(obj[i])
|
||||||
}
|
}
|
||||||
return copy
|
return copy as TOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isObject(obj)) {
|
if (isObject(obj)) {
|
||||||
const copy: Record<any, any> = {}
|
const copy: Record<any, any> = {}
|
||||||
for (let attr in obj) {
|
for (let attr in obj) {
|
||||||
if (obj.hasOwnProperty(attr)) {
|
if (obj.hasOwnProperty(attr)) {
|
||||||
copy[attr] = deepCopy(obj[attr])
|
copy[attr] = deepCopy(obj[attr] as T)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return copy
|
return copy
|
||||||
|
|||||||
0
packages/framework/framework/README.md
Normal file
0
packages/framework/framework/README.md
Normal file
17
packages/framework/framework/jest.config.js
Normal file
17
packages/framework/framework/jest.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module.exports = {
|
||||||
|
moduleNameMapper: {},
|
||||||
|
transform: {
|
||||||
|
"^.+\\.[jt]s$": [
|
||||||
|
"@swc/jest",
|
||||||
|
{
|
||||||
|
jsc: {
|
||||||
|
parser: { syntax: "typescript", decorators: true },
|
||||||
|
transform: { decoratorMetadata: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
testEnvironment: `node`,
|
||||||
|
moduleFileExtensions: [`js`, `ts`],
|
||||||
|
modulePathIgnorePatterns: ["dist/"],
|
||||||
|
}
|
||||||
66
packages/framework/framework/package.json
Normal file
66
packages/framework/framework/package.json
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "@medusajs/framework",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Framework",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"node": "./dist/index.js",
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"require": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"./config": {
|
||||||
|
"types": "./dist/config/index.d.ts",
|
||||||
|
"import": "./dist/config/index.js",
|
||||||
|
"require": "./dist/config/index.js",
|
||||||
|
"node": "./dist/config/index.js"
|
||||||
|
},
|
||||||
|
"./logger": {
|
||||||
|
"types": "./dist/logger/index.d.ts",
|
||||||
|
"import": "./dist/logger/index.js",
|
||||||
|
"require": "./dist/logger/index.js",
|
||||||
|
"node": "./dist/logger/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/medusajs/medusa",
|
||||||
|
"directory": "packages/framework/framework"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"author": "Medusa",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"watch": "tsc --build --watch -p ./tsconfig.build.json",
|
||||||
|
"watch:test": "tsc --build tsconfig.spec.json --watch",
|
||||||
|
"prepublishOnly": "cross-env NODE_ENV=production tsc -p ./tsconfig.build.json && tsc-alias -p ./tsconfig.build.json",
|
||||||
|
"build": "rimraf dist && tsc --build && tsc-alias",
|
||||||
|
"test": "jest --runInBand --bail --passWithNoTests --forceExit -- src",
|
||||||
|
"test:integration": "jest --forceExit -- integration-tests/**/__tests__/**/*.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@medusajs/types": "workspace:^",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"ioredis": "^5.2.5",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"tsc-alias": "^1.8.6",
|
||||||
|
"typescript": "^5.1.6",
|
||||||
|
"vite": "^5.2.11"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@medusajs/medusa-cli": "workspace:^",
|
||||||
|
"@medusajs/utils": "workspace:^",
|
||||||
|
"awilix": "^8.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
157
packages/framework/framework/src/config/config.ts
Normal file
157
packages/framework/framework/src/config/config.ts
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import { ConfigModule } from "./types"
|
||||||
|
import { deepCopy, isDefined } from "@medusajs/utils"
|
||||||
|
import { Logger } from "@medusajs/types"
|
||||||
|
|
||||||
|
export class ConfigManager {
|
||||||
|
/**
|
||||||
|
* A flag to specify if we are in production or not, determine whether an error would be critical and thrown or just logged as a warning in developement
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
readonly #isProduction: boolean = ["production", "prod"].includes(
|
||||||
|
process.env.NODE_ENV || ""
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The worker mode
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
readonly #envWorkMode?: ConfigModule["projectConfig"]["workerMode"] = process
|
||||||
|
.env.MEDUSA_WORKER_MODE as ConfigModule["projectConfig"]["workerMode"]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger instance to use
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
readonly #logger: Logger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config object after loading it
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#config!: ConfigModule
|
||||||
|
|
||||||
|
get config(): ConfigModule {
|
||||||
|
if (!this.#config) {
|
||||||
|
this.rejectErrors(
|
||||||
|
`Config not loaded. Make sure the config have been loaded first using the 'configLoader' or 'configManager.loadConfig'.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return this.#config
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor({ logger }: { logger: Logger }) {
|
||||||
|
this.#logger = logger
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rejects an error either by throwing when in production or by logging the error as a warning
|
||||||
|
* @param error
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected rejectErrors(error: string): never | void {
|
||||||
|
if (this.#isProduction) {
|
||||||
|
throw new Error(`[config] ⚠️ ${error}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#logger.warn(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the http config object and assign the defaults if needed
|
||||||
|
* @param projectConfig
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected buildHttpConfig(
|
||||||
|
projectConfig: Partial<ConfigModule["projectConfig"]>
|
||||||
|
): ConfigModule["projectConfig"]["http"] {
|
||||||
|
const http = (projectConfig.http ??
|
||||||
|
{}) as ConfigModule["projectConfig"]["http"]
|
||||||
|
|
||||||
|
http.jwtExpiresIn = http?.jwtExpiresIn ?? "1d"
|
||||||
|
http.authCors = http.authCors ?? ""
|
||||||
|
http.storeCors = http.storeCors ?? ""
|
||||||
|
http.adminCors = http.adminCors ?? ""
|
||||||
|
|
||||||
|
http.jwtSecret = http?.jwtSecret ?? process.env.JWT_SECRET
|
||||||
|
|
||||||
|
if (!http.jwtSecret) {
|
||||||
|
this.rejectErrors(
|
||||||
|
`http.jwtSecret not found.${
|
||||||
|
this.#isProduction ? "" : "Using default 'supersecret'."
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
http.jwtSecret = "supersecret"
|
||||||
|
}
|
||||||
|
|
||||||
|
http.cookieSecret = (projectConfig.http?.cookieSecret ??
|
||||||
|
process.env.COOKIE_SECRET)!
|
||||||
|
|
||||||
|
if (!http.cookieSecret) {
|
||||||
|
this.rejectErrors(
|
||||||
|
`http.cookieSecret not found.${
|
||||||
|
this.#isProduction ? "" : " Using default 'supersecret'."
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
http.cookieSecret = "supersecret"
|
||||||
|
}
|
||||||
|
|
||||||
|
return http
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the project config object and assign the defaults if needed
|
||||||
|
* @param projectConfig
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected normalizeProjectConfig(
|
||||||
|
projectConfig: Partial<ConfigModule["projectConfig"]>
|
||||||
|
): ConfigModule["projectConfig"] {
|
||||||
|
const outputConfig: ConfigModule["projectConfig"] = deepCopy(projectConfig)
|
||||||
|
|
||||||
|
if (!outputConfig?.redisUrl) {
|
||||||
|
console.log(`redisUrl not found. A fake redis instance will be used.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
outputConfig.http = this.buildHttpConfig(projectConfig)
|
||||||
|
|
||||||
|
let workerMode = outputConfig?.workerMode!
|
||||||
|
|
||||||
|
if (!isDefined(workerMode)) {
|
||||||
|
const env = this.#envWorkMode
|
||||||
|
if (isDefined(env)) {
|
||||||
|
const workerModes = ["shared", "worker", "server"]
|
||||||
|
if (workerModes.includes(env)) {
|
||||||
|
workerMode = env
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
workerMode = "shared"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...outputConfig,
|
||||||
|
workerMode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the full configuration after validation and normalization
|
||||||
|
*/
|
||||||
|
loadConfig(rawConfig: Partial<ConfigModule> = {}): ConfigModule {
|
||||||
|
const projectConfig = this.normalizeProjectConfig(
|
||||||
|
rawConfig.projectConfig ?? {}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.#config = {
|
||||||
|
projectConfig,
|
||||||
|
admin: rawConfig.admin ?? {},
|
||||||
|
modules: rawConfig.modules ?? {},
|
||||||
|
featureFlags: rawConfig.featureFlags ?? {},
|
||||||
|
plugins: rawConfig.plugins ?? [],
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#config
|
||||||
|
}
|
||||||
|
}
|
||||||
3
packages/framework/framework/src/config/index.ts
Normal file
3
packages/framework/framework/src/config/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./loader"
|
||||||
|
export * from "./config"
|
||||||
|
export * from "./types"
|
||||||
39
packages/framework/framework/src/config/loader.ts
Normal file
39
packages/framework/framework/src/config/loader.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { ConfigModule } from "./types"
|
||||||
|
import { getConfigFile } from "@medusajs/utils"
|
||||||
|
import { logger } from "../logger"
|
||||||
|
import { ConfigManager } from "./config"
|
||||||
|
|
||||||
|
const handleConfigError = (error: Error): void => {
|
||||||
|
logger.error(`Error in loading config: ${error.message}`)
|
||||||
|
if (error.stack) {
|
||||||
|
logger.error(error.stack)
|
||||||
|
}
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Later on we could store the config manager into the unique container
|
||||||
|
export const configManager = new ConfigManager({
|
||||||
|
logger,
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the config file and returns the config module after validating, normalizing the configurations
|
||||||
|
*
|
||||||
|
* @param entryDirectory The directory to find the config file from
|
||||||
|
* @param configFileName The name of the config file to search for in the entry directory
|
||||||
|
*/
|
||||||
|
export function configLoader(
|
||||||
|
entryDirectory: string,
|
||||||
|
configFileName: string
|
||||||
|
): ConfigModule {
|
||||||
|
const { configModule, error } = getConfigFile<ConfigModule>(
|
||||||
|
entryDirectory,
|
||||||
|
configFileName
|
||||||
|
)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
handleConfigError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return configManager.loadConfig(configModule)
|
||||||
|
}
|
||||||
868
packages/framework/framework/src/config/types.ts
Normal file
868
packages/framework/framework/src/config/types.ts
Normal file
@@ -0,0 +1,868 @@
|
|||||||
|
import {
|
||||||
|
ExternalModuleDeclaration,
|
||||||
|
InternalModuleDeclaration,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
|
||||||
|
import type { RedisOptions } from "ioredis"
|
||||||
|
import type { InlineConfig } from "vite"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*
|
||||||
|
* Admin dashboard configurations.
|
||||||
|
*/
|
||||||
|
export type AdminOptions = {
|
||||||
|
/**
|
||||||
|
* Whether to disable the admin dashboard. If set to `true`, the admin dashboard is disabled,
|
||||||
|
* in both development and production environments. The default value is `false`.
|
||||||
|
*/
|
||||||
|
disable?: boolean
|
||||||
|
/**
|
||||||
|
* The path to the admin dashboard. The default value is `/app`.
|
||||||
|
*
|
||||||
|
* The value cannot be one of the reserved paths:
|
||||||
|
* - `/admin`
|
||||||
|
* - `/store`
|
||||||
|
* - `/auth`
|
||||||
|
* - `/`
|
||||||
|
*/
|
||||||
|
path?: `/${string}`
|
||||||
|
/**
|
||||||
|
* The directory where the admin build is output. This is where the build process places the generated files.
|
||||||
|
* The default value is `./build`.
|
||||||
|
*/
|
||||||
|
outDir?: string
|
||||||
|
/**
|
||||||
|
* The URL of your Medusa backend. Defaults to an empty string, which means requests will hit the same server that serves the dashboard.
|
||||||
|
*/
|
||||||
|
backendUrl?: string
|
||||||
|
/**
|
||||||
|
* Configure the Vite configuration for the admin dashboard. This function receives the default Vite configuration
|
||||||
|
* and returns the modified configuration. The default value is `undefined`.
|
||||||
|
*
|
||||||
|
* @privateRemarks TODO Add example
|
||||||
|
*/
|
||||||
|
vite?: (config: InlineConfig) => InlineConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*
|
||||||
|
* Options to pass to `express-session`.
|
||||||
|
*/
|
||||||
|
type SessionOptions = {
|
||||||
|
/**
|
||||||
|
* The name of the session ID cookie to set in the response (and read from in the request). The default value is `connect.sid`.
|
||||||
|
* Refer to [express-session’s documentation](https://www.npmjs.com/package/express-session#name) for more details.
|
||||||
|
*/
|
||||||
|
name?: string
|
||||||
|
/**
|
||||||
|
* Whether the session should be saved back to the session store, even if the session was never modified during the request. The default value is `true`.
|
||||||
|
* Refer to [express-session’s documentation](https://www.npmjs.com/package/express-session#resave) for more details.
|
||||||
|
*/
|
||||||
|
resave?: boolean
|
||||||
|
/**
|
||||||
|
* Whether the session identifier cookie should be force-set on every response. The default value is `false`.
|
||||||
|
* Refer to [express-session’s documentation](https://www.npmjs.com/package/express-session#rolling) for more details.
|
||||||
|
*/
|
||||||
|
rolling?: boolean
|
||||||
|
/**
|
||||||
|
* Whether a session that is "uninitialized" is forced to be saved to the store. The default value is `true`.
|
||||||
|
* Refer to [express-session’s documentation](https://www.npmjs.com/package/express-session#saveUninitialized) for more details.
|
||||||
|
*/
|
||||||
|
saveUninitialized?: boolean
|
||||||
|
/**
|
||||||
|
* The secret to sign the session ID cookie. By default, the value of `http.cookieSecret` is used.
|
||||||
|
* Refer to [express-session’s documentation](https://www.npmjs.com/package/express-session#secret) for details.
|
||||||
|
*/
|
||||||
|
secret?: string
|
||||||
|
/**
|
||||||
|
* Used when calculating the `Expires` `Set-Cookie` attribute of cookies. By default, its value is `10 * 60 * 60 * 1000`.
|
||||||
|
* Refer to [express-session’s documentation](https://www.npmjs.com/package/express-session#cookiemaxage) for details.
|
||||||
|
*/
|
||||||
|
ttl?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*
|
||||||
|
* HTTP compression configurations.
|
||||||
|
*/
|
||||||
|
export type HttpCompressionOptions = {
|
||||||
|
/**
|
||||||
|
* Whether HTTP compression is enabled. By default, it's `false`.
|
||||||
|
*/
|
||||||
|
enabled?: boolean
|
||||||
|
/**
|
||||||
|
* The level of zlib compression to apply to responses. A higher level will result in better compression but will take longer to complete.
|
||||||
|
* A lower level will result in less compression but will be much faster. The default value is `6`.
|
||||||
|
*/
|
||||||
|
level?: number
|
||||||
|
/**
|
||||||
|
* How much memory should be allocated to the internal compression state. It's an integer in the range of 1 (minimum level) and 9 (maximum level).
|
||||||
|
* The default value is `8`.
|
||||||
|
*/
|
||||||
|
memLevel?: number
|
||||||
|
/**
|
||||||
|
* The minimum response body size that compression is applied on. Its value can be the number of bytes or any string accepted by the
|
||||||
|
* [bytes](https://www.npmjs.com/package/bytes) module. The default value is `1024`.
|
||||||
|
*/
|
||||||
|
threshold?: number | string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*
|
||||||
|
* Essential configurations related to the Medusa backend, such as database and CORS configurations.
|
||||||
|
*/
|
||||||
|
export type ProjectConfigOptions = {
|
||||||
|
/**
|
||||||
|
* The name of the database to connect to. If specified in `databaseUrl`, then it’s not required to include it.
|
||||||
|
*
|
||||||
|
* Make sure to create the PostgreSQL database before using it. You can check how to create a database in
|
||||||
|
* [PostgreSQL's documentation](https://www.postgresql.org/docs/current/sql-createdatabase.html).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* databaseName: process.env.DATABASE_NAME ||
|
||||||
|
* "medusa-store",
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
databaseName?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection URL of the database. The format of the connection URL for PostgreSQL is:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* postgres://[user][:password]@[host][:port]/[dbname]
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Where:
|
||||||
|
*
|
||||||
|
* - `[user]`: (required) your PostgreSQL username. If not specified, the system's username is used by default. The database user that you use must have create privileges. If you're using the `postgres` superuser, then it should have these privileges by default. Otherwise, make sure to grant your user create privileges. You can learn how to do that in [PostgreSQL's documentation](https://www.postgresql.org/docs/current/ddl-priv.html).
|
||||||
|
* - `[:password]`: an optional password for the user. When provided, make sure to put `:` before the password.
|
||||||
|
* - `[host]`: (required) your PostgreSQL host. When run locally, it should be `localhost`.
|
||||||
|
* - `[:port]`: an optional port that the PostgreSQL server is listening on. By default, it's `5432`. When provided, make sure to put `:` before the port.
|
||||||
|
* - `[dbname]`: (required) the name of the database.
|
||||||
|
*
|
||||||
|
* You can learn more about the connection URL format in [PostgreSQL’s documentation](https://www.postgresql.org/docs/current/libpq-connect.html).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* For example, set the following database URL in your environment variables:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* DATABASE_URL=postgres://postgres@localhost/medusa-store
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Then, use the value in `medusa-config.js`:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* databaseUrl: process.env.DATABASE_URL,
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
databaseUrl?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database schema to connect to. This is not required to provide if you’re using the default schema, which is `public`.
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* databaseSchema: process.env.DATABASE_SCHEMA ||
|
||||||
|
* "custom",
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
databaseSchema?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This configuration specifies what database messages to log. Its value can be one of the following:
|
||||||
|
*
|
||||||
|
* - (default) A boolean value that indicates whether any messages should be logged.
|
||||||
|
* - The string value `all` that indicates all types of messages should be logged.
|
||||||
|
* - An array of log-level strings to indicate which type of messages to show in the logs. The strings can be `query`, `schema`, `error`, `warn`, `info`, `log`, or `migration`. Refer to [Typeorm’s documentation](https://typeorm.io/logging#logging-options) for more details on what each of these values means.
|
||||||
|
*
|
||||||
|
* If this configuration isn't set, its default value is `false`, meaning no database messages are logged.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* databaseLogging: boolean
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
databaseLogging?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @deprecated
|
||||||
|
*
|
||||||
|
* @privateRemarks
|
||||||
|
* only postgres is supported, so this config has no effect
|
||||||
|
*/
|
||||||
|
databaseType?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that includes additional configurations to pass to the database connection for v2. You can pass any configuration. One defined configuration to pass is
|
||||||
|
* `ssl` which enables support for TLS/SSL connections.
|
||||||
|
*
|
||||||
|
* This is useful for production databases, which can be supported by setting the `rejectUnauthorized` attribute of `ssl` object to `false`.
|
||||||
|
* During development, it’s recommended not to pass this option.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* databaseDriverOptions: process.env.NODE_ENV !== "development" ?
|
||||||
|
* { ssl: { rejectUnauthorized: false } } : {}
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
databaseDriverOptions?: Record<string, unknown> & {
|
||||||
|
connection?: {
|
||||||
|
/**
|
||||||
|
* Configure support for TLS/SSL connection
|
||||||
|
*/
|
||||||
|
ssl?: {
|
||||||
|
/**
|
||||||
|
* Whether to fail connection if the server certificate is verified against the list of supplied CAs and the hostname and no match is found.
|
||||||
|
*/
|
||||||
|
rejectUnauthorized?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to specify the URL to connect to Redis. This is only used for scheduled jobs. If you omit this configuration, scheduled jobs won't work.
|
||||||
|
*
|
||||||
|
* :::note
|
||||||
|
*
|
||||||
|
* You must first have Redis installed. You can refer to [Redis's installation guide](https://redis.io/docs/getting-started/installation/).
|
||||||
|
*
|
||||||
|
* :::
|
||||||
|
*
|
||||||
|
* The Redis connection URL has the following format:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* redis[s]://[[username][:password]@][host][:port][/db-number]
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* For a local Redis installation, the connection URL should be `redis://localhost:6379` unless you’ve made any changes to the Redis configuration during installation.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* redisUrl: process.env.REDIS_URL ||
|
||||||
|
* "redis://localhost:6379",
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
redisUrl?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The prefix set on all keys stored in Redis. The default value is `sess:`.
|
||||||
|
*
|
||||||
|
* If this configuration option is provided, it is prepended to `sess:`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* redisPrefix: process.env.REDIS_URL || "medusa:",
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
redisPrefix?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object of options to pass ioredis. You can refer to [ioredis’s RedisOptions documentation](https://redis.github.io/ioredis/index.html#RedisOptions)
|
||||||
|
* for the list of available options.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* redisOptions: {
|
||||||
|
* connectionName: process.env.REDIS_CONNECTION_NAME ||
|
||||||
|
* "medusa",
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
redisOptions?: RedisOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object of options to pass to [express-session](https://www.npmjs.com/package/express-session).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* sessionOptions: {
|
||||||
|
* name: process.env.SESSION_NAME || "custom",
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
sessionOptions?: SessionOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure HTTP compression from the application layer. If you have access to the HTTP server, the recommended approach would be to enable it there.
|
||||||
|
* However, some platforms don't offer access to the HTTP layer and in those cases, this is a good alternative.
|
||||||
|
*
|
||||||
|
* If you enable HTTP compression and you want to disable it for specific API Routes, you can pass in the request header `"x-no-compression": true`.
|
||||||
|
*
|
||||||
|
* @ignore
|
||||||
|
*
|
||||||
|
* @deprecated use {@link http }'s `compression` property instead.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
httpCompression?: HttpCompressionOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the number of staged jobs that are polled from the database. Default is `1000`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* jobsBatchSize: 100
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
jobsBatchSize?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the application's worker mode. Default is `shared`.
|
||||||
|
*
|
||||||
|
* - Use `shared` to run the application in a single process.
|
||||||
|
* - Use `worker` to run the a worker process only.
|
||||||
|
* - Use `server` to run the application server only.
|
||||||
|
*
|
||||||
|
* Learn more in [this guide](https://docs.medusajs.com/development/medusa-worker).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* workerMode: "shared"
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
workerMode?: "shared" | "worker" | "server"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the application's http-specific settings
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* cookieSecret: "supersecret",
|
||||||
|
* compression: {
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
http: {
|
||||||
|
/**
|
||||||
|
* A random string used to create authentication tokens in the http layer. Although this configuration option is not required, it’s highly recommended to set it for better security.
|
||||||
|
*
|
||||||
|
* In a development environment, if this option is not set the default secret is `supersecret` However, in production, if this configuration is not set an error, an
|
||||||
|
* error is thrown and the backend crashes.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* jwtSecret: "supersecret",
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
jwtSecret?: string
|
||||||
|
/**
|
||||||
|
* The expiration time for the JWT token. If not provided, the default value is `24h`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* jwtExpiresIn: "2d"
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
jwtExpiresIn?: string
|
||||||
|
/**
|
||||||
|
* A random string used to create cookie tokens in the http layer. Although this configuration option is not required, it’s highly recommended to set it for better security.
|
||||||
|
*
|
||||||
|
* In a development environment, if this option is not set, the default secret is `supersecret` However, in production, if this configuration is not set, an error is thrown and
|
||||||
|
* the backend crashes.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* cookieSecret: "supersecret"
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
cookieSecret?: string
|
||||||
|
/**
|
||||||
|
* The Medusa backend’s API Routes are protected by Cross-Origin Resource Sharing (CORS). So, only allowed URLs or URLs matching a specified pattern can send requests to the backend’s API Routes.
|
||||||
|
*
|
||||||
|
* `cors` is a string used to specify the accepted URLs or patterns for API Routes starting with `/auth`. It can either be one accepted origin, or a comma-separated list of accepted origins.
|
||||||
|
*
|
||||||
|
* Every origin in that list must either be:
|
||||||
|
*
|
||||||
|
* 1. A URL. For example, `http://localhost:7001`. The URL must not end with a backslash;
|
||||||
|
* 2. Or a regular expression pattern that can match more than one origin. For example, `.example.com`. The regex pattern that the backend tests for is `^([\/~@;%#'])(.*?)\1([gimsuy]*)$`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* Some example values of common use cases:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* # Allow different ports locally starting with 700
|
||||||
|
* AUTH_CORS=/http:\/\/localhost:700\d+$/
|
||||||
|
*
|
||||||
|
* # Allow any origin ending with vercel.app. For example, admin.vercel.app
|
||||||
|
* AUTH_CORS=/vercel\.app$/
|
||||||
|
*
|
||||||
|
* # Allow all HTTP requests
|
||||||
|
* AUTH_CORS=/http:\/\/.+/
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Then, set the configuration in `medusa-config.js`:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* authCors: process.env.AUTH_CORS
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If you’re adding the value directly within `medusa-config.js`, make sure to add an extra escaping `/` for every backslash in the pattern. For example:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* authCors: "/http:\\/\\/localhost:700\\d+$/",
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
authCors: string
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Configure HTTP compression from the application layer. If you have access to the HTTP server, the recommended approach would be to enable it there.
|
||||||
|
* However, some platforms don't offer access to the HTTP layer and in those cases, this is a good alternative.
|
||||||
|
*
|
||||||
|
* Its value is an object that has the following properties:
|
||||||
|
*
|
||||||
|
* If you enable HTTP compression and you want to disable it for specific API Routes, you can pass in the request header `"x-no-compression": true`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* compression: {
|
||||||
|
* enabled: true,
|
||||||
|
* level: 6,
|
||||||
|
* memLevel: 8,
|
||||||
|
* threshold: 1024
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
compression?: HttpCompressionOptions
|
||||||
|
/**
|
||||||
|
* The Medusa backend’s API Routes are protected by Cross-Origin Resource Sharing (CORS). So, only allowed URLs or URLs matching a specified pattern can send requests to the backend’s API Routes.
|
||||||
|
*
|
||||||
|
* `store_cors` is a string used to specify the accepted URLs or patterns for store API Routes. It can either be one accepted origin, or a comma-separated list of accepted origins.
|
||||||
|
*
|
||||||
|
* Every origin in that list must either be:
|
||||||
|
*
|
||||||
|
* 1. A URL. For example, `http://localhost:8000`. The URL must not end with a backslash;
|
||||||
|
* 2. Or a regular expression pattern that can match more than one origin. For example, `.example.com`. The regex pattern that the backend tests for is `^([\/~@;%#'])(.*?)\1([gimsuy]*)$`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* Some example values of common use cases:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* # Allow different ports locally starting with 800
|
||||||
|
* STORE_CORS=/http:\/\/localhost:800\d+$/
|
||||||
|
*
|
||||||
|
* # Allow any origin ending with vercel.app. For example, storefront.vercel.app
|
||||||
|
* STORE_CORS=/vercel\.app$/
|
||||||
|
*
|
||||||
|
* # Allow all HTTP requests
|
||||||
|
* STORE_CORS=/http:\/\/.+/
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Then, set the configuration in `medusa-config.js`:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* storeCors: process.env.STORE_CORS,
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If you’re adding the value directly within `medusa-config.js`, make sure to add an extra escaping `/` for every backslash in the pattern. For example:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* storeCors: "/vercel\\.app$/",
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
storeCors: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Medusa backend’s API Routes are protected by Cross-Origin Resource Sharing (CORS). So, only allowed URLs or URLs matching a specified pattern can send requests to the backend’s API Routes.
|
||||||
|
*
|
||||||
|
* `admin_cors` is a string used to specify the accepted URLs or patterns for admin API Routes. It can either be one accepted origin, or a comma-separated list of accepted origins.
|
||||||
|
*
|
||||||
|
* Every origin in that list must either be:
|
||||||
|
*
|
||||||
|
* 1. A URL. For example, `http://localhost:7001`. The URL must not end with a backslash;
|
||||||
|
* 2. Or a regular expression pattern that can match more than one origin. For example, `.example.com`. The regex pattern that the backend tests for is `^([\/~@;%#'])(.*?)\1([gimsuy]*)$`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* Some example values of common use cases:
|
||||||
|
*
|
||||||
|
* ```bash
|
||||||
|
* # Allow different ports locally starting with 700
|
||||||
|
* ADMIN_CORS=/http:\/\/localhost:700\d+$/
|
||||||
|
*
|
||||||
|
* # Allow any origin ending with vercel.app. For example, admin.vercel.app
|
||||||
|
* ADMIN_CORS=/vercel\.app$/
|
||||||
|
*
|
||||||
|
* # Allow all HTTP requests
|
||||||
|
* ADMIN_CORS=/http:\/\/.+/
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Then, set the configuration in `medusa-config.js`:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* adminCors: process.env.ADMIN_CORS,
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If you’re adding the value directly within `medusa-config.js`, make sure to add an extra escaping `/` for every backslash in the pattern. For example:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* adminCors: "/vercel\\.app$/",
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
adminCors: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally you can specify the supported authentication providers per actor type (such as user, customer, or any custom actors).
|
||||||
|
* For example, you only want to allow SSO logins for `users` to the admin, while you want to allow email/password logins for `customers` to the storefront.
|
||||||
|
*
|
||||||
|
* `authMethodsPerActor` is a a map where the actor type (eg. 'user') is the key, and an array of supported auth providers as the value.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* Some example values of common use cases:
|
||||||
|
*
|
||||||
|
* Then, set the configuration in `medusa-config.js`:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* http: {
|
||||||
|
* authMethodsPerActor: {
|
||||||
|
* user: ["email"],
|
||||||
|
* customer: ["emailpas", "google"]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
authMethodsPerActor?: Record<string, string[]>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
*
|
||||||
|
* The configurations for your Medusa backend are in `medusa-config.js` located in the root of your Medusa project. The configurations include database, modules, and plugin configurations, among other configurations.
|
||||||
|
*
|
||||||
|
* `medusa-config.js` exports an object having the following properties:
|
||||||
|
*
|
||||||
|
* - {@link ConfigModule.projectConfig | projectConfig} (required): An object that holds general configurations related to the Medusa backend, such as database or CORS configurations.
|
||||||
|
* - {@link ConfigModule.admin | admin}: An object that holds admin-related configurations.
|
||||||
|
* - {@link ConfigModule.plugins | plugins}: An array of plugin configurations that defines what plugins are installed and optionally specifies each of their configurations.
|
||||||
|
* - {@link ConfigModule.modules | modules}: An object that defines what modules are installed and optionally specifies each of their configurations.
|
||||||
|
* - {@link ConfigModule.featureFlags | featureFlags}: An object that enables or disables features guarded by a feature flag.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* projectConfig: {
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* admin: {
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* modules: {
|
||||||
|
* // ...
|
||||||
|
* },
|
||||||
|
* featureFlags: {
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* ## Environment Variables
|
||||||
|
*
|
||||||
|
* It's highly recommended to store the values of configurations in environment variables, then reference them within `medusa-config.js`.
|
||||||
|
*
|
||||||
|
* During development, you can set your environment variables in the `.env` file at the root of your Medusa backend project. In production,
|
||||||
|
* setting the environment variables depends on the hosting provider.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*/
|
||||||
|
export type ConfigModule = {
|
||||||
|
/**
|
||||||
|
* This property holds essential configurations related to the Medusa backend, such as database and CORS configurations.
|
||||||
|
*/
|
||||||
|
projectConfig: ProjectConfigOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin dashboard configurations.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* admin: {
|
||||||
|
* backendUrl: process.env.MEDUSA_BACKEND_URL ||
|
||||||
|
* "http://localhost:9000"
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
admin?: AdminOptions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On your Medusa backend, you can use [Plugins](https://docs.medusajs.com/development/plugins/overview) to add custom features or integrate third-party services.
|
||||||
|
* For example, installing a plugin to use Stripe as a payment processor.
|
||||||
|
*
|
||||||
|
* Aside from installing the plugin with NPM, you need to pass the plugin you installed into the `plugins` array defined in `medusa-config.js`.
|
||||||
|
*
|
||||||
|
* The items in the array can either be:
|
||||||
|
*
|
||||||
|
* - A string, which is the name of the plugin to add. You can pass a plugin as a string if it doesn’t require any configurations.
|
||||||
|
* - An object having the following properties:
|
||||||
|
* - `resolve`: The name of the plugin.
|
||||||
|
* - `options`: An object that includes the plugin’s options. These options vary for each plugin, and you should refer to the plugin’s documentation for available options.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = {
|
||||||
|
* plugins: [
|
||||||
|
* `medusa-my-plugin-1`,
|
||||||
|
* {
|
||||||
|
* resolve: `medusa-my-plugin`,
|
||||||
|
* options: {
|
||||||
|
* apiKey: process.env.MY_API_KEY ||
|
||||||
|
* `test`,
|
||||||
|
* },
|
||||||
|
* },
|
||||||
|
* // ...
|
||||||
|
* ],
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @ignore
|
||||||
|
*
|
||||||
|
* @privateRemarks
|
||||||
|
* Added the `@\ignore` tag for now so it's not generated in the main docs until we figure out what to do with plugins
|
||||||
|
*/
|
||||||
|
plugins: (
|
||||||
|
| {
|
||||||
|
resolve: string
|
||||||
|
options: Record<string, unknown>
|
||||||
|
}
|
||||||
|
| string
|
||||||
|
)[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Medusa, commerce and core logic are modularized to allow developers to extend or replace certain [modules](https://docs.medusajs.com/development/modules/overview)
|
||||||
|
* with custom implementations.
|
||||||
|
*
|
||||||
|
* Aside from installing the module with NPM, you must add it to the exported object in `medusa-config.js`.
|
||||||
|
*
|
||||||
|
* The keys of the `modules` configuration object refer to the module's registration name. Its value can be one of the following:
|
||||||
|
*
|
||||||
|
* 1. A boolean value indicating whether the module type is enabled. This is only supported for Medusa's commerce and architectural modules;
|
||||||
|
* 2. Or an object having the following properties:
|
||||||
|
* 1. `resolve`: a string indicating the path to the module relative to `src`, or the module's NPM package name.
|
||||||
|
* 2. `options`: (optional) an object indicating the options to pass to the module.
|
||||||
|
* 3. `definition`: (optional) an object of extra configurations, such as `isQueryable` used when a module has relationships.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* modules: {
|
||||||
|
* helloModuleService: {
|
||||||
|
* resolve: "./modules/hello"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
modules?: Record<
|
||||||
|
string,
|
||||||
|
boolean | Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some features in the Medusa backend are guarded by a feature flag. This ensures constant shipping of new features while maintaining the engine’s stability.
|
||||||
|
*
|
||||||
|
* You can specify whether a feature should or shouldn’t be used in your backend by enabling its feature flag. Feature flags can be enabled through either environment
|
||||||
|
* variables or through this configuration exported in `medusa-config.js`.
|
||||||
|
*
|
||||||
|
* The `featureFlags` configuration is an object. Its properties are the names of the feature flags. Each property’s value is a boolean indicating whether the feature flag is enabled.
|
||||||
|
*
|
||||||
|
* You can find available feature flags and their key name [here](https://github.com/medusajs/medusa/tree/develop/packages/medusa/src/loaders/feature-flags).
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js title="medusa-config.js"
|
||||||
|
* module.exports = defineConfig({
|
||||||
|
* featureFlags: {
|
||||||
|
* product_categories: true,
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* :::note
|
||||||
|
*
|
||||||
|
* After enabling a feature flag, make sure to run migrations as it may require making changes to the database.
|
||||||
|
*
|
||||||
|
* :::
|
||||||
|
*/
|
||||||
|
featureFlags: Record<string, boolean | string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PluginDetails = {
|
||||||
|
resolve: string
|
||||||
|
name: string
|
||||||
|
id: string
|
||||||
|
options: Record<string, unknown>
|
||||||
|
version: string
|
||||||
|
}
|
||||||
2
packages/framework/framework/src/index.ts
Normal file
2
packages/framework/framework/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./config"
|
||||||
|
export * from "./logger"
|
||||||
3
packages/framework/framework/src/logger/index.ts
Normal file
3
packages/framework/framework/src/logger/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import logger from "@medusajs/medusa-cli/dist/reporter"
|
||||||
|
|
||||||
|
export { logger }
|
||||||
11
packages/framework/framework/tsconfig.build.json
Normal file
11
packages/framework/framework/tsconfig.build.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig",
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"./src/**/__tests__",
|
||||||
|
"./src/**/__mocks__",
|
||||||
|
"./src/**/__fixtures__",
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
}
|
||||||
32
packages/framework/framework/tsconfig.json
Normal file
32
packages/framework/framework/tsconfig.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["ESNext"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"sourceMap": false,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"paths": {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
||||||
8
packages/framework/framework/tsconfig.spec.json
Normal file
8
packages/framework/framework/tsconfig.spec.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": ["src", "integration-tests"],
|
||||||
|
"exclude": ["node_modules", "dist"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"sourceMap": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
"@inquirer/checkbox": "^2.3.11",
|
"@inquirer/checkbox": "^2.3.11",
|
||||||
"@medusajs/admin-sdk": "0.0.1",
|
"@medusajs/admin-sdk": "0.0.1",
|
||||||
"@medusajs/core-flows": "^0.0.9",
|
"@medusajs/core-flows": "^0.0.9",
|
||||||
|
"@medusajs/framework": "workspace:^",
|
||||||
"@medusajs/link-modules": "^0.2.11",
|
"@medusajs/link-modules": "^0.2.11",
|
||||||
"@medusajs/medusa-cli": "^1.3.22",
|
"@medusajs/medusa-cli": "^1.3.22",
|
||||||
"@medusajs/modules-sdk": "^1.12.11",
|
"@medusajs/modules-sdk": "^1.12.11",
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
import { ConfigModule } from "@medusajs/types"
|
|
||||||
import { getConfigFile, isDefined } from "@medusajs/utils"
|
|
||||||
import logger from "./logger"
|
|
||||||
|
|
||||||
const isProduction = ["production", "prod"].includes(process.env.NODE_ENV || "")
|
|
||||||
|
|
||||||
const errorHandler = isProduction
|
|
||||||
? (msg: string): never => {
|
|
||||||
throw new Error(msg)
|
|
||||||
}
|
|
||||||
: console.log
|
|
||||||
|
|
||||||
export const handleConfigError = (error: Error): void => {
|
|
||||||
logger.error(`Error in loading config: ${error.message}`)
|
|
||||||
if (error.stack) {
|
|
||||||
logger.error(error.stack)
|
|
||||||
}
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildHttpConfig = (projectConfig: ConfigModule["projectConfig"]) => {
|
|
||||||
const http = projectConfig.http ?? {}
|
|
||||||
|
|
||||||
http.jwtExpiresIn = http?.jwtExpiresIn ?? "1d"
|
|
||||||
http.authCors = http.authCors ?? ""
|
|
||||||
http.storeCors = http.storeCors ?? ""
|
|
||||||
http.adminCors = http.adminCors ?? ""
|
|
||||||
|
|
||||||
http.jwtSecret = http?.jwtSecret ?? process.env.JWT_SECRET
|
|
||||||
|
|
||||||
if (!http.jwtSecret) {
|
|
||||||
errorHandler(
|
|
||||||
`[medusa-config] ⚠️ http.jwtSecret not found.${
|
|
||||||
isProduction ? "" : "Using default 'supersecret'."
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
|
|
||||||
http.jwtSecret = "supersecret"
|
|
||||||
}
|
|
||||||
|
|
||||||
http.cookieSecret =
|
|
||||||
projectConfig.http?.cookieSecret ?? process.env.COOKIE_SECRET
|
|
||||||
|
|
||||||
if (!http.cookieSecret) {
|
|
||||||
errorHandler(
|
|
||||||
`[medusa-config] ⚠️ http.cookieSecret not found.${
|
|
||||||
isProduction ? "" : " Using default 'supersecret'."
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
|
|
||||||
http.cookieSecret = "supersecret"
|
|
||||||
}
|
|
||||||
|
|
||||||
return http
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizeProjectConfig = (
|
|
||||||
projectConfig: ConfigModule["projectConfig"]
|
|
||||||
) => {
|
|
||||||
if (!projectConfig?.redisUrl) {
|
|
||||||
console.log(
|
|
||||||
`[medusa-config] ⚠️ redisUrl not found. A fake redis instance will be used.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
projectConfig.http = buildHttpConfig(projectConfig)
|
|
||||||
|
|
||||||
let workedMode = projectConfig?.workerMode
|
|
||||||
|
|
||||||
if (!isDefined(workedMode)) {
|
|
||||||
const env = process.env.MEDUSA_WORKER_MODE
|
|
||||||
if (isDefined(env)) {
|
|
||||||
if (env === "shared" || env === "worker" || env === "server") {
|
|
||||||
workedMode = env
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
workedMode = "shared"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...projectConfig,
|
|
||||||
workerMode: workedMode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (rootDirectory: string): ConfigModule => {
|
|
||||||
const { configModule, error } = getConfigFile<ConfigModule>(
|
|
||||||
rootDirectory,
|
|
||||||
`medusa-config`
|
|
||||||
)
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
handleConfigError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
const projectConfig = normalizeProjectConfig(configModule.projectConfig)
|
|
||||||
|
|
||||||
return {
|
|
||||||
projectConfig,
|
|
||||||
admin: configModule?.admin ?? {},
|
|
||||||
modules: configModule.modules ?? {},
|
|
||||||
featureFlags: configModule?.featureFlags ?? {},
|
|
||||||
plugins: configModule?.plugins ?? [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,7 @@ import requestIp from "request-ip"
|
|||||||
import { v4 } from "uuid"
|
import { v4 } from "uuid"
|
||||||
import adminLoader from "./admin"
|
import adminLoader from "./admin"
|
||||||
import apiLoader from "./api"
|
import apiLoader from "./api"
|
||||||
import loadConfig from "./config"
|
import { configLoader, logger } from "@medusajs/framework"
|
||||||
import expressLoader from "./express"
|
import expressLoader from "./express"
|
||||||
import featureFlagsLoader from "./feature-flags"
|
import featureFlagsLoader from "./feature-flags"
|
||||||
import { registerJobs } from "./helpers/register-jobs"
|
import { registerJobs } from "./helpers/register-jobs"
|
||||||
@@ -20,7 +20,6 @@ import { registerWorkflows } from "./helpers/register-workflows"
|
|||||||
import { getResolvedPlugins } from "./helpers/resolve-plugins"
|
import { getResolvedPlugins } from "./helpers/resolve-plugins"
|
||||||
import { resolvePluginsLinks } from "./helpers/resolve-plugins-links"
|
import { resolvePluginsLinks } from "./helpers/resolve-plugins-links"
|
||||||
import { SubscriberLoader } from "./helpers/subscribers"
|
import { SubscriberLoader } from "./helpers/subscribers"
|
||||||
import Logger from "./logger"
|
|
||||||
import loadMedusaApp from "./medusa-app"
|
import loadMedusaApp from "./medusa-app"
|
||||||
import registerPgConnection from "./pg-connection"
|
import registerPgConnection from "./pg-connection"
|
||||||
|
|
||||||
@@ -124,11 +123,11 @@ async function loadEntrypoints(
|
|||||||
|
|
||||||
export async function initializeContainer(rootDirectory: string) {
|
export async function initializeContainer(rootDirectory: string) {
|
||||||
const container = createMedusaContainer()
|
const container = createMedusaContainer()
|
||||||
const configModule = loadConfig(rootDirectory)
|
const configModule = configLoader(rootDirectory, "medusa-config.js")
|
||||||
const featureFlagRouter = featureFlagsLoader(configModule, Logger)
|
const featureFlagRouter = featureFlagsLoader(configModule, logger)
|
||||||
|
|
||||||
container.register({
|
container.register({
|
||||||
[ContainerRegistrationKeys.LOGGER]: asValue(Logger),
|
[ContainerRegistrationKeys.LOGGER]: asValue(logger),
|
||||||
[ContainerRegistrationKeys.FEATURE_FLAG_ROUTER]: asValue(featureFlagRouter),
|
[ContainerRegistrationKeys.FEATURE_FLAG_ROUTER]: asValue(featureFlagRouter),
|
||||||
[ContainerRegistrationKeys.CONFIG_MODULE]: asValue(configModule),
|
[ContainerRegistrationKeys.CONFIG_MODULE]: asValue(configModule),
|
||||||
[ContainerRegistrationKeys.REMOTE_QUERY]: asValue(null),
|
[ContainerRegistrationKeys.REMOTE_QUERY]: asValue(null),
|
||||||
|
|||||||
23
yarn.lock
23
yarn.lock
@@ -4604,6 +4604,23 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@medusajs/framework@workspace:^, @medusajs/framework@workspace:packages/framework/framework":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@medusajs/framework@workspace:packages/framework/framework"
|
||||||
|
dependencies:
|
||||||
|
"@medusajs/medusa-cli": "workspace:^"
|
||||||
|
"@medusajs/types": "workspace:^"
|
||||||
|
"@medusajs/utils": "workspace:^"
|
||||||
|
awilix: ^8.0.0
|
||||||
|
cross-env: ^7.0.3
|
||||||
|
ioredis: ^5.2.5
|
||||||
|
rimraf: ^3.0.2
|
||||||
|
tsc-alias: ^1.8.6
|
||||||
|
typescript: ^5.1.6
|
||||||
|
vite: ^5.2.11
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@medusajs/fulfillment-manual@workspace:*, @medusajs/fulfillment-manual@workspace:^, @medusajs/fulfillment-manual@workspace:packages/modules/providers/fulfillment-manual":
|
"@medusajs/fulfillment-manual@workspace:*, @medusajs/fulfillment-manual@workspace:^, @medusajs/fulfillment-manual@workspace:packages/modules/providers/fulfillment-manual":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@medusajs/fulfillment-manual@workspace:packages/modules/providers/fulfillment-manual"
|
resolution: "@medusajs/fulfillment-manual@workspace:packages/modules/providers/fulfillment-manual"
|
||||||
@@ -4743,7 +4760,7 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@medusajs/medusa-cli@^1.3.22, @medusajs/medusa-cli@workspace:packages/cli/medusa-cli":
|
"@medusajs/medusa-cli@^1.3.22, @medusajs/medusa-cli@workspace:^, @medusajs/medusa-cli@workspace:packages/cli/medusa-cli":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@medusajs/medusa-cli@workspace:packages/cli/medusa-cli"
|
resolution: "@medusajs/medusa-cli@workspace:packages/cli/medusa-cli"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4822,6 +4839,7 @@ __metadata:
|
|||||||
"@inquirer/checkbox": ^2.3.11
|
"@inquirer/checkbox": ^2.3.11
|
||||||
"@medusajs/admin-sdk": 0.0.1
|
"@medusajs/admin-sdk": 0.0.1
|
||||||
"@medusajs/core-flows": ^0.0.9
|
"@medusajs/core-flows": ^0.0.9
|
||||||
|
"@medusajs/framework": "workspace:^"
|
||||||
"@medusajs/link-modules": ^0.2.11
|
"@medusajs/link-modules": ^0.2.11
|
||||||
"@medusajs/medusa-cli": ^1.3.22
|
"@medusajs/medusa-cli": ^1.3.22
|
||||||
"@medusajs/modules-sdk": ^1.12.11
|
"@medusajs/modules-sdk": ^1.12.11
|
||||||
@@ -22694,6 +22712,7 @@ __metadata:
|
|||||||
rimraf: ^3.0.2
|
rimraf: ^3.0.2
|
||||||
typescript: ^5.1.6
|
typescript: ^5.1.6
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
"@medusajs/framework": "workspace:^"
|
||||||
"@medusajs/medusa": ">1.19"
|
"@medusajs/medusa": ">1.19"
|
||||||
"@medusajs/modules-sdk": ^1.12.10
|
"@medusajs/modules-sdk": ^1.12.10
|
||||||
axios: ^0.28.0
|
axios: ^0.28.0
|
||||||
@@ -22701,6 +22720,8 @@ __metadata:
|
|||||||
get-port: ^5.1.0
|
get-port: ^5.1.0
|
||||||
pg-god: ^1.0.12
|
pg-god: ^1.0.12
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
|
"@medusajs/framework":
|
||||||
|
optional: true
|
||||||
"@medusajs/medusa":
|
"@medusajs/medusa":
|
||||||
optional: true
|
optional: true
|
||||||
axios:
|
axios:
|
||||||
|
|||||||
Reference in New Issue
Block a user