breaking: move shared HTTP utils to the framework (#9402)

Fixes: FRMW-2728, FRMW-2729

After this PR gets merged the following middleware will be exported from the `@medusajs/framework/http` import path.

- applyParamsAsFilters
- clearFiltersByKey
- applyDefaultFilters
- setContext
- getQueryConfig
- httpCompression
- maybeApplyLinkFilter
- refetchEntities
- unlessPath
- validateBody
- validateQuery

Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
This commit is contained in:
Harminder Virk
2024-10-03 15:12:00 +05:30
committed by GitHub
parent 193f93464f
commit 48e00169d2
557 changed files with 2365 additions and 3499 deletions

View File

@@ -25,7 +25,10 @@ import {
installNextjsStarter,
startNextjsStarter,
} from "../utils/nextjs-utils.js"
import { getNodeVersion, MIN_SUPPORTED_NODE_VERSION } from "../utils/node-version.js"
import {
getNodeVersion,
MIN_SUPPORTED_NODE_VERSION,
} from "../utils/node-version.js"
const slugify = slugifyType.default

View File

@@ -1,6 +1,9 @@
import { EOL } from "os"
import pg from "pg"
import postgresClient, { DEFAULT_HOST, DEFAULT_PORT } from "./postgres-client.js"
import postgresClient, {
DEFAULT_HOST,
DEFAULT_PORT,
} from "./postgres-client.js"
import inquirer from "inquirer"
import logMessage from "./log-message.js"
import formatConnectionString from "./format-connection-string.js"
@@ -16,8 +19,13 @@ export default async function createDb({ client, db }: CreateDbOptions) {
await client.query(`CREATE DATABASE "${db}"`)
}
async function doesDbExist (client: pg.Client, dbName: string): Promise<boolean> {
const result = await client.query(`SELECT datname FROM pg_catalog.pg_database WHERE datname='${dbName}';`)
async function doesDbExist(
client: pg.Client,
dbName: string
): Promise<boolean> {
const result = await client.query(
`SELECT datname FROM pg_catalog.pg_database WHERE datname='${dbName}';`
)
return !!result.rowCount
}
@@ -75,14 +83,14 @@ async function getForDbName({
const defaultConnectionOptions = {
host: DEFAULT_HOST,
port: DEFAULT_PORT
port: DEFAULT_PORT,
}
try {
client = await postgresClient({
user: postgresUsername,
password: postgresPassword,
...defaultConnectionOptions
...defaultConnectionOptions,
})
} catch (e) {
if (verbose) {
@@ -129,7 +137,7 @@ async function getForDbName({
user: postgresUsername,
password: postgresPassword,
database: userDbName,
...defaultConnectionOptions
...defaultConnectionOptions,
})
} catch (e) {
logMessage({
@@ -148,7 +156,9 @@ async function getForDbName({
message: `A database already exists with the name ${dbName}, please enter a name for the database:`,
default: dbName,
validate: (input) => {
return typeof input === "string" && input.length > 0 && input !== dbName
return (
typeof input === "string" && input.length > 0 && input !== dbName
)
},
},
])
@@ -167,7 +177,7 @@ async function getForDbName({
return {
client,
dbConnectionString,
dbName
dbName,
}
}

View File

@@ -32,7 +32,7 @@ const facts = [
"The event bus module is responsible for triggering events and relaying them to subscribers.",
"The cache module is responsible for caching data that requires heavy computation.",
"A workflow is a series of steps that are defined once and executed anywhere. Workflows are created under the src/workflows directory.",
"A workflow's steps can be retried or rolled back in case of an error."
"A workflow's steps can be retried or rolled back in case of an error.",
]
export const getFact = () => {

View File

@@ -1,7 +1,7 @@
import inquirer from "inquirer"
import { exec } from "child_process"
import execute from "./execute.js"
import { FactBoxOptions, displayFactBox } from "./facts.js"
import { displayFactBox, FactBoxOptions } from "./facts.js"
import fs from "fs"
import path from "path"
import { customAlphabet } from "nanoid"
@@ -37,7 +37,7 @@ export async function installNextjsStarter({
abortController,
factBoxOptions,
verbose = false,
processManager
processManager,
}: InstallOptions): Promise<string> {
factBoxOptions.interval = displayFactBox({
...factBoxOptions,
@@ -72,7 +72,7 @@ export async function installNextjsStarter({
)
const execOptions = {
signal: abortController?.signal,
cwd: nextjsDirectory
cwd: nextjsDirectory,
}
await processManager.runProcess({
process: async () => {

View File

@@ -1,7 +1,7 @@
export function getNodeVersion(): number {
const [major] = process.versions.node.split('.').map(Number)
const [major] = process.versions.node.split(".").map(Number)
return major
}
export const MIN_SUPPORTED_NODE_VERSION = 20
export const MIN_SUPPORTED_NODE_VERSION = 20

View File

@@ -1,4 +1,5 @@
import pg from "pg"
const { Client } = pg
export const DEFAULT_HOST = "localhost"

View File

@@ -47,6 +47,7 @@
},
"dependencies": {
"@medusajs/utils": "1.11.9",
"@types/express": "^4.17.17",
"chalk": "^4.0.0",
"configstore": "5.0.1",
"dotenv": "^16.4.5",

View File

@@ -22,10 +22,7 @@ import reporter from "../reporter"
import { getPackageManager, setPackageManager } from "../util/package-manager"
import { PanicId } from "../reporter/panic-handler"
import { clearProject } from "../util/clear-project"
import {
getNodeVersion,
MIN_SUPPORTED_NODE_VERSION,
} from "@medusajs/utils"
import { getNodeVersion, MIN_SUPPORTED_NODE_VERSION } from "@medusajs/utils"
const removeUndefined = (obj) => {
return Object.fromEntries(

View File

@@ -1,19 +1,19 @@
const signalExit = require(`signal-exit`);
const signalExit = require(`signal-exit`)
const cleanupTasks = new Set();
const cleanupTasks = new Set()
exports.registerCleanupTask = (taskFn) => {
cleanupTasks.add(taskFn);
cleanupTasks.add(taskFn)
return () => {
const result = taskFn();
cleanupTasks.delete(taskFn);
return result;
};
};
const result = taskFn()
cleanupTasks.delete(taskFn)
return result
}
}
signalExit(() => {
if (cleanupTasks.size) {
console.log(`Process exitted in middle of publishing - cleaning up`);
cleanupTasks.forEach((taskFn) => taskFn());
console.log(`Process exitted in middle of publishing - cleaning up`)
cleanupTasks.forEach((taskFn) => taskFn())
}
});
})

View File

@@ -15,7 +15,7 @@ const getDependantPackages = ({
packagesToPublish.add(packageName)
const dependants = depTree[packageName]
if (dependants) {
dependants.forEach(dependant =>
dependants.forEach((dependant) =>
getDependantPackages({
packageName: dependant,
depTree,

View File

@@ -5,7 +5,7 @@ const defaultSpawnArgs = {
stdio: `inherit`,
}
exports.setDefaultSpawnStdio = stdio => {
exports.setDefaultSpawnStdio = (stdio) => {
defaultSpawnArgs.stdio = stdio
}

View File

@@ -1,4 +1,4 @@
exports.getVersionInfo = () => {
const { version: devCliVersion } = require(`../../package.json`);
return `Medusa Dev CLI version: ${devCliVersion}`;
};
const { version: devCliVersion } = require(`../../package.json`)
return `Medusa Dev CLI version: ${devCliVersion}`
}

View File

@@ -10,13 +10,23 @@ import execa from "execa"
/**
* OAS output directory
*
*
* @privateRemarks
* This should be the only directory OAS is loaded from for Medusa V2.
* For now, we only use it if the --v2 flag it passed to the CLI tool.
*/
const oasOutputPath = path.resolve(
__dirname, "..", "..", "..", "..", "..", "..", "www", "utils", "generated", "oas-output"
__dirname,
"..",
"..",
"..",
"..",
"..",
"..",
"www",
"utils",
"generated",
"oas-output"
)
const basePath = path.resolve(__dirname, `../../`)
@@ -128,7 +138,13 @@ describe("command oas", () => {
beforeAll(async () => {
const outDir = path.resolve(tmpDir, uid())
await runCLI("oas", ["--type", "combined", "--out-dir", outDir, "--local"])
await runCLI("oas", [
"--type",
"combined",
"--out-dir",
outDir,
"--local",
])
const generatedFilePath = path.resolve(outDir, "combined.oas.json")
oas = (await readJson(generatedFilePath)) as OpenAPIObject
})
@@ -227,7 +243,7 @@ describe("command oas", () => {
outDir,
"--paths",
additionalPath,
"--local"
"--local",
])
const generatedFilePath = path.resolve(outDir, "store.oas.json")
oas = (await readJson(generatedFilePath)) as OpenAPIObject
@@ -363,7 +379,7 @@ components:
outDir,
"--base",
filePath,
"--local"
"--local",
])
const generatedFilePath = path.resolve(outDir, "store.oas.json")
oas = (await readJson(generatedFilePath)) as OpenAPIObject
@@ -473,7 +489,7 @@ components:
const routes = Object.keys(oas.paths)
expect(routes.includes("/admin/products")).toBeTruthy()
expect(routes.includes("/store/products")).toBeFalsy()
})
})
})
describe("public OAS with base", () => {
@@ -579,7 +595,7 @@ components:
])
const generatedFilePath = path.resolve(outDir, "store.oas.json")
oas = (await readJson(generatedFilePath)) as OpenAPIObject
})
})
it("should add new path to existing paths", async () => {
const routes = Object.keys(oas.paths)

View File

@@ -1,4 +1,7 @@
import { PreviewDocsOptions, previewDocs } from "@redocly/cli/lib/commands/preview-docs"
import {
previewDocs,
PreviewDocsOptions,
} from "@redocly/cli/lib/commands/preview-docs"
import { commandWrapper } from "@redocly/cli/lib/wrapper"
import { Command, Option, OptionValues } from "commander"
import execa from "execa"
@@ -12,7 +15,12 @@ import {
} from "./utils/circular-patch-utils"
import { getTmpDirectory, isFile } from "./utils/fs-utils"
import { readJson } from "./utils/json-utils"
import { jsonObjectToYamlString, readYaml, writeYaml, writeYamlFromJson } from "./utils/yaml-utils"
import {
jsonObjectToYamlString,
readYaml,
writeYaml,
writeYamlFromJson,
} from "./utils/yaml-utils"
import yargs from "yargs"
/**
@@ -64,7 +72,7 @@ export const commandOptions: Option[] = [
new Option(
"--main-file-name <mainFileName>",
"The name of the main YAML file."
).default("openapi.yaml")
).default("openapi.yaml"),
]
export function getCommand(): Command {
@@ -140,7 +148,10 @@ export async function execute(cliParams: OptionValues): Promise<void> {
if (dryRun) {
console.log(`⚫️ Dry run - no files generated`)
// check out possible changes in redocly config
await execa("git", ["checkout", path.join(basePath, "redocly", "redocly-config.yaml")])
await execa("git", [
"checkout",
path.join(basePath, "redocly", "redocly-config.yaml"),
])
return
}
if (shouldPreview) {
@@ -150,7 +161,10 @@ export async function execute(cliParams: OptionValues): Promise<void> {
if (shouldSplit) {
await generateReference(srcFileSanitized, outDir)
} else {
await writeYaml(path.join(outDir, finalOASFile), await fs.readFile(srcFileSanitized, "utf8"))
await writeYaml(
path.join(outDir, finalOASFile),
await fs.readFile(srcFileSanitized, "utf8")
)
}
if (shouldBuildHTML) {
const outHTMLFile = path.resolve(outDir, "index.html")
@@ -236,17 +250,31 @@ const fixCirclularReferences = async (srcFile: string): Promise<void> => {
${hint}
###
`
const redoclyConfigPath = path.join(basePath, "redocly", "redocly-config.yaml")
const originalContent = await readYaml(redoclyConfigPath) as CircularReferenceConfig
const redoclyConfigPath = path.join(
basePath,
"redocly",
"redocly-config.yaml"
)
const originalContent = (await readYaml(
redoclyConfigPath
)) as CircularReferenceConfig
Object.keys(recommendation).forEach((recKey) => {
originalContent.decorators["medusa/circular-patch"].schemas[recKey] = [
...(originalContent.decorators["medusa/circular-patch"].schemas[recKey] || []),
...recommendation[recKey]
...(originalContent.decorators["medusa/circular-patch"].schemas[
recKey
] || []),
...recommendation[recKey],
]
})
await writeYaml(redoclyConfigPath, jsonObjectToYamlString(originalContent))
console.log(`🟡 Added the following unhandled circular references to redocly-config.ts:` + hintMessage)
await writeYaml(
redoclyConfigPath,
jsonObjectToYamlString(originalContent)
)
console.log(
`🟡 Added the following unhandled circular references to redocly-config.ts:` +
hintMessage
)
}
}
console.log(`🟢 All circular references are handled`)

View File

@@ -15,9 +15,7 @@ import { isFile } from "./utils/fs-utils"
* Constants
*/
// Medusa core package directory
const medusaPackagePath = path.dirname(
require.resolve("@medusajs/medusa")
)
const medusaPackagePath = path.dirname(require.resolve("@medusajs/medusa"))
const basePath = path.resolve(__dirname, "../")
/**
@@ -48,7 +46,7 @@ export const commandOptions: Option[] = [
new Option(
"--local",
"Generate OAS from local files rather than public OAS. This is useful for generating references in the Medusa monorepo."
)
),
]
export function getCommand() {
@@ -105,11 +103,17 @@ export async function execute(cliParams: OptionValues) {
console.log(`🟣 Generating OAS - ${apiType}`)
if (apiType === "combined") {
const adminOAS = !local ? await getPublicOas("admin") : await getOASFromCodebase("admin")
const storeOAS = !local ? await getPublicOas("store") : await getOASFromCodebase("store")
const adminOAS = !local
? await getPublicOas("admin")
: await getOASFromCodebase("admin")
const storeOAS = !local
? await getPublicOas("store")
: await getOASFromCodebase("store")
oas = await combineOAS(adminOAS, storeOAS)
} else {
oas = !local ? await getPublicOas(apiType) : await getOASFromCodebase(apiType)
oas = !local
? await getPublicOas(apiType)
: await getOASFromCodebase(apiType)
}
if (additionalPaths.length || baseFile) {
@@ -133,14 +137,21 @@ export async function execute(cliParams: OptionValues) {
/**
* Methods
*/
async function getOASFromCodebase(
apiType: ApiType
): Promise<OpenAPIObject> {
async function getOASFromCodebase(apiType: ApiType): Promise<OpenAPIObject> {
/**
* OAS output directory
*/
const oasOutputPath = path.resolve(
__dirname, "..", "..", "..", "..", "..", "www", "utils", "generated", "oas-output"
__dirname,
"..",
"..",
"..",
"..",
"..",
"www",
"utils",
"generated",
"oas-output"
)
const gen = await swaggerInline(
[
@@ -158,11 +169,9 @@ async function getOASFromCodebase(
return (await OpenAPIParser.parse(JSON.parse(gen))) as OpenAPIObject
}
async function getPublicOas(
apiType: ApiType,
) {
async function getPublicOas(apiType: ApiType) {
const url = `https://docs.medusajs.com/v2/api/api/download/${apiType}`
return await OpenAPIParser.parse(url) as OpenAPIObject
return (await OpenAPIParser.parse(url)) as OpenAPIObject
}
async function getOASFromPaths(

View File

@@ -8,4 +8,4 @@ type CircularReferenceConfig = {
schemas: CircularReferenceSchema
}
}
}
}

View File

@@ -1,6 +1,5 @@
import { access, lstat, mkdtemp } from "fs/promises"
import path from "path"
import { sep } from "path"
import path, { sep } from "path"
import { tmpdir } from "os"
export async function isFile(filePath: string): Promise<boolean> {

View File

@@ -6,11 +6,17 @@ export const readYaml = async (filePath): Promise<unknown> => {
return yaml.load(yamlString)
}
export const writeYaml = async (filePath: string, yamlContent: string): Promise<void> => {
export const writeYaml = async (
filePath: string,
yamlContent: string
): Promise<void> => {
await fs.writeFile(filePath, yamlContent, "utf8")
}
export const writeYamlFromJson = async (filePath, jsonObject): Promise<void> => {
export const writeYamlFromJson = async (
filePath,
jsonObject
): Promise<void> => {
const yamlString = yaml.dump(jsonObject)
await fs.writeFile(filePath, yamlString, "utf8")
}