Merge branch 'develop' into docs/quote-management-guide

This commit is contained in:
Shahed Nasser committed 2025-03-05 17:15:13 +02:00
commit 5bda9f6037
880 files changed
+491175 -480049

No files matched your search

-6
View File
@@ -1,6 +0,0 @@
---
"@medusajs/types": patch
"@medusajs/medusa": patch
---
fix(types, medusa): remove fulfillment and payment status filters from validator + http types
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/dashboard": patch
---
fix(dashboard): Use derrived state in DataTable
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/types": patch
---
chore(types): change payment provider types to interfaces
-6
View File
@@ -1,6 +0,0 @@
---
"@medusajs/types": patch
"@medusajs/medusa": patch
---
fix(types,medusa): calculate taxes for original price
-6
View File
@@ -1,6 +0,0 @@
---
"@medusajs/product": patch
"@medusajs/utils": patch
---
chore(product): Remove upsertWithReplace where needed
-7
View File
@@ -1,7 +0,0 @@
---
"@medusajs/medusa": patch
"@medusajs/core-flows": patch
"@medusajs/types": patch
---
fix: add additionl data to product categories hook
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/core-flows": patch
---
chore(core-flows): pass cart as reference to subflows
-7
View File
@@ -1,7 +0,0 @@
---
"@medusajs/cart": patch
"@medusajs/core-flows": patch
"@medusajs/types": patch
---
chore(): Improve cart update line items
-6
View File
@@ -1,6 +0,0 @@
---
"@medusajs/core-flows": patch
"@medusajs/cart": patch
---
chore(): Prevent workflow steps to even call modules when not necessary
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/framework": patch
---
feat: add middleware-file-loader
-6
View File
@@ -1,6 +0,0 @@
---
"@medusajs/framework": patch
"@medusajs/utils": patch
---
chore(): Add support for extra pool configuration
+7
View File
@@ -0,0 +1,7 @@
---
"@medusajs/product": patch
"@medusajs/framework": patch
"@medusajs/medusa": patch
---
chore(product): Improve product normalization
-9
View File
@@ -1,9 +0,0 @@
---
"@medusajs/cache-redis": patch
"@medusajs/event-bus-redis": patch
"@medusajs/workflow-engine-redis": patch
"@medusajs/locking-redis": patch
"@medusajs/workflows-sdk": patch
---
chore(): Prevent sub workflow events release early + redis unlink
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/types": patch
---
fix(types): Allow providing either vite@5 or vite@6 for the peer dependency
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/utils": patch
---
chore(): Improve cascade soft deletetion and update
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/link-modules": patch
---
Chore/link module serialization
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/core-flows": patch
---
fix(core-flows): support 0 as a valid unit price for custom line items
-9
View File
@@ -1,9 +0,0 @@
---
"@medusajs/inventory": patch
"@medusajs/link-modules": patch
"@medusajs/product": patch
"@medusajs/types": patch
"@medusajs/utils": patch
---
chore(): Improve internal repository delete algo
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/dashboard": patch
---
fix(dashboard): bust variant inventory cache on inventory update
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/core-flows": patch
---
chore(core-flows): reserve inventory from locations with availability
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/utils": patch
---
feat(utils): add error message when manager is not found
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/framework": patch
---
feat: add routes loader
-5
View File
@@ -1,5 +0,0 @@
---
"@medusajs/core-flows": patch
---
chore(core-flows): avoid overfetching to refresh cart
-7
View File
@@ -1,7 +0,0 @@
---
"@medusajs/dashboard": patch
"@medusajs/core-flows": patch
"@medusajs/medusa": patch
---
fix(core-flows, dashboard, medusa): prevent creatiion of a fulfilment without items
+28
View File
@@ -1,5 +1,33 @@
# integration-tests-http
## 1.0.9
### Patch Changes
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`d172ad8ebc4677bba73c36465c973f4784dc50ae`](https://github.com/medusajs/medusa/commit/d172ad8ebc4677bba73c36465c973f4784dc50ae), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`322d108c0395757b4655a1e0055d722acf127b36`](https://github.com/medusajs/medusa/commit/322d108c0395757b4655a1e0055d722acf127b36), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`caf83cf78cb6d2dbd1837f6814062dafecbd04fa`](https://github.com/medusajs/medusa/commit/caf83cf78cb6d2dbd1837f6814062dafecbd04fa), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`38beeb157eadcd7dabe814119c48b5ddbc17fe20`](https://github.com/medusajs/medusa/commit/38beeb157eadcd7dabe814119c48b5ddbc17fe20), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`03731c7660fe5dca3c6d3c38a2a71eb2ea89e192`](https://github.com/medusajs/medusa/commit/03731c7660fe5dca3c6d3c38a2a71eb2ea89e192), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031), [`cad8b40c130e371d615d3bd953bb466fb4ac54a8`](https://github.com/medusajs/medusa/commit/cad8b40c130e371d615d3bd953bb466fb4ac54a8), [`7dbec10b3bdde8a9f869080d5ef2c3c97fca1077`](https://github.com/medusajs/medusa/commit/7dbec10b3bdde8a9f869080d5ef2c3c97fca1077), [`fa1793e8e92164251c776859dea7a5e312ef9432`](https://github.com/medusajs/medusa/commit/fa1793e8e92164251c776859dea7a5e312ef9432), [`e23f204b7ca0f195e36fef2ba0bae7a686b8da4f`](https://github.com/medusajs/medusa/commit/e23f204b7ca0f195e36fef2ba0bae7a686b8da4f), [`aabbbb7292a59ec029a6165451aa6d949844b2ea`](https://github.com/medusajs/medusa/commit/aabbbb7292a59ec029a6165451aa6d949844b2ea)]:
- @medusajs/medusa@2.6.0
- @medusajs/product@2.6.0
- @medusajs/utils@2.6.0
- @medusajs/core-flows@2.6.0
- @medusajs/inventory@2.6.0
- @medusajs/modules-sdk@2.6.0
- @medusajs/test-utils@2.6.0
- @medusajs/api-key@2.6.0
- @medusajs/auth@2.6.0
- @medusajs/cache-inmemory@2.6.0
- @medusajs/customer@2.6.0
- @medusajs/event-bus-local@2.6.0
- @medusajs/fulfillment@2.6.0
- @medusajs/pricing@2.6.0
- @medusajs/promotion@2.6.0
- @medusajs/fulfillment-manual@2.6.0
- @medusajs/region@2.6.0
- @medusajs/stock-location@2.6.0
- @medusajs/store@2.6.0
- @medusajs/tax@2.6.0
- @medusajs/user@2.6.0
- @medusajs/workflow-engine-inmemory@2.6.0
## 1.0.8
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "integration-tests-http",
"version": "1.0.8",
"version": "1.0.9",
"main": "index.js",
"license": "MIT",
"private": true,
@@ -1,5 +1,14 @@
# @medusajs/admin-bundler
## 2.6.0
### Patch Changes
- Updated dependencies [[`c28ae573e50b51bd3ef18de7c0e37b37963c423e`](https://github.com/medusajs/medusa/commit/c28ae573e50b51bd3ef18de7c0e37b37963c423e), [`954136f13a4ff00c0fa66d8159f43b2bce90355a`](https://github.com/medusajs/medusa/commit/954136f13a4ff00c0fa66d8159f43b2bce90355a), [`e23f204b7ca0f195e36fef2ba0bae7a686b8da4f`](https://github.com/medusajs/medusa/commit/e23f204b7ca0f195e36fef2ba0bae7a686b8da4f)]:
- @medusajs/dashboard@2.6.0
- @medusajs/admin-shared@2.6.0
- @medusajs/admin-vite-plugin@2.6.0
## 2.5.1
### Patch Changes
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/admin-bundler",
"version": "2.5.1",
"version": "2.6.0",
"description": "Bundler for the Medusa admin dashboard.",
"author": "Kasper Kristensen <kasper@medusajs.com>",
"scripts": {
@@ -18,7 +18,7 @@
"package.json"
],
"devDependencies": {
"@medusajs/types": "^2.5.1",
"@medusajs/types": "^2.6.0",
"@types/compression": "^1.7.5",
"copyfiles": "^2.4.1",
"express": "^4.21.0",
@@ -26,9 +26,9 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@medusajs/admin-shared": "2.5.1",
"@medusajs/admin-vite-plugin": "2.5.1",
"@medusajs/dashboard": "2.5.1",
"@medusajs/admin-shared": "2.6.0",
"@medusajs/admin-vite-plugin": "2.6.0",
"@medusajs/dashboard": "2.6.0",
"@rollup/plugin-node-resolve": "^16.0.0",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
+7
View File
@@ -1,5 +1,12 @@
# @medusajs/admin-sdk
## 2.6.0
### Patch Changes
- Updated dependencies []:
- @medusajs/admin-shared@2.6.0
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@medusajs/admin-sdk",
"description": "SDK for building extension for the Medusa admin dashboard.",
"version": "2.5.1",
"version": "2.6.0",
"author": "Kasper Kristensen <kasper@medusajs.com>",
"types": "dist/index.d.ts",
"main": "dist/index.js",
@@ -24,7 +24,7 @@
"typescript": "^5.3.3"
},
"dependencies": {
"@medusajs/admin-shared": "^2.5.1",
"@medusajs/admin-shared": "^2.6.0",
"zod": "3.22.4"
},
"packageManager": "yarn@3.2.1"
+2
View File
@@ -1,5 +1,7 @@
# @medusajs/admin-shared
## 2.6.0
## 2.5.1
## 2.5.0
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@medusajs/admin-shared",
"description": "Shared code for Medusa admin packages.",
"version": "2.5.1",
"version": "2.6.0",
"author": "Kasper Kristensen <kasper@medusajs.com>",
"types": "dist/index.d.ts",
"main": "dist/index.js",
@@ -1,5 +1,12 @@
# @medusajs/admin-vite-plugin
## 2.6.0
### Patch Changes
- Updated dependencies []:
- @medusajs/admin-shared@2.6.0
## 2.5.1
### Patch Changes
@@ -1,6 +1,6 @@
{
"name": "@medusajs/admin-vite-plugin",
"version": "2.5.1",
"version": "2.6.0",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
@@ -40,7 +40,7 @@
"@babel/parser": "7.25.6",
"@babel/traverse": "7.25.6",
"@babel/types": "7.25.6",
"@medusajs/admin-shared": "2.5.1",
"@medusajs/admin-shared": "2.6.0",
"chokidar": "3.5.3",
"fdir": "6.1.1",
"magic-string": "0.30.5",
+15
View File
@@ -1,5 +1,20 @@
# @medusajs/dashboard
## 2.6.0
### Patch Changes
- [#11487](https://github.com/medusajs/medusa/pull/11487) [`c28ae573e50b51bd3ef18de7c0e37b37963c423e`](https://github.com/medusajs/medusa/commit/c28ae573e50b51bd3ef18de7c0e37b37963c423e) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(dashboard): Use derrived state in DataTable
- [#11690](https://github.com/medusajs/medusa/pull/11690) [`954136f13a4ff00c0fa66d8159f43b2bce90355a`](https://github.com/medusajs/medusa/commit/954136f13a4ff00c0fa66d8159f43b2bce90355a) Thanks [@riqwan](https://github.com/riqwan)! - fix(dashboard): bust variant inventory cache on inventory update
- [#11664](https://github.com/medusajs/medusa/pull/11664) [`e23f204b7ca0f195e36fef2ba0bae7a686b8da4f`](https://github.com/medusajs/medusa/commit/e23f204b7ca0f195e36fef2ba0bae7a686b8da4f) Thanks [@fPolic](https://github.com/fPolic)! - fix(core-flows, dashboard, medusa): prevent creatiion of a fulfilment without items
- Updated dependencies []:
- @medusajs/admin-shared@2.6.0
- @medusajs/js-sdk@2.6.0
- @medusajs/icons@2.6.0
## 2.5.1
### Patch Changes
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/dashboard",
"version": "2.5.1",
"version": "2.6.0",
"scripts": {
"generate:static": "node ./scripts/generate-currencies.js && prettier --write ./src/lib/currencies.ts",
"dev": "vite",
@@ -45,9 +45,9 @@
"@dnd-kit/sortable": "^8.0.0",
"@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "3.4.2",
"@medusajs/admin-shared": "^2.5.1",
"@medusajs/icons": "^2.5.1",
"@medusajs/js-sdk": "^2.5.1",
"@medusajs/admin-shared": "^2.6.0",
"@medusajs/icons": "^2.6.0",
"@medusajs/js-sdk": "^2.6.0",
"@medusajs/ui": "~4.0.6",
"@tanstack/react-query": "5.64.2",
"@tanstack/react-table": "8.20.5",
@@ -75,10 +75,10 @@
"zod": "3.22.4"
},
"devDependencies": {
"@medusajs/admin-shared": "^2.5.1",
"@medusajs/admin-vite-plugin": "^2.5.1",
"@medusajs/types": "^2.5.1",
"@medusajs/ui-preset": "^2.5.1",
"@medusajs/admin-shared": "^2.6.0",
"@medusajs/admin-vite-plugin": "^2.6.0",
"@medusajs/types": "^2.6.0",
"@medusajs/ui-preset": "^2.6.0",
"@types/node": "^20.11.15",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
@@ -1,5 +1,12 @@
# Change Log
## 2.6.0
### Patch Changes
- Updated dependencies []:
- @medusajs/telemetry@2.6.0
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "create-medusa-app",
"version": "2.5.1",
"version": "2.6.0",
"description": "Create a Medusa project using a single command.",
"type": "module",
"exports": "./dist/index.js",
@@ -13,7 +13,7 @@
"watch": "tsc --watch"
},
"dependencies": {
"@medusajs/telemetry": "^2.5.1",
"@medusajs/telemetry": "^2.6.0",
"boxen": "^5",
"chalk": "^5.2.0",
"commander": "^10.0.1",
+8
View File
@@ -1,5 +1,13 @@
# Change Log
## 2.6.0
### Patch Changes
- Updated dependencies [[`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031)]:
- @medusajs/utils@2.6.0
- @medusajs/telemetry@2.6.0
## 2.5.1
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/cli",
"version": "2.5.1",
"version": "2.6.0",
"description": "Command Line interface for Medusa Commerce",
"main": "dist/index.js",
"bin": {
@@ -46,8 +46,8 @@
"typescript": "^5.6.2"
},
"dependencies": {
"@medusajs/telemetry": "^2.5.1",
"@medusajs/utils": "2.5.1",
"@medusajs/telemetry": "^2.6.0",
"@medusajs/utils": "2.6.0",
"@types/express": "^4.17.17",
"chalk": "^4.0.0",
"configstore": "5.0.1",
+2
View File
@@ -1,5 +1,7 @@
# Change Log
## 2.6.0
## 2.5.1
## 2.5.0
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "medusa-dev-cli",
"description": "CLI helpers for contributors working on Medusa",
"version": "2.5.1",
"version": "2.6.0",
"author": "Sebastian Rindom <skrindom@gmail.com>",
"bin": {
"medusa-dev": "./dist/index.js"
@@ -1,5 +1,13 @@
# @medusajs/oas-cli
## 2.6.0
### Patch Changes
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`d172ad8ebc4677bba73c36465c973f4784dc50ae`](https://github.com/medusajs/medusa/commit/d172ad8ebc4677bba73c36465c973f4784dc50ae), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031), [`e23f204b7ca0f195e36fef2ba0bae7a686b8da4f`](https://github.com/medusajs/medusa/commit/e23f204b7ca0f195e36fef2ba0bae7a686b8da4f), [`aabbbb7292a59ec029a6165451aa6d949844b2ea`](https://github.com/medusajs/medusa/commit/aabbbb7292a59ec029a6165451aa6d949844b2ea)]:
- @medusajs/medusa@2.6.0
- @medusajs/utils@2.6.0
## 2.5.1
### Patch Changes
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/medusa-oas-cli",
"version": "2.5.1",
"version": "2.6.0",
"description": "OAS CLI",
"main": "dist/index.js",
"bin": {
@@ -21,7 +21,7 @@
"author": "Medusa",
"license": "MIT",
"devDependencies": {
"@medusajs/types": "^2.5.1",
"@medusajs/types": "^2.6.0",
"@types/js-yaml": "^4.0.9",
"jest": "^29.1.0",
"js-yaml": "^4.1.0",
@@ -35,8 +35,8 @@
"medusa-oas": "ts-node src/index.ts"
},
"dependencies": {
"@medusajs/medusa": "^2.5.1",
"@medusajs/utils": "^2.5.1",
"@medusajs/medusa": "^2.6.0",
"@medusajs/utils": "^2.6.0",
"@readme/json-schema-ref-parser": "^1.2.0",
"@readme/openapi-parser": "^2.4.0",
"@redocly/cli": "^1.7.0",
@@ -1,5 +1,12 @@
# @medusajs/oas-github-ci
## 2.6.0
### Patch Changes
- Updated dependencies []:
- @medusajs/medusa-oas-cli@2.6.0
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/oas-github-ci",
"version": "2.5.1",
"version": "2.6.0",
"description": "OAS Github CI",
"main": "scripts/build-openapi.js",
"files": [
@@ -21,7 +21,7 @@
"test": "jest --passWithNoTests"
},
"dependencies": {
"@medusajs/medusa-oas-cli": "2.5.1",
"@medusajs/medusa-oas-cli": "2.6.0",
"execa": "^5.1.1"
}
}
+22
View File
@@ -1,5 +1,27 @@
# @medusajs/core-flows
## 2.6.0
### Patch Changes
- [#11226](https://github.com/medusajs/medusa/pull/11226) [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9) Thanks [@bouazzaayyoub](https://github.com/bouazzaayyoub)! - fix: add additionl data to product categories hook
- [#11617](https://github.com/medusajs/medusa/pull/11617) [`322d108c0395757b4655a1e0055d722acf127b36`](https://github.com/medusajs/medusa/commit/322d108c0395757b4655a1e0055d722acf127b36) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - chore(core-flows): pass cart as reference to subflows
- [#11666](https://github.com/medusajs/medusa/pull/11666) [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Improve cart update line items
- [#11632](https://github.com/medusajs/medusa/pull/11632) [`caf83cf78cb6d2dbd1837f6814062dafecbd04fa`](https://github.com/medusajs/medusa/commit/caf83cf78cb6d2dbd1837f6814062dafecbd04fa) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Prevent workflow steps to even call modules when not necessary
- [#11631](https://github.com/medusajs/medusa/pull/11631) [`38beeb157eadcd7dabe814119c48b5ddbc17fe20`](https://github.com/medusajs/medusa/commit/38beeb157eadcd7dabe814119c48b5ddbc17fe20) Thanks [@riqwan](https://github.com/riqwan)! - fix(core-flows): support 0 as a valid unit price for custom line items
- [#11538](https://github.com/medusajs/medusa/pull/11538) [`03731c7660fe5dca3c6d3c38a2a71eb2ea89e192`](https://github.com/medusajs/medusa/commit/03731c7660fe5dca3c6d3c38a2a71eb2ea89e192) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - chore(core-flows): reserve inventory from locations with availability
- [#11712](https://github.com/medusajs/medusa/pull/11712) [`7dbec10b3bdde8a9f869080d5ef2c3c97fca1077`](https://github.com/medusajs/medusa/commit/7dbec10b3bdde8a9f869080d5ef2c3c97fca1077) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - fix(order): summary raw totals
- [#11602](https://github.com/medusajs/medusa/pull/11602) [`fa1793e8e92164251c776859dea7a5e312ef9432`](https://github.com/medusajs/medusa/commit/fa1793e8e92164251c776859dea7a5e312ef9432) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - chore(core-flows): avoid overfetching to refresh cart
- [#11664](https://github.com/medusajs/medusa/pull/11664) [`e23f204b7ca0f195e36fef2ba0bae7a686b8da4f`](https://github.com/medusajs/medusa/commit/e23f204b7ca0f195e36fef2ba0bae7a686b8da4f) Thanks [@fPolic](https://github.com/fPolic)! - fix(core-flows, dashboard, medusa): prevent creatiion of a fulfilment without items
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/core-flows",
"version": "2.5.1",
"version": "2.6.0",
"description": "Set of workflow definitions for Medusa",
"main": "dist/index.js",
"exports": {
@@ -26,7 +26,7 @@
"author": "Medusa",
"license": "MIT",
"devDependencies": {
"@medusajs/framework": "^2.5.1",
"@medusajs/framework": "^2.6.0",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
@@ -33,14 +33,14 @@ export type ValidateRefundStepInput = {
/**
* This step validates that the refund is valid for the order.
* If the order does not have an outstanding balance to refund, the step throws an error.
*
*
* :::note
*
*
* You can retrieve an order or payment's details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = validateRefundStep({
* order: {
@@ -56,12 +56,11 @@ export type ValidateRefundStepInput = {
*/
export const validateRefundStep = createStep(
"validate-refund-step",
async function ({
order,
payment,
amount,
}: ValidateRefundStepInput) {
const pendingDifference = order.summary?.raw_pending_difference!
async function ({ order, payment, amount }: ValidateRefundStepInput) {
const pendingDifference =
order.summary?.raw_pending_difference! ??
order.summary?.pending_difference! ??
0
if (MathBN.gte(pendingDifference, 0)) {
throw new MedusaError(
@@ -102,12 +101,12 @@ export type RefundPaymentWorkflowInput = {
export const refundPaymentWorkflowId = "refund-payment-workflow"
/**
* This workflow refunds a payment. It's used by the
* This workflow refunds a payment. It's used by the
* [Refund Payment Admin API Route](https://docs.medusajs.com/api/admin#payments_postpaymentsidrefund).
*
*
* You can use this workflow within your own customizations or custom workflows, allowing you
* to refund a payment in your custom flows.
*
*
* @example
* const { result } = await refundPaymentWorkflow(container)
* .run({
@@ -115,16 +114,14 @@ export const refundPaymentWorkflowId = "refund-payment-workflow"
* payment_id: "payment_123",
* }
* })
*
*
* @summary
*
*
* Refund a payment.
*/
export const refundPaymentWorkflow = createWorkflow(
refundPaymentWorkflowId,
(
input: WorkflowData<RefundPaymentWorkflowInput>
) => {
(input: WorkflowData<RefundPaymentWorkflowInput>) => {
const payment = useRemoteQueryStep({
entry_point: "payment",
fields: [
@@ -1,6 +1,7 @@
import {
WorkflowData,
WorkflowResponse,
createHook,
createWorkflow,
} from "@medusajs/framework/workflows-sdk"
@@ -44,6 +45,14 @@ export const createStockLocationsWorkflowId = "create-stock-locations-workflow"
export const createStockLocationsWorkflow = createWorkflow(
createStockLocationsWorkflowId,
(input: WorkflowData<CreateStockLocationsWorkflowInput>) => {
return new WorkflowResponse(createStockLocations(input.locations))
const stockLocations = createStockLocations(input.locations)
const stockLocationsCreated = createHook("stockLocationsCreated", {
stockLocations,
})
return new WorkflowResponse(stockLocations, {
hooks: [stockLocationsCreated],
})
}
)
+22
View File
@@ -1,5 +1,27 @@
# @medusajs/framework
## 2.6.0
### Patch Changes
- [#11638](https://github.com/medusajs/medusa/pull/11638) [`b0a16488e01632bc2bfee4d4bf2a3e1d3e11b104`](https://github.com/medusajs/medusa/commit/b0a16488e01632bc2bfee4d4bf2a3e1d3e11b104) Thanks [@thetutlage](https://github.com/thetutlage)! - feat: add middleware-file-loader
- [#11636](https://github.com/medusajs/medusa/pull/11636) [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Add support for extra pool configuration
- [#11707](https://github.com/medusajs/medusa/pull/11707) [`5d184ba0c8ff0438b422af5602bf275333eb2019`](https://github.com/medusajs/medusa/commit/5d184ba0c8ff0438b422af5602bf275333eb2019) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(framework): Unified resource loading and exclude non js/ts files
- [#11592](https://github.com/medusajs/medusa/pull/11592) [`9e2af4801daeb72d0e5a4d5ae674bdf6d415cf58`](https://github.com/medusajs/medusa/commit/9e2af4801daeb72d0e5a4d5ae674bdf6d415cf58) Thanks [@thetutlage](https://github.com/thetutlage)! - feat: add routes loader
- [#11646](https://github.com/medusajs/medusa/pull/11646) [`aabbbb7292a59ec029a6165451aa6d949844b2ea`](https://github.com/medusajs/medusa/commit/aabbbb7292a59ec029a6165451aa6d949844b2ea) Thanks [@thetutlage](https://github.com/thetutlage)! - feat: Replace existing router with the new implementation
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`c250de79192bda1b1cd217bcca37f458c693de1d`](https://github.com/medusajs/medusa/commit/c250de79192bda1b1cd217bcca37f458c693de1d), [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031)]:
- @medusajs/types@2.6.0
- @medusajs/utils@2.6.0
- @medusajs/workflows-sdk@2.6.0
- @medusajs/modules-sdk@2.6.0
- @medusajs/orchestration@2.6.0
- @medusajs/telemetry@2.6.0
## 2.5.1
### Patch Changes
+9 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/framework",
"version": "2.5.1",
"version": "2.6.0",
"description": "Framework",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -54,7 +54,7 @@
"test": "jest --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts"
},
"devDependencies": {
"@medusajs/cli": "^2.5.1",
"@medusajs/cli": "^2.6.0",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
@@ -74,12 +74,12 @@
},
"dependencies": {
"@jercle/yargonaut": "^1.1.5",
"@medusajs/modules-sdk": "^2.5.1",
"@medusajs/orchestration": "^2.5.1",
"@medusajs/telemetry": "^2.5.1",
"@medusajs/types": "^2.5.1",
"@medusajs/utils": "^2.5.1",
"@medusajs/workflows-sdk": "^2.5.1",
"@medusajs/modules-sdk": "^2.6.0",
"@medusajs/orchestration": "^2.6.0",
"@medusajs/telemetry": "^2.6.0",
"@medusajs/types": "^2.6.0",
"@medusajs/utils": "^2.6.0",
"@medusajs/workflows-sdk": "^2.6.0",
"@opentelemetry/api": "^1.9.0",
"@types/express": "^4.17.17",
"chokidar": "^3.4.2",
@@ -93,6 +93,7 @@
"jsonwebtoken": "^9.0.2",
"lodash": "4.17.21",
"morgan": "^1.9.1",
"path-to-regexp": "^0.1.10",
"tsconfig-paths": "^4.2.0",
"zod": "3.22.4"
},
@@ -0,0 +1,5 @@
import { Request, Response } from "express"
export function GET(req: Request, res: Response) {
throw new Error("Failed")
}
@@ -16,7 +16,7 @@ import { container } from "../../../container"
import { featureFlagsLoader } from "../../../feature-flags"
import { logger } from "../../../logger"
import { MedusaRequest } from "../../types"
import { RoutesLoader } from "../../router"
import { ApiLoader } from "../../router"
function asArray(resolvers) {
return {
@@ -94,7 +94,7 @@ export const createServer = async (rootDir) => {
next()
})
await new RoutesLoader({
await new ApiLoader({
app,
sourceDir: rootDir,
}).load()
@@ -6,7 +6,7 @@ import {
storeGlobalMiddlewareMock,
} from "../__fixtures__/mocks"
import { createServer } from "../__fixtures__/server"
import { MedusaNextFunction, RoutesLoader } from "../index"
import { MedusaNextFunction, ApiLoader } from "../index"
jest.setTimeout(30000)
@@ -36,6 +36,22 @@ describe("RoutesLoader", function () {
request = request_
})
it("should be handled by the error handler when a route handler fails", async function () {
const res = await request("GET", "/admin/fail", {
adminSession: {
jwt: {
userId: "admin_user",
},
},
})
expect(res.status).toBe(500)
console.log(res)
expect(res.text).toBe(
'{"code":"unknown_error","type":"unknown_error","message":"An unknown error occurred."}'
)
})
it("should return a status 200 on GET admin/order/:id", async function () {
const res = await request("GET", "/admin/orders/1000", {
adminSession: {
@@ -237,7 +253,7 @@ describe("RoutesLoader", function () {
__dirname,
"../__fixtures__/routers-duplicate-parameter"
)
const err = await new RoutesLoader({
const err = await new ApiLoader({
app,
sourceDir: rootDir,
})
@@ -246,7 +262,7 @@ describe("RoutesLoader", function () {
expect(err).toBeDefined()
expect(err.message).toBe(
"Duplicate parameters found in route /admin/customers/[id]/orders/[id] (id). Make sure that all parameters are unique."
"Duplicate parameters found in route /admin/customers/[id]/orders/[id]/route.ts (id). Make sure that all parameters are unique."
)
})
})
@@ -4,7 +4,7 @@ import { MiddlewareFileLoader } from "../middleware-file-loader"
describe("Middleware file loader", () => {
it("should load routes from the filesystem", async () => {
const BASE_DIR = resolve(__dirname, "../__fixtures__/routers-middleware")
const loader = new MiddlewareFileLoader({})
const loader = new MiddlewareFileLoader()
await loader.scanDir(BASE_DIR)
expect(loader.getBodyParserConfigRoutes()).toMatchInlineSnapshot(`
@@ -14,12 +14,22 @@ describe("Middleware file loader", () => {
"preserveRawBody": true,
},
"matcher": "/webhooks",
"method": undefined,
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
"HEAD",
],
},
{
"config": false,
"matcher": "/webhooks/*",
"method": "POST",
"methods": [
"POST",
],
},
]
`)
@@ -28,22 +38,26 @@ describe("Middleware file loader", () => {
{
"handler": [Function],
"matcher": "/customers",
"method": undefined,
"methods": undefined,
},
{
"handler": [Function],
"matcher": "/customers",
"method": "POST",
"methods": [
"POST",
],
},
{
"handler": [Function],
"matcher": "/store/*",
"method": undefined,
"methods": undefined,
},
{
"handler": [Function],
"matcher": "/webhooks/*",
"method": "POST",
"methods": [
"POST",
],
},
]
`)
@@ -4,18 +4,19 @@ import { RoutesLoader } from "../routes-loader"
describe("Routes loader", () => {
it("should load routes from the filesystem", async () => {
const BASE_DIR = resolve(__dirname, "../__fixtures__/routers")
const loader = new RoutesLoader({})
const loader = new RoutesLoader()
await loader.scanDir(BASE_DIR)
expect(loader.getRoutes()).toMatchInlineSnapshot(`
[
{
"absolutePath": "${BASE_DIR}/admin/orders/[id]/route.ts",
"absolutePath": "${BASE_DIR}/admin/fail/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/fail",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/[id]/route.ts",
"route": "/admin/orders/:id",
"relativePath": "/admin/fail/route.ts",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -23,10 +24,23 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/orders/[id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/orders/:id",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/[id]/route.ts",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
},
{
"absolutePath": "${BASE_DIR}/admin/orders/[id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/orders/:id",
"method": "POST",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/[id]/route.ts",
"route": "/admin/orders/:id",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -34,10 +48,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/orders/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/orders",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/route.ts",
"route": "/admin/orders",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -45,10 +60,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/[id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products/:id",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/products/[id]/route.ts",
"route": "/admin/products/:id",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -56,10 +72,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "DELETE",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -67,10 +84,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -78,10 +96,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "HEAD",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -89,10 +108,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "OPTIONS",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -100,10 +120,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "PATCH",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -111,10 +132,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "POST",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -122,10 +144,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "PUT",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -133,10 +156,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/route.ts",
"route": "/admin",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -144,10 +168,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin",
"method": "POST",
"optedOutOfAuth": false,
"relativePath": "/admin/route.ts",
"route": "/admin",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -155,10 +180,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/customers/[customer_id]/orders/[order_id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/customers/:customer_id/orders/:order_id",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/customers/[customer_id]/orders/[order_id]/route.ts",
"route": "/customers/:customer_id/orders/:order_id",
"shouldAppendAdminCors": false,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -166,10 +192,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/customers/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/customers",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/customers/route.ts",
"route": "/customers",
"shouldAppendAdminCors": false,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -184,19 +211,20 @@ describe("Routes loader", () => {
__dirname,
"../__fixtures__/routers-with-duplicates"
)
const loader = new RoutesLoader({})
const loader = new RoutesLoader()
await loader.scanDir(BASE_DIR)
await loader.scanDir(BASE_DIR_2)
expect(loader.getRoutes()).toMatchInlineSnapshot(`
[
{
"absolutePath": "${BASE_DIR}/admin/orders/[id]/route.ts",
"absolutePath": "${BASE_DIR}/admin/fail/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/fail",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/[id]/route.ts",
"route": "/admin/orders/:id",
"relativePath": "/admin/fail/route.ts",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -204,10 +232,23 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/orders/[id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/orders/:id",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/[id]/route.ts",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
},
{
"absolutePath": "${BASE_DIR}/admin/orders/[id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/orders/:id",
"method": "POST",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/[id]/route.ts",
"route": "/admin/orders/:id",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -215,10 +256,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/orders/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/orders",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/orders/route.ts",
"route": "/admin/orders",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -226,10 +268,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR_2}/admin/products/[id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products/:id",
"method": "GET",
"optedOutOfAuth": true,
"relativePath": "/admin/products/[id]/route.ts",
"route": "/admin/products/:id",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -237,10 +280,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "DELETE",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -248,10 +292,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR_2}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "GET",
"optedOutOfAuth": true,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -259,10 +304,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "HEAD",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -270,10 +316,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "OPTIONS",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -281,10 +328,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "PATCH",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -292,10 +340,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR_2}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "POST",
"optedOutOfAuth": true,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -303,10 +352,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/products/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin/products",
"method": "PUT",
"optedOutOfAuth": false,
"relativePath": "/admin/products/route.ts",
"route": "/admin/products",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -314,10 +364,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/admin/route.ts",
"route": "/admin",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -325,10 +376,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/admin/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/admin",
"method": "POST",
"optedOutOfAuth": false,
"relativePath": "/admin/route.ts",
"route": "/admin",
"shouldAppendAdminCors": true,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -336,10 +388,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/customers/[customer_id]/orders/[order_id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/customers/:customer_id/orders/:order_id",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/customers/[customer_id]/orders/[order_id]/route.ts",
"route": "/customers/:customer_id/orders/:order_id",
"shouldAppendAdminCors": false,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -347,10 +400,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR}/customers/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/customers",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/customers/route.ts",
"route": "/customers",
"shouldAppendAdminCors": false,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": false,
@@ -358,10 +412,11 @@ describe("Routes loader", () => {
{
"absolutePath": "${BASE_DIR_2}/store/[customer_id]/orders/[order_id]/route.ts",
"handler": [Function],
"isRoute": true,
"matcher": "/store/:customer_id/orders/:order_id",
"method": "GET",
"optedOutOfAuth": false,
"relativePath": "/store/[customer_id]/orders/[order_id]/route.ts",
"route": "/store/:customer_id/orders/:order_id",
"shouldAppendAdminCors": false,
"shouldAppendAuthCors": false,
"shouldAppendStoreCors": true,
@@ -376,7 +431,7 @@ describe("Routes loader", () => {
"../__fixtures__/routers-duplicate-parameter"
)
const loader = new RoutesLoader({})
const loader = new RoutesLoader()
await expect(() => loader.scanDir(BASE_DIR)).rejects.toThrow(
"Duplicate parameters found in route /admin/customers/[id]/orders/[id]/route.ts (id). Make sure that all parameters are unique."
)
@@ -19,6 +19,14 @@ describe("Routes sorter", () => {
isAppRoute: true,
handler: () => {},
},
{
matcher: "/admin",
handler: () => {},
},
{
matcher: "/store",
handler: () => {},
},
{
matcher: "/admin/products/export",
methods: ["GET"],
@@ -32,12 +40,20 @@ describe("Routes sorter", () => {
},
{
matcher: "/admin/products/:id",
isAppRoute: true,
methods: ["GET"],
handler: () => {},
},
{
matcher: "/admin/products/:id",
isAppRoute: true,
methods: ["POST"],
handler: () => {},
},
{
matcher: "/admin/products/batch",
methods: ["GET"],
isAppRoute: true,
methods: ["POST"],
handler: () => {},
},
{
@@ -57,6 +73,7 @@ describe("Routes sorter", () => {
},
{
matcher: "/admin/:id/export",
isAppRoute: true,
methods: ["GET"],
handler: () => {},
},
@@ -69,6 +86,14 @@ describe("Routes sorter", () => {
expect(sorter.sort()).toMatchInlineSnapshot(`
[
{
"handler": [Function],
"matcher": "/admin",
},
{
"handler": [Function],
"matcher": "/store",
},
{
"handler": [Function],
"matcher": "/v1",
@@ -136,13 +161,15 @@ describe("Routes sorter", () => {
},
{
"handler": [Function],
"isAppRoute": true,
"matcher": "/admin/products/batch",
"methods": [
"GET",
"POST",
],
},
{
"handler": [Function],
"isAppRoute": true,
"matcher": "/admin/products/:id",
"methods": [
"GET",
@@ -150,6 +177,15 @@ describe("Routes sorter", () => {
},
{
"handler": [Function],
"isAppRoute": true,
"matcher": "/admin/products/:id",
"methods": [
"POST",
],
},
{
"handler": [Function],
"isAppRoute": true,
"matcher": "/admin/:id/export",
"methods": [
"GET",
@@ -286,4 +322,77 @@ describe("Routes sorter", () => {
]
`)
})
it("should sort routes with multiple params and static values", () => {
const sorter = new RoutesSorter([
{
matcher: "/admin/promotions/:id/:rule_type",
methods: ["GET"],
handler: () => {},
},
{
matcher:
"/admin/promotions/rule-value-options/:rule_type/:rule_attribute_id",
methods: ["GET"],
handler: () => {},
},
{
matcher: "/admin/promotions/rule-attribute-options/:rule_type",
methods: ["GET"],
handler: () => {},
},
{
matcher: "/admin/promotions/:id/:rule_type",
methods: ["GET"],
handler: () => {},
},
{
matcher: "/admin/promotions/rule-attribute-options/:rule_type",
methods: ["GET"],
isAppRoute: true,
handler: () => {},
},
])
expect(sorter.sort()).toMatchInlineSnapshot(`
[
{
"handler": [Function],
"matcher": "/admin/promotions/rule-value-options/:rule_type/:rule_attribute_id",
"methods": [
"GET",
],
},
{
"handler": [Function],
"matcher": "/admin/promotions/rule-attribute-options/:rule_type",
"methods": [
"GET",
],
},
{
"handler": [Function],
"isAppRoute": true,
"matcher": "/admin/promotions/rule-attribute-options/:rule_type",
"methods": [
"GET",
],
},
{
"handler": [Function],
"matcher": "/admin/promotions/:id/:rule_type",
"methods": [
"GET",
],
},
{
"handler": [Function],
"matcher": "/admin/promotions/:id/:rule_type",
"methods": [
"GET",
],
},
]
`)
})
})
@@ -2,10 +2,12 @@ import { join } from "path"
import { dynamicImport, FileSystem } from "@medusajs/utils"
import { logger } from "../logger"
import type {
MiddlewaresConfig,
BodyParserConfigRoute,
ScannedMiddlewareDescriptor,
import {
type MiddlewaresConfig,
type BodyParserConfigRoute,
type MiddlewareDescriptor,
type MedusaErrorHandlerFunction,
HTTP_METHODS,
} from "./types"
/**
@@ -13,21 +15,6 @@ import type {
*/
const MIDDLEWARE_FILE_NAME = "middlewares"
const log = ({
activityId,
message,
}: {
activityId?: string
message: string
}) => {
if (activityId) {
logger.progress(activityId, message)
return
}
logger.debug(message)
}
/**
* Exposes the API to scan a directory and load the `middleware.ts` file. This file contains
* the configuration for certain global middlewares and core routes validators. Also, it may
@@ -35,19 +22,19 @@ const log = ({
*/
export class MiddlewareFileLoader {
/**
* Middleware collected manually or by scanning directories
* Global error handler exported from the middleware file loader
*/
#middleware: ScannedMiddlewareDescriptor[] = []
#bodyParserConfigRoutes: BodyParserConfigRoute[] = []
#errorHandler?: MedusaErrorHandlerFunction
/**
* An eventual activity id for information tracking
* Middleware collected manually or by scanning directories
*/
readonly #activityId?: string
#middleware: MiddlewareDescriptor[] = []
constructor({ activityId }: { activityId?: string }) {
this.#activityId = activityId
}
/**
* Route matchers on which a custom body parser config is used
*/
#bodyParserConfigRoutes: BodyParserConfigRoute[] = []
/**
* Processes the middleware file and returns the middleware and the
@@ -58,25 +45,23 @@ export class MiddlewareFileLoader {
const middlewareConfig = middlewareExports.default
if (!middlewareConfig) {
log({
activityId: this.#activityId,
message: `No middleware configuration found in ${absolutePath}. Skipping middleware configuration.`,
})
logger.warn(
`No middleware configuration found in ${absolutePath}. Skipping middleware configuration.`
)
return
}
const routes = middlewareConfig.routes as MiddlewaresConfig["routes"]
if (!routes || !Array.isArray(routes)) {
log({
activityId: this.#activityId,
message: `Invalid default export found in ${absolutePath}. Make sure to use "defineMiddlewares" function and export its output.`,
})
logger.warn(
`Invalid default export found in ${absolutePath}. Make sure to use "defineMiddlewares" function and export its output.`
)
return
}
const result = routes.reduce<{
bodyParserConfigRoutes: BodyParserConfigRoute[]
middleware: ScannedMiddlewareDescriptor[]
middleware: MiddlewareDescriptor[]
}>(
(result, route) => {
if (!route.matcher) {
@@ -92,9 +77,15 @@ export class MiddlewareFileLoader {
const matcher = String(route.matcher)
if ("bodyParser" in route && route.bodyParser !== undefined) {
const methods = route.methods || [...HTTP_METHODS]
logger.debug(
`using custom bodyparser config on matcher ${methods}:${route.matcher}`
)
result.bodyParserConfigRoutes.push({
matcher: matcher,
method: route.method,
methods,
config: route.bodyParser,
})
}
@@ -104,7 +95,7 @@ export class MiddlewareFileLoader {
result.middleware.push({
handler: middleware,
matcher: matcher,
method: route.method,
methods: route.methods,
})
})
}
@@ -116,8 +107,16 @@ export class MiddlewareFileLoader {
}
)
this.#middleware = result.middleware
this.#bodyParserConfigRoutes = result.bodyParserConfigRoutes
const errorHandler =
middlewareConfig.errorHandler as MiddlewaresConfig["errorHandler"]
if (errorHandler) {
this.#errorHandler = errorHandler
}
this.#middleware = this.#middleware.concat(result.middleware)
this.#bodyParserConfigRoutes = this.#bodyParserConfigRoutes.concat(
result.bodyParserConfigRoutes
)
}
/**
@@ -133,11 +132,18 @@ export class MiddlewareFileLoader {
)
} else if (await fs.exists(`${MIDDLEWARE_FILE_NAME}.js`)) {
await this.#processMiddlewareFile(
join(sourceDir, `${MIDDLEWARE_FILE_NAME}.ts`)
join(sourceDir, `${MIDDLEWARE_FILE_NAME}.js`)
)
}
}
/**
* Returns the globally registered error handler (if any)
*/
getErrorHandler() {
return this.#errorHandler
}
/**
* Returns a collection of registered middleware
*/
@@ -1,10 +1,18 @@
import { isObject, isPresent } from "@medusajs/utils"
import { MedusaNextFunction, MedusaRequest } from "../types"
import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "../types"
export function applyDefaultFilters<TFilter extends object>(
filtersToApply: TFilter
) {
return async (req: MedusaRequest, _, next: MedusaNextFunction) => {
return async function defaultFiltersMiddleware(
req: MedusaRequest,
_: MedusaResponse,
next: MedusaNextFunction
) {
for (const [filter, filterValue] of Object.entries(filtersToApply)) {
let valueToApply = filterValue
@@ -1,7 +1,15 @@
import { MedusaNextFunction, MedusaRequest } from "../types"
import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "../types"
export function applyParamsAsFilters(mappings: { [param: string]: string }) {
return async (req: MedusaRequest, _, next: MedusaNextFunction) => {
return async function paramsAsFiltersMiddleware(
req: MedusaRequest,
_: MedusaResponse,
next: MedusaNextFunction
) {
for (const [param, paramValue] of Object.entries(req.params)) {
if (mappings[param]) {
req.filterableFields[mappings[param]] = paramValue
@@ -0,0 +1,96 @@
import { memoize } from "lodash"
import logger from "@medusajs/cli/dist/reporter"
import { json, NextFunction, RequestHandler, text, urlencoded } from "express"
import type {
MedusaRequest,
MedusaResponse,
MiddlewareVerb,
ParserConfigArgs,
MiddlewareFunction,
BodyParserConfigRoute,
} from "../types"
import type { RoutesFinder } from "../routes-finder"
/**
* Parsers to use for parsing the HTTP request body
*/
const parsers = {
json: memoize(function jsonParserMiddleware(options?: ParserConfigArgs) {
return json({
limit: options?.sizeLimit,
verify: options?.preserveRawBody
? (req: MedusaRequest, res: MedusaResponse, buf: Buffer) => {
req.rawBody = buf
}
: undefined,
})
}),
text: memoize(function textParser(options?: ParserConfigArgs) {
return text({
limit: options?.sizeLimit,
})
}),
urlencoded: memoize(function urlencodedParserMiddleware(
options?: ParserConfigArgs
) {
return urlencoded({
limit: options?.sizeLimit,
extended: true,
})
}),
}
/**
* Creates the bodyparser middlewares stack that creates custom bodyparsers
* during an HTTP request based upon the defined config. The bodyparser
* instances are cached for re-use.
*/
export function createBodyParserMiddlewaresStack(
route: string,
routesFinder: RoutesFinder<BodyParserConfigRoute>,
tracer?: (
handler: RequestHandler | MiddlewareFunction,
route: { route: string; method?: string }
) => RequestHandler | MiddlewareFunction
) {
return (["json", "text", "urlencoded"] as (keyof typeof parsers)[]).map(
(parser) => {
function bodyParser(
req: MedusaRequest,
res: MedusaResponse,
next: NextFunction
) {
const matchingRoute = routesFinder.find(
req.path,
req.method as MiddlewareVerb
)
const parserMiddleware = parsers[parser]
if (!matchingRoute) {
return parserMiddleware()(req, res, next)
}
if (matchingRoute.config === false) {
logger.debug(
`skipping ${parser} bodyparser middleware ${req.method} ${req.path}`
)
return next()
}
logger.debug(
`using custom ${parser} bodyparser config ${req.method} ${req.path}`
)
return parserMiddleware(matchingRoute.config)(req, res, next)
}
Object.defineProperty(bodyParser, "name", {
value: `${parser}BodyParser`,
})
return (
tracer ? tracer(bodyParser, { route }) : bodyParser
) as RequestHandler
}
)
}
@@ -1,7 +1,15 @@
import { MedusaNextFunction, MedusaRequest } from "../types"
import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "../types"
export function clearFiltersByKey(keys: string[]) {
return async (req: MedusaRequest, _, next: MedusaNextFunction) => {
return async function clearFiltersByKeyMiddleware(
req: MedusaRequest,
_: MedusaResponse,
next: MedusaNextFunction
) {
keys.forEach((key) => {
delete req.filterableFields[key]
})
@@ -5,7 +5,7 @@ import {
MedusaError,
PUBLISHABLE_KEY_HEADER,
} from "@medusajs/utils"
import {
import type {
MedusaNextFunction,
MedusaResponse,
MedusaStoreRequest,
@@ -13,7 +13,7 @@ import {
export async function ensurePublishableApiKeyMiddleware(
req: MedusaStoreRequest,
_res: MedusaResponse,
_: MedusaResponse,
next: MedusaNextFunction
) {
const publishableApiKey = req.get(PUBLISHABLE_KEY_HEADER)
@@ -1,4 +1,4 @@
import { NextFunction, Response } from "express"
import { NextFunction, ErrorRequestHandler, Response } from "express"
import { ContainerRegistrationKeys, MedusaError } from "@medusajs/utils"
import { formatException } from "./exception-formatter"
@@ -13,12 +13,12 @@ const INVALID_REQUEST_ERROR = "invalid_request_error"
const INVALID_STATE_ERROR = "invalid_state_error"
export function errorHandler() {
return (
return function coreErrorHandler(
err: MedusaError,
req: MedusaRequest,
res: Response,
next: NextFunction
) => {
_: NextFunction
) {
const logger = req.scope.resolve(ContainerRegistrationKeys.LOGGER)
err = formatException(err)
@@ -76,7 +76,7 @@ export function errorHandler() {
}
res.status(statusCode).json(errObj)
}
} as unknown as ErrorRequestHandler
}
/**
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,64 @@
import pathToRegexp from "path-to-regexp"
import type { MiddlewareVerb, RouteVerb } from "./types"
export class RoutesFinder<
T extends
| { matcher: string; methods: MiddlewareVerb | MiddlewareVerb[] }
| { matcher: string; method: RouteVerb }
> {
/**
* Cache of existing matches to avoid regex tests on every
* single HTTP request
*/
#existingMatches: Map<
string,
| (T & {
matchRegex: RegExp
})
| null
> = new Map()
/**
* Collection of registered routes
*/
#routes: (T & {
matchRegex: RegExp
})[] = []
constructor(routes?: T[]) {
if (routes) {
routes.forEach((route) => this.add(route))
}
}
/**
* Register route for lookup
*/
add(route: T) {
this.#routes.push({
...route,
matchRegex: pathToRegexp(route.matcher),
})
}
/**
* Get the matching route for a given HTTP method and URL
*/
find(url: string, method: MiddlewareVerb) {
const key = `${method}:${url}`
if (this.#existingMatches.has(key)) {
return this.#existingMatches.get(key)
}
const result =
this.#routes.find((route) => {
if ("methods" in route) {
return route.methods.includes(method) && route.matchRegex.test(url)
}
return route.method === method && route.matchRegex.test(url)
}) ?? null
this.#existingMatches.set(key, result)
return result
}
}
@@ -1,12 +1,7 @@
import { join, parse, sep } from "path"
import { dynamicImport, readDirRecursive } from "@medusajs/utils"
import { logger } from "../logger"
import {
type RouteVerb,
HTTP_METHODS,
type ScannedRouteDescriptor,
type FileSystemRouteDescriptor,
} from "./types"
import { type RouteVerb, HTTP_METHODS, type RouteDescriptor } from "./types"
/**
* File name that is used to indicate that the file is a route file
@@ -43,21 +38,6 @@ const ADMIN_ROUTE_MATCH = /(\/admin$|\/admin\/)/
const STORE_ROUTE_MATCH = /(\/store$|\/store\/)/
const AUTH_ROUTE_MATCH = /(\/auth$|\/auth\/)/
const log = ({
activityId,
message,
}: {
activityId?: string
message: string
}) => {
if (activityId) {
logger.progress(activityId, message)
return
}
logger.debug(message)
}
/**
* Exposes to API to register routes manually or by scanning the filesystem from a
* source directory.
@@ -69,19 +49,7 @@ export class RoutesLoader {
/**
* Routes collected manually or by scanning directories
*/
#routes: Record<
string,
Record<string, ScannedRouteDescriptor | FileSystemRouteDescriptor>
> = {}
/**
* An eventual activity id for information tracking
*/
readonly #activityId?: string
constructor({ activityId }: { activityId?: string }) {
this.#activityId = activityId
}
#routes: Record<string, Record<string, RouteDescriptor>> = {}
/**
* Creates the route path from its relative file path.
@@ -96,10 +64,9 @@ export class RoutesLoader {
if (segment.startsWith("[")) {
segment = segment.replace(PARAM_SEGMENT_MATCHER, (_, group) => {
if (params[group]) {
log({
activityId: this.#activityId,
message: `Duplicate parameters found in route ${relativePath} (${group})`,
})
logger.debug(
`Duplicate parameters found in route ${relativePath} (${group})`
)
throw new Error(
`Duplicate parameters found in route ${relativePath} (${group}). Make sure that all parameters are unique.`
@@ -122,7 +89,7 @@ export class RoutesLoader {
async #getRoutesForFile(
routePath: string,
absolutePath: string
): Promise<ScannedRouteDescriptor[]> {
): Promise<RouteDescriptor[]> {
const routeExports = await dynamicImport(absolutePath)
/**
@@ -161,10 +128,9 @@ export class RoutesLoader {
}
if (!HTTP_METHODS.includes(key as RouteVerb)) {
log({
activityId: this.#activityId,
message: `Skipping handler ${key} in ${absolutePath}. Invalid HTTP method: ${key}.`,
})
logger.debug(
`Skipping handler ${key} in ${absolutePath}. Invalid HTTP method: ${key}.`
)
return false
}
@@ -172,14 +138,15 @@ export class RoutesLoader {
})
.map((key) => {
return {
route: routePath,
isRoute: true,
matcher: routePath,
method: key as RouteVerb,
handler: routeExports[key],
optedOutOfAuth: !shouldAuthenticate,
shouldAppendAdminCors: shouldApplyCors && routeType === "admin",
shouldAppendAuthCors: shouldApplyCors && routeType === "auth",
shouldAppendStoreCors: shouldApplyCors && routeType === "store",
} satisfies ScannedRouteDescriptor
} satisfies RouteDescriptor
})
}
@@ -232,18 +199,16 @@ export class RoutesLoader {
/**
* Register a route
*/
registerRoute(route: ScannedRouteDescriptor | FileSystemRouteDescriptor) {
this.#routes[route.route] = this.#routes[route.route] ?? {}
const trackedRoute = this.#routes[route.route]
registerRoute(route: RouteDescriptor) {
this.#routes[route.matcher] = this.#routes[route.matcher] ?? {}
const trackedRoute = this.#routes[route.matcher]
trackedRoute[route.method] = route
}
/**
* Register one or more routes
*/
registerRoutes(
routes: (ScannedRouteDescriptor | FileSystemRouteDescriptor)[]
) {
registerRoutes(routes: RouteDescriptor[]) {
routes.forEach((route) => this.registerRoute(route))
}
@@ -252,14 +217,16 @@ export class RoutesLoader {
* manually.
*/
getRoutes() {
return Object.keys(this.#routes).reduce<
(ScannedRouteDescriptor | FileSystemRouteDescriptor)[]
>((result, routePattern) => {
const methodsRoutes = this.#routes[routePattern]
Object.keys(methodsRoutes).forEach((method) => {
result.push(methodsRoutes[method])
})
return result
}, [])
return Object.keys(this.#routes).reduce<RouteDescriptor[]>(
(result, routePattern) => {
const methodsRoutes = this.#routes[routePattern]
Object.keys(methodsRoutes).forEach((method) => {
const route = methodsRoutes[method]
result.push(route)
})
return result
},
[]
)
}
}
@@ -1,9 +1,9 @@
import { MiddlewareVerb } from "./types"
import { MiddlewareVerb, RouteVerb } from "./types"
/**
* Route represents both the middleware/routes defined via the
* "defineMiddlewares" method and the routes scanned from
* the filesystem. The later one's must be marked with "isAppRoute = true".
* the filesystem.
*/
type Route = {
/**
@@ -17,10 +17,9 @@ type Route = {
handler?: any
/**
* Must be true when the route is discovered via the fileystem
* scanning.
* The HTTP method specified as a single value
*/
isAppRoute?: boolean
method?: RouteVerb
/**
* The HTTP methods this route is supposed to handle.
@@ -48,39 +47,39 @@ type Route = {
* - static
* - params
*/
type RoutesBranch = {
type RoutesBranch<T extends Route> = {
global: {
routes: Route[]
routes: T[]
children?: {
[segment: string]: RoutesBranch
[segment: string]: RoutesBranch<T>
}
}
regex: {
routes: Route[]
routes: T[]
children?: {
[segment: string]: RoutesBranch
[segment: string]: RoutesBranch<T>
}
}
wildcard: {
routes: Route[]
routes: T[]
children?: {
[segment: string]: RoutesBranch
[segment: string]: RoutesBranch<T>
}
}
params: {
routes: Route[]
routes: T[]
children?: {
[segment: string]: RoutesBranch
[segment: string]: RoutesBranch<T>
}
}
static: {
routes: Route[]
routes: T[]
children?: {
[segment: string]: RoutesBranch
[segment: string]: RoutesBranch<T>
}
}
}
@@ -91,29 +90,42 @@ type RoutesBranch = {
* like structure and then sort them back to a flat array based upon the
* priorities of different types of nodes.
*/
export class RoutesSorter {
export class RoutesSorter<T extends Route> {
/**
* The order in which the routes will be sorted. This
* can be overridden at the time of call the sort
* method.
*/
#orderBy: [
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>
] = ["global", "wildcard", "regex", "static", "params"]
/**
* Input routes
*/
#routesToProcess: Route[]
#routesToProcess: T[]
/**
* Intermediate tree representation for sorting routes
*/
#routesTree: {
[segment: string]: RoutesBranch
[segment: string]: RoutesBranch<T>
} = {
root: this.#createBranch(),
}
constructor(routes: Route[]) {
constructor(routes: T[]) {
this.#routesToProcess = routes
}
/**
* Creates an empty branch with known nodes
*/
#createBranch(): RoutesBranch {
#createBranch(): RoutesBranch<T> {
return {
global: {
routes: [],
@@ -162,14 +174,14 @@ export class RoutesSorter {
* }
* ```
*/
#processRoute(route: Route) {
#processRoute(route: T) {
const segments = route.matcher.split("/").filter((s) => s.length)
let parent = this.#routesTree["root"]
segments.forEach((segment, index) => {
let bucket: keyof RoutesBranch = "static"
let bucket: keyof RoutesBranch<T> = "static"
if (!route.methods) {
if (!route.methods && !route.method) {
bucket = "global"
} else if (segment.startsWith("*")) {
bucket = "wildcard"
@@ -194,40 +206,51 @@ export class RoutesSorter {
/**
* Returns an array of sorted routes for a given branch.
*/
#sortBranch(routeBranch: { [segment: string]: RoutesBranch }) {
#sortBranch(
routeBranch: { [segment: string]: RoutesBranch<T> },
orderBy: [
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>
]
) {
const branchRoutes = Object.keys(routeBranch).reduce<{
global: Route[]
wildcard: Route[]
regex: Route[]
params: Route[]
static: Route[]
global: T[]
wildcard: T[]
regex: T[]
params: T[]
static: T[]
}>(
(result, branchKey) => {
const node = routeBranch[branchKey]
result.global.push(...node.global.routes)
if (node.global.children) {
result.global.push(...this.#sortBranch(node.global.children))
result.global.push(...this.#sortBranch(node.global.children, orderBy))
}
result.wildcard.push(...node.wildcard.routes)
if (node.wildcard.children) {
result.wildcard.push(...this.#sortBranch(node.wildcard.children))
result.wildcard.push(
...this.#sortBranch(node.wildcard.children, orderBy)
)
}
result.regex.push(...node.regex.routes)
if (node.regex.children) {
result.regex.push(...this.#sortBranch(node.regex.children))
result.regex.push(...this.#sortBranch(node.regex.children, orderBy))
}
result.static.push(...node.static.routes)
if (node.static.children) {
result.static.push(...this.#sortBranch(node.static.children))
result.static.push(...this.#sortBranch(node.static.children, orderBy))
}
result.params.push(...node.params.routes)
if (node.params.children) {
result.params.push(...this.#sortBranch(node.params.children))
result.params.push(...this.#sortBranch(node.params.children, orderBy))
}
return result
@@ -244,19 +267,33 @@ export class RoutesSorter {
/**
* Concatenating routes as per their priority.
*/
const routes: Route[] = branchRoutes.global
.concat(branchRoutes.wildcard)
.concat(branchRoutes.regex)
.concat(branchRoutes.static)
.concat(branchRoutes.params)
return routes
return orderBy.reduce<T[]>((result, branch) => {
result = result.concat(branchRoutes[branch])
return result
}, [])
}
/**
* Sort the input routes
* Returns the intermediate representation of routes as a tree.
*/
sort() {
getTree() {
return this.#routesTree
}
/**
* Sort the input routes. You can optionally specify a custom
* orderBy array. Defaults to: ["global", "wildcard", "regex", "static", "params"]
*/
sort(
orderBy?: [
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>,
keyof RoutesBranch<T>
]
) {
this.#routesToProcess.map((route) => this.#processRoute(route))
return this.#sortBranch(this.#routesTree)
return this.#sortBranch(this.#routesTree, orderBy ?? this.#orderBy)
}
}
+14 -35
View File
@@ -34,20 +34,6 @@ export type AsyncRouteHandler = (
export type RouteHandler = SyncRouteHandler | AsyncRouteHandler
export type RouteImplementation = {
method?: RouteVerb
handler: RouteHandler
}
export type RouteConfig = {
optedOutOfAuth?: boolean
routeType?: "admin" | "store" | "auth"
shouldAppendAdminCors?: boolean
shouldAppendStoreCors?: boolean
shouldAppendAuthCors?: boolean
routes?: RouteImplementation[]
}
export type MiddlewareFunction =
| MedusaRequestHandler
| ((...args: any[]) => any)
@@ -67,7 +53,11 @@ export type ParserConfigArgs = {
export type ParserConfig = false | ParserConfigArgs
export type MiddlewareRoute = {
/**
* @deprecated. Instead use {@link MiddlewareRoute.methods}
*/
method?: MiddlewareVerb | MiddlewareVerb[]
methods?: MiddlewareVerb[]
matcher: string | RegExp
bodyParser?: ParserConfig
middlewares?: MiddlewareFunction[]
@@ -78,49 +68,38 @@ export type MiddlewaresConfig = {
routes?: MiddlewareRoute[]
}
export type RouteDescriptor = {
absolutePath: string
relativePath: string
route: string
priority: number
config?: RouteConfig
}
/**
* Route descriptor refers represents a route either scanned
* from the filesystem or registered manually. It does not
* represent a middleware
*/
export type ScannedRouteDescriptor = {
route: string
export type RouteDescriptor = {
matcher: string
method: RouteVerb
handler: RouteHandler
optedOutOfAuth: boolean
isRoute: true
routeType?: "admin" | "store" | "auth"
absolutePath?: string
relativePath?: string
shouldAppendAdminCors: boolean
shouldAppendStoreCors: boolean
shouldAppendAuthCors: boolean
}
/**
* FileSystem route description represents a route scanned from
* the filesystem
* Represents a middleware
*/
export type FileSystemRouteDescriptor = ScannedRouteDescriptor & {
absolutePath: string
relativePath: string
}
export type ScannedMiddlewareDescriptor = {
export type MiddlewareDescriptor = {
matcher: string
method?: MiddlewareVerb | MiddlewareVerb[]
methods?: MiddlewareVerb | MiddlewareVerb[]
handler: MiddlewareFunction
}
export type BodyParserConfigRoute = {
matcher: string
method?: MiddlewareVerb | MiddlewareVerb[]
config?: ParserConfig
methods: MiddlewareVerb | MiddlewareVerb[]
config: ParserConfig
}
export type GlobalMiddlewareDescriptor = {
@@ -16,7 +16,11 @@ import zod, { ZodRawShape } from "zod"
*/
export function defineMiddlewares<
Route extends {
/**
* @deprecated. Instead use {@link MiddlewareRoute.methods}
*/
method?: MiddlewareVerb | MiddlewareVerb[]
methods?: MiddlewareVerb[]
matcher: string | RegExp
bodyParser?: ParserConfig
additionalDataValidator?: ZodRawShape
@@ -38,7 +42,8 @@ export function defineMiddlewares<
return {
errorHandler,
routes: routes.map((route) => {
const { middlewares, additionalDataValidator, ...rest } = route
let { middlewares, method, methods, additionalDataValidator, ...rest } =
route
const customMiddleware: MedusaRequestHandler[] = []
/**
@@ -54,8 +59,13 @@ export function defineMiddlewares<
})
}
if (!methods) {
methods = Array.isArray(method) ? method : method ? [method] : method
}
return {
...rest,
methods,
middlewares: customMiddleware.concat(middlewares || []),
}
}),
@@ -3,7 +3,11 @@ import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import { MedusaNextFunction, MedusaRequest } from "../types"
import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "../types"
export function maybeApplyLinkFilter({
entryPoint,
@@ -13,7 +17,7 @@ export function maybeApplyLinkFilter({
}) {
return async function linkFilter(
req: MedusaRequest,
_,
_: MedusaResponse,
next: MedusaNextFunction
) {
const filterableFields = req.filterableFields
@@ -0,0 +1,38 @@
import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
MiddlewareFunction,
RouteHandler,
} from "../types"
export const wrapHandler = <T extends RouteHandler | MiddlewareFunction>(
fn: T
) => {
async function wrappedHandler(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) {
const req_ = req as MedusaRequest & { errors?: Error[] }
if (req_?.errors?.length) {
return res.status(400).json({
errors: req_.errors,
message:
"Provided request body contains errors. Please check the data and retry the request",
})
}
try {
return await fn(req, res, next)
} catch (err) {
console.log(err)
next(err)
}
}
if (fn.name) {
Object.defineProperty(wrappedHandler, "name", { value: fn.name })
}
return wrappedHandler as T
}
@@ -0,0 +1,11 @@
import { MedusaContainer } from "@medusajs/types"
export default async function handler(container: MedusaContainer) {
console.log(`You have received 5 orders today`)
}
export const config = {
name: "summarize-orders",
schedule: "* * * * * *",
numberOfExecutions: 2,
}
@@ -0,0 +1,11 @@
import { MedusaContainer } from "@medusajs/types"
export default async function handler(container: MedusaContainer) {
console.log(`You have received 5 orders today`)
}
export const config = {
name: "summarize-orders",
schedule: "* * * * * *",
numberOfExecutions: 2,
}
@@ -6,13 +6,14 @@ import { JobLoader } from "../job-loader"
describe("register jobs", () => {
WorkflowScheduler.setStorage(new MockSchedulerStorage())
let jobLoader!: JobLoader
beforeAll(() => {
jobLoader = new JobLoader(join(__dirname, "../__fixtures__/plugin/jobs"))
afterEach(() => {
WorkflowManager.unregisterAll()
})
it("registers jobs from plugins", async () => {
it("should registers jobs from plugins", async () => {
const jobLoader: JobLoader = new JobLoader(
join(__dirname, "../__fixtures__/plugin/jobs")
)
await jobLoader.load()
const workflow = WorkflowManager.getWorkflow("job-summarize-orders")
expect(workflow).toBeDefined()
@@ -21,4 +22,13 @@ describe("register jobs", () => {
numberOfExecutions: 2,
})
})
it("should not load non js/ts files", async () => {
const jobLoader: JobLoader = new JobLoader(
join(__dirname, "../__fixtures__/plugin/jobs-with-other-files")
)
await jobLoader.load()
const workflow = WorkflowManager.getWorkflow("job-summarize-orders")
expect(workflow).toBeUndefined()
})
})
+23 -82
View File
@@ -1,21 +1,13 @@
import type { SchedulerOptions } from "@medusajs/orchestration"
import { MedusaContainer } from "@medusajs/types"
import {
dynamicImport,
isObject,
MedusaError,
promiseAll,
readDirRecursive,
} from "@medusajs/utils"
import { isObject, MedusaError } from "@medusajs/utils"
import {
createStep,
createWorkflow,
StepResponse,
} from "@medusajs/workflows-sdk"
import { Dirent } from "fs"
import { access } from "fs/promises"
import { join } from "path"
import { logger } from "../logger"
import { ResourceLoader } from "../utils/resource-loader"
type CronJobConfig = {
name: string
@@ -25,27 +17,26 @@ type CronJobConfig = {
type CronJobHandler = (container: MedusaContainer) => Promise<any>
export class JobLoader {
/**
* The directory from which to load the jobs
* @private
*/
#sourceDir: string | string[]
/**
* The list of file names to exclude from the subscriber scan
* @private
*/
#excludes: RegExp[] = [
/index\.js/,
/index\.ts/,
/\.DS_Store/,
/(\.ts\.map|\.js\.map|\.d\.ts|\.md)/,
/^_[^/\\]*(\.[^/\\]+)?$/,
]
export class JobLoader extends ResourceLoader {
protected resourceName = "job"
constructor(sourceDir: string | string[]) {
this.#sourceDir = sourceDir
super(sourceDir)
}
protected async onFileLoaded(
path: string,
fileExports: {
default: CronJobHandler
config: CronJobConfig
}
) {
this.validateConfig(fileExports.config)
logger.debug(`Registering job from ${path}.`)
this.register({
config: fileExports.config,
handler: fileExports.default,
})
}
/**
@@ -85,7 +76,7 @@ export class JobLoader {
* @param handler
* @protected
*/
protected registerJob({
protected register({
config,
handler,
}: {
@@ -128,58 +119,8 @@ export class JobLoader {
* Load cron jobs from one or multiple source paths
*/
async load() {
const normalizedSourcePath = Array.isArray(this.#sourceDir)
? this.#sourceDir
: [this.#sourceDir]
await super.discoverResources()
const promises = normalizedSourcePath.map(async (sourcePath) => {
try {
await access(sourcePath)
} catch {
logger.info(`No job to load from ${sourcePath}. skipped.`)
return
}
return await readDirRecursive(sourcePath).then(async (entries) => {
const fileEntries = entries.filter((entry: Dirent) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(entry.name))
)
})
logger.debug(`Registering jobs from ${sourcePath}.`)
return await promiseAll(
fileEntries.map(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
const module_ = await dynamicImport(fullPath)
const input = {
config: module_.config,
handler: module_.default,
}
this.validateConfig(input.config)
return input
})
)
})
})
const jobsInputs = await promiseAll(promises)
const flatJobsInput = jobsInputs.flat(1).filter(
(
job
): job is {
config: CronJobConfig
handler: CronJobHandler
} => !!job
)
flatJobsInput.map(this.registerJob)
logger.debug(`Job registered.`)
logger.debug(`Jobs registered.`)
}
}
@@ -0,0 +1,10 @@
import { SubscriberArgs, SubscriberConfig } from "../../types"
export default async function orderNotifier(\_: SubscriberArgs) {
return await Promise.resolve()
}
export const config: SubscriberConfig = {
event: ["order.placed", "order.canceled", "order.completed"],
context: { subscriberId: "order-notifier-md" },
}
@@ -0,0 +1,10 @@
import { SubscriberArgs, SubscriberConfig } from "../../types"
export default async function orderNotifier(_: SubscriberArgs) {
return await Promise.resolve()
}
export const config: SubscriberConfig = {
event: ["order.placed", "order.canceled", "order.completed"],
context: { subscriberId: "order-notifier-txt" },
}
@@ -1,20 +1,12 @@
import { Event, IEventBusModuleService, Subscriber } from "@medusajs/types"
import {
dynamicImport,
kebabCase,
Modules,
promiseAll,
readDirRecursive,
resolveExports,
} from "@medusajs/utils"
import { access } from "fs/promises"
import { join, parse } from "path"
import { kebabCase, Modules } from "@medusajs/utils"
import { parse } from "path"
import { Dirent } from "fs"
import { configManager } from "../config"
import { container } from "../container"
import { logger } from "../logger"
import { SubscriberArgs, SubscriberConfig } from "./types"
import { ResourceLoader } from "../utils/resource-loader"
type SubscriberHandler<T> = (args: SubscriberArgs<T>) => Promise<void>
@@ -23,31 +15,15 @@ type SubscriberModule<T> = {
handler: SubscriberHandler<T>
}
export class SubscriberLoader {
export class SubscriberLoader extends ResourceLoader {
protected resourceName = "subscriber"
/**
* The options of the plugin from which the subscribers are being loaded
* @private
*/
#pluginOptions: Record<string, unknown>
/**
* The base directory from which to scan for the subscribers
* @private
*/
#sourceDir: string | string[]
/**
* The list of file names to exclude from the subscriber scan
* @private
*/
#excludes: RegExp[] = [
/index\.js/,
/index\.ts/,
/\.DS_Store/,
/(\.ts\.map|\.js\.map|\.d\.ts|\.md)/,
/^_[^/\\]*(\.[^/\\]+)?$/,
]
/**
* Map of subscribers descriptors to consume in the loader
* @private
@@ -58,10 +34,28 @@ export class SubscriberLoader {
sourceDir: string | string[],
options: Record<string, unknown> = {}
) {
this.#sourceDir = sourceDir
super(sourceDir)
this.#pluginOptions = options
}
protected async onFileLoaded(
path: string,
fileExports: Record<string, unknown>
) {
const isValid = this.validateSubscriber(fileExports, path)
logger.debug(`Registering subscribers from ${path}.`)
if (!isValid) {
return
}
this.#subscriberDescriptors.set(path, {
config: fileExports.config,
handler: fileExports.default,
})
}
private validateSubscriber(
subscriber: any,
path: string
@@ -122,42 +116,6 @@ export class SubscriberLoader {
return true
}
private async createDescriptor(absolutePath: string) {
return await dynamicImport(absolutePath).then((module_) => {
module_ = resolveExports(module_)
const isValid = this.validateSubscriber(module_, absolutePath)
if (!isValid) {
return
}
this.#subscriberDescriptors.set(absolutePath, {
config: module_.config,
handler: module_.default,
})
})
}
private async createMap(dirPath: string) {
const promises = await readDirRecursive(dirPath).then(async (entries) => {
const fileEntries = entries.filter((entry) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(entry.name))
)
})
logger.debug(`Registering subscribers from ${dirPath}.`)
return fileEntries.flatMap(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
return await this.createDescriptor(fullPath)
})
})
await promiseAll(promises)
}
private inferIdentifier<T>(
fileName: string,
{ context }: SubscriberConfig,
@@ -222,21 +180,7 @@ export class SubscriberLoader {
}
async load() {
const normalizeSourcePaths = Array.isArray(this.#sourceDir)
? this.#sourceDir
: [this.#sourceDir]
const promises = normalizeSourcePaths.map(async (sourcePath) => {
try {
await access(sourcePath)
} catch {
logger.info(`No subscribers to load from ${sourcePath}. skipped.`)
return
}
return await this.createMap(sourcePath)
})
await promiseAll(promises)
await super.discoverResources()
for (const [
fileName,
@@ -0,0 +1,101 @@
import { dynamicImport, promiseAll, readDirRecursive } from "@medusajs/utils"
import { Dirent } from "fs"
import { access } from "fs/promises"
import { join, parse } from "path"
import { logger } from "../logger"
export abstract class ResourceLoader {
/**
* The name of the resource (e.g job, subscriber, workflow)
*/
protected abstract resourceName: string
/**
* The directory from which to load the jobs
* @private
*/
#sourceDir: string | string[]
/**
* The list of file names to exclude from the subscriber scan
* @private
*/
#excludes: RegExp[] = [/^_[^/\\]*(\.[^/\\]+)?$/]
constructor(sourceDir: string | string[]) {
this.#sourceDir = sourceDir
}
/**
* Discover resources from the source directory
* @param exclude - custom exclusion regexes
* @param customFiltering - custom filtering function
* @returns The resources discovered
*/
protected async discoverResources({
exclude,
customFiltering,
}: {
exclude?: RegExp[]
customFiltering?: (entry: Dirent) => boolean
} = {}): Promise<Record<string, unknown>[]> {
exclude ??= []
customFiltering ??= (entry: Dirent) => {
const parsedName = parse(entry.name)
return (
!entry.isDirectory() &&
parsedName.name !== "index" &&
!parsedName.base.endsWith(".d.ts") &&
[".js", ".ts"].includes(parsedName.ext) &&
!this.#excludes.some((exclude) => exclude.test(parsedName.base)) &&
!exclude.some((exclude) => exclude.test(parsedName.base))
)
}
const normalizedSourcePath = Array.isArray(this.#sourceDir)
? this.#sourceDir
: [this.#sourceDir]
const promises = normalizedSourcePath.map(async (sourcePath) => {
try {
await access(sourcePath)
} catch {
logger.info(
`No ${this.resourceName} to load from ${sourcePath}. skipped.`
)
return
}
return await readDirRecursive(sourcePath).then(async (entries) => {
const fileEntries = entries.filter((entry: Dirent) =>
customFiltering(entry)
)
return await promiseAll(
fileEntries.map(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
const module_ = await dynamicImport(fullPath)
await this.onFileLoaded(fullPath, module_)
return module_
})
)
})
})
const resources = await promiseAll(promises)
return resources.flat()
}
/**
* Called when a file is imported
* @param path - The path of the file
* @param fileExports - The exports of the file
*/
protected abstract onFileLoaded(
path: string,
fileExports: Record<string, unknown>
): Promise<void> | never
}
@@ -1,30 +1,18 @@
import { dynamicImport, promiseAll, readDirRecursive } from "@medusajs/utils"
import { Dirent } from "fs"
import { access } from "fs/promises"
import { join } from "path"
import { logger } from "../logger"
import { ResourceLoader } from "../utils/resource-loader"
export class WorkflowLoader {
/**
* The directory from which to load the workflows
* @private
*/
#sourceDir: string | string[]
/**
* The list of file names to exclude from the subscriber scan
* @private
*/
#excludes: RegExp[] = [
/index\.js/,
/index\.ts/,
/\.DS_Store/,
/(\.ts\.map|\.js\.map|\.d\.ts|\.md)/,
/^_[^/\\]*(\.[^/\\]+)?$/,
]
export class WorkflowLoader extends ResourceLoader {
protected resourceName = "workflow"
constructor(sourceDir: string | string[]) {
this.#sourceDir = sourceDir
super(sourceDir)
}
protected async onFileLoaded(
path: string,
fileExports: Record<string, unknown>
) {
logger.debug(`Registering workflows from ${path}.`)
}
/**
@@ -32,38 +20,7 @@ export class WorkflowLoader {
* therefore we only need to import them
*/
async load() {
const normalizedSourcePath = Array.isArray(this.#sourceDir)
? this.#sourceDir
: [this.#sourceDir]
const promises = normalizedSourcePath.map(async (sourcePath) => {
try {
await access(sourcePath)
} catch {
logger.info(`No workflow to load from ${sourcePath}. skipped.`)
return
}
return await readDirRecursive(sourcePath).then(async (entries) => {
const fileEntries = entries.filter((entry: Dirent) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(entry.name))
)
})
logger.debug(`Registering workflows from ${sourcePath}.`)
return await promiseAll(
fileEntries.map(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
return await dynamicImport(fullPath)
})
)
})
})
await promiseAll(promises)
await super.discoverResources()
logger.debug(`Workflows registered.`)
}
+7
View File
@@ -1,5 +1,12 @@
# @medusajs/js-sdk
## 2.6.0
### Patch Changes
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76)]:
- @medusajs/types@2.6.0
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/js-sdk",
"version": "2.5.1",
"version": "2.6.0",
"description": "SDK for the Medusa API",
"main": "dist/index.js",
"module": "dist/esm/index.js",
@@ -35,7 +35,7 @@
"typescript": "^5.6.2"
},
"dependencies": {
"@medusajs/types": "^2.5.1",
"@medusajs/types": "^2.6.0",
"fetch-event-stream": "^0.1.5",
"qs": "^6.12.1"
},
+9
View File
@@ -1,5 +1,14 @@
# @medusajs/modules-sdk
## 2.6.0
### Patch Changes
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031)]:
- @medusajs/types@2.6.0
- @medusajs/utils@2.6.0
- @medusajs/orchestration@2.6.0
## 2.5.1
### Patch Changes
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/modules-sdk",
"version": "2.5.1",
"version": "2.6.0",
"description": "SDK for medusa modules",
"main": "dist/index.js",
"export": {
@@ -45,9 +45,9 @@
"typescript": "^5.6.2"
},
"dependencies": {
"@medusajs/orchestration": "^2.5.1",
"@medusajs/types": "^2.5.1",
"@medusajs/utils": "^2.5.1"
"@medusajs/orchestration": "^2.6.0",
"@medusajs/types": "^2.6.0",
"@medusajs/utils": "^2.6.0"
},
"peerDependencies": {
"@mikro-orm/core": "6.4.3",
+8
View File
@@ -1,5 +1,13 @@
# @medusajs/orchestration
## 2.6.0
### Patch Changes
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031)]:
- @medusajs/types@2.6.0
- @medusajs/utils@2.6.0
## 2.5.1
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/orchestration",
"version": "2.5.1",
"version": "2.6.0",
"description": "Medusa utilities to orchestrate modules",
"main": "dist/index.js",
"exports": {
@@ -39,8 +39,8 @@
"typescript": "^5.6.2"
},
"dependencies": {
"@medusajs/types": "^2.5.1",
"@medusajs/utils": "^2.5.1"
"@medusajs/types": "^2.6.0",
"@medusajs/utils": "^2.6.0"
},
"peerDependencies": {
"@mikro-orm/core": "6.4.3",
+18
View File
@@ -1,5 +1,23 @@
# @medusajs/types
## 2.6.0
### Patch Changes
- [#11604](https://github.com/medusajs/medusa/pull/11604) [`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(types, medusa): remove fulfillment and payment status filters from validator + http types
- [#11597](https://github.com/medusajs/medusa/pull/11597) [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261) Thanks [@shahednasser](https://github.com/shahednasser)! - chore(types): change payment provider types to interfaces
- [#11692](https://github.com/medusajs/medusa/pull/11692) [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907) Thanks [@riqwan](https://github.com/riqwan)! - fix(types,medusa): calculate taxes for original price
- [#11226](https://github.com/medusajs/medusa/pull/11226) [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9) Thanks [@bouazzaayyoub](https://github.com/bouazzaayyoub)! - fix: add additionl data to product categories hook
- [#11666](https://github.com/medusajs/medusa/pull/11666) [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Improve cart update line items
- [#11581](https://github.com/medusajs/medusa/pull/11581) [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(types): Allow providing either vite@5 or vite@6 for the peer dependency
- [#11601](https://github.com/medusajs/medusa/pull/11601) [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Improve internal repository delete algo
## 2.5.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/types",
"version": "2.5.1",
"version": "2.6.0",
"description": "Medusa Types definition",
"main": "dist/index.js",
"types": "dist/index.d.ts",
+17
View File
@@ -1,5 +1,22 @@
# @medusajs/utils
## 2.6.0
### Patch Changes
- [#11585](https://github.com/medusajs/medusa/pull/11585) [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(product): Remove upsertWithReplace where needed
- [#11636](https://github.com/medusajs/medusa/pull/11636) [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Add support for extra pool configuration
- [#11618](https://github.com/medusajs/medusa/pull/11618) [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Improve cascade soft deletetion and update
- [#11601](https://github.com/medusajs/medusa/pull/11601) [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Improve internal repository delete algo
- [#11693](https://github.com/medusajs/medusa/pull/11693) [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031) Thanks [@riqwan](https://github.com/riqwan)! - feat(utils): add error message when manager is not found
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76)]:
- @medusajs/types@2.6.0
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/utils",
"version": "2.5.1",
"version": "2.6.0",
"description": "Medusa utilities functions shared by Medusa core and Modules",
"main": "dist/index.js",
"exports": {
@@ -47,7 +47,7 @@
"@graphql-codegen/typescript": "^4.0.9",
"@graphql-tools/merge": "^9.0.7",
"@graphql-tools/schema": "^10.0.6",
"@medusajs/types": "^2.5.1",
"@medusajs/types": "^2.6.0",
"@types/pluralize": "^0.0.33",
"bignumber.js": "^9.1.2",
"dotenv": "^16.4.5",
+12
View File
@@ -1,5 +1,17 @@
# @medusajs/workflows-sdk
## 2.6.0
### Patch Changes
- [#11641](https://github.com/medusajs/medusa/pull/11641) [`c250de79192bda1b1cd217bcca37f458c693de1d`](https://github.com/medusajs/medusa/commit/c250de79192bda1b1cd217bcca37f458c693de1d) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(): Prevent sub workflow events release early + redis unlink
- Updated dependencies [[`8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125`](https://github.com/medusajs/medusa/commit/8bb0a25f573c62ca1d1bcd7af184b0d0cf98e125), [`698a520729a3045cd13eed5ee0e5120a563e9261`](https://github.com/medusajs/medusa/commit/698a520729a3045cd13eed5ee0e5120a563e9261), [`51b0af193c7dde4899a696a515b59373b465d907`](https://github.com/medusajs/medusa/commit/51b0af193c7dde4899a696a515b59373b465d907), [`eeebb35758ea443468dd2355a7ea761dfe24babc`](https://github.com/medusajs/medusa/commit/eeebb35758ea443468dd2355a7ea761dfe24babc), [`93cbc6b6695f236fa39b66169de971228888f1b9`](https://github.com/medusajs/medusa/commit/93cbc6b6695f236fa39b66169de971228888f1b9), [`d1efad9bf05ca80959e8b50d74b74167fc1b0064`](https://github.com/medusajs/medusa/commit/d1efad9bf05ca80959e8b50d74b74167fc1b0064), [`ca6a15717d05de112ca00ca56d65beb2ab0f2598`](https://github.com/medusajs/medusa/commit/ca6a15717d05de112ca00ca56d65beb2ab0f2598), [`d814d9540e76256be23d733b73cf5a63aa380c8b`](https://github.com/medusajs/medusa/commit/d814d9540e76256be23d733b73cf5a63aa380c8b), [`d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30`](https://github.com/medusajs/medusa/commit/d254b2ddba3fba4fb60e1076a6bc4e7d425bbd30), [`b42f151be31161a5d7a73132ee6794b990403d76`](https://github.com/medusajs/medusa/commit/b42f151be31161a5d7a73132ee6794b990403d76), [`ab96ad3b8213b117b067ae0ab66b94f74b8bd031`](https://github.com/medusajs/medusa/commit/ab96ad3b8213b117b067ae0ab66b94f74b8bd031)]:
- @medusajs/types@2.6.0
- @medusajs/utils@2.6.0
- @medusajs/modules-sdk@2.6.0
- @medusajs/orchestration@2.6.0
## 2.5.1
### Patch Changes
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/workflows-sdk",
"version": "2.5.1",
"version": "2.6.0",
"description": "Set of workflows tooling for Medusa",
"main": "dist/index.js",
"exports": {
@@ -40,10 +40,10 @@
"typescript": "^5.6.2"
},
"dependencies": {
"@medusajs/modules-sdk": "^2.5.1",
"@medusajs/orchestration": "^2.5.1",
"@medusajs/types": "^2.5.1",
"@medusajs/utils": "^2.5.1",
"@medusajs/modules-sdk": "^2.6.0",
"@medusajs/orchestration": "^2.6.0",
"@medusajs/types": "^2.6.0",
"@medusajs/utils": "^2.6.0",
"ulid": "^2.3.0"
},
"peerDependencies": {
@@ -1,5 +1,7 @@
# @medusajs/icons
## 2.6.0
## 2.5.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@medusajs/icons",
"version": "2.5.1",
"version": "2.6.0",
"description": "Medusa UI React icon library",
"author": "Kasper Kristensen <kasper@medusajs.com>",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"devDependencies": {
"@atomico/rollup-plugin-sizes": "^1.1.4",
"@medusajs/toolbox": "^2.5.1",
"@medusajs/toolbox": "^2.6.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@rollup/plugin-replace": "^5.0.2",
"@testing-library/dom": "^9.3.1",
@@ -1,5 +1,7 @@
# @medusajs/toolbox
## 2.6.0
## 2.5.1
## 2.5.0
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@medusajs/toolbox",
"private": true,
"version": "2.5.1",
"version": "2.6.0",
"description": "CLI tool for importing Figma designs for Medusa UI",
"license": "MIT",
"author": "Kasper Kristensen <kasper@medusajs.com>",
@@ -1,5 +1,7 @@
# @medusajs/ui-preset
## 2.6.0
## 2.5.1
## 2.5.0
@@ -1,6 +1,6 @@
{
"name": "@medusajs/ui-preset",
"version": "2.5.1",
"version": "2.6.0",
"description": "Medusa UI preset",
"license": "MIT",
"repository": {
@@ -30,7 +30,7 @@
"tailwindcss": ">=3.0.0"
},
"devDependencies": {
"@medusajs/toolbox": "^2.5.1",
"@medusajs/toolbox": "^2.6.0",
"tailwindcss": "^3.4.1",
"tsup": "^7.1.0",
"typescript": "^5.1.6"
Loaded 100 of 880 files, more files were not shown because too many files have changed in this diff. Show more