@csbeker/medusa-product-attributes 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/.medusa/server/src/admin/index.js +9012 -0
  2. package/.medusa/server/src/admin/index.mjs +9010 -0
  3. package/.medusa/server/src/api/admin/middlewares.js +10 -0
  4. package/.medusa/server/src/api/admin/plugin/attribute-set/[id]/attributes/route.js +17 -0
  5. package/.medusa/server/src/api/admin/plugin/attribute-set/[id]/route.js +33 -0
  6. package/.medusa/server/src/api/admin/plugin/attribute-set/middlewares.js +44 -0
  7. package/.medusa/server/src/api/admin/plugin/attribute-set/query-config.js +22 -0
  8. package/.medusa/server/src/api/admin/plugin/attribute-set/route.js +25 -0
  9. package/.medusa/server/src/api/admin/plugin/attribute-set/validators.js +37 -0
  10. package/.medusa/server/src/api/admin/plugin/attributes/[id]/route.js +68 -0
  11. package/.medusa/server/src/api/admin/plugin/attributes/[id]/values/[valueId]/route.js +37 -0
  12. package/.medusa/server/src/api/admin/plugin/attributes/[id]/values/route.js +31 -0
  13. package/.medusa/server/src/api/admin/plugin/attributes/middlewares.js +103 -0
  14. package/.medusa/server/src/api/admin/plugin/attributes/query-config.js +41 -0
  15. package/.medusa/server/src/api/admin/plugin/attributes/route.js +28 -0
  16. package/.medusa/server/src/api/admin/plugin/attributes/validators.js +69 -0
  17. package/.medusa/server/src/api/admin/plugin/route.js +7 -0
  18. package/.medusa/server/src/api/middlewares.js +12 -0
  19. package/.medusa/server/src/api/store/middlewares.js +8 -0
  20. package/.medusa/server/src/api/store/plugin/attributes/middlewares.js +64 -0
  21. package/.medusa/server/src/api/store/plugin/attributes/products/middlewares.js +100 -0
  22. package/.medusa/server/src/api/store/plugin/attributes/products/query-config.js +20 -0
  23. package/.medusa/server/src/api/store/plugin/attributes/products/route.js +48 -0
  24. package/.medusa/server/src/api/store/plugin/attributes/products/validators.js +39 -0
  25. package/.medusa/server/src/api/store/plugin/attributes/query-config.js +21 -0
  26. package/.medusa/server/src/api/store/plugin/attributes/route.js +15 -0
  27. package/.medusa/server/src/api/store/plugin/attributes/validators.js +14 -0
  28. package/.medusa/server/src/api/store/plugin/route.js +7 -0
  29. package/.medusa/server/src/api/utils/common-validators.js +23 -0
  30. package/.medusa/server/src/api/utils/constants.js +6 -0
  31. package/.medusa/server/src/api/utils/middlewares.js +34 -0
  32. package/.medusa/server/src/links/attribute-product-category.js +16 -0
  33. package/.medusa/server/src/links/attribute-value-product.js +16 -0
  34. package/.medusa/server/src/modules/attribute/events/index.js +8 -0
  35. package/.medusa/server/src/modules/attribute/index.js +13 -0
  36. package/.medusa/server/src/modules/attribute/migrations/Migration20250319161229.js +24 -0
  37. package/.medusa/server/src/modules/attribute/migrations/Migration20250320182643.js +16 -0
  38. package/.medusa/server/src/modules/attribute/migrations/Migration20250321162638.js +14 -0
  39. package/.medusa/server/src/modules/attribute/migrations/Migration20250505144933.js +23 -0
  40. package/.medusa/server/src/modules/attribute/migrations/Migration20250505201747.js +21 -0
  41. package/.medusa/server/src/modules/attribute/migrations/Migration20250506162300.js +14 -0
  42. package/.medusa/server/src/modules/attribute/migrations/Migration20250611160552.js +14 -0
  43. package/.medusa/server/src/modules/attribute/migrations/Migration20250611173345.js +16 -0
  44. package/.medusa/server/src/modules/attribute/migrations/Migration20250612192857.js +16 -0
  45. package/.medusa/server/src/modules/attribute/models/attribute-possible-value.js +24 -0
  46. package/.medusa/server/src/modules/attribute/models/attribute-set.js +22 -0
  47. package/.medusa/server/src/modules/attribute/models/attribute-value.js +17 -0
  48. package/.medusa/server/src/modules/attribute/models/attribute.js +27 -0
  49. package/.medusa/server/src/modules/attribute/service.js +84 -0
  50. package/.medusa/server/src/modules/attribute/types/attribute/common.js +13 -0
  51. package/.medusa/server/src/modules/attribute/types/attribute/index.js +18 -0
  52. package/.medusa/server/src/modules/attribute/types/attribute-set/index.js +18 -0
  53. package/.medusa/server/src/modules/attribute/types/attribute-set/mutations.js +3 -0
  54. package/.medusa/server/src/modules/attribute/types/attribute-value/index.js +18 -0
  55. package/.medusa/server/src/modules/attribute/types/attribute-value/mutations.js +3 -0
  56. package/.medusa/server/src/modules/attribute/types/index.js +20 -0
  57. package/.medusa/server/src/types/attribute/common.js +3 -0
  58. package/.medusa/server/src/types/attribute/http/attribute/admin/index.js +3 -0
  59. package/.medusa/server/src/types/attribute/http/attribute/index.js +18 -0
  60. package/.medusa/server/src/types/attribute/http/attribute-set/index.js +3 -0
  61. package/.medusa/server/src/types/attribute/http/index.js +19 -0
  62. package/.medusa/server/src/types/attribute/index.js +19 -0
  63. package/.medusa/server/src/utils/index.js +18 -0
  64. package/.medusa/server/src/utils/products-created-handler.js +22 -0
  65. package/.medusa/server/src/utils/products-updated-handler.js +58 -0
  66. package/.medusa/server/src/utils/validate-attribute-values-to-link.js +43 -0
  67. package/.medusa/server/src/workflows/attribute/index.js +19 -0
  68. package/.medusa/server/src/workflows/attribute/steps/create-attribute-possible-values.js +18 -0
  69. package/.medusa/server/src/workflows/attribute/steps/create-attributes.js +27 -0
  70. package/.medusa/server/src/workflows/attribute/steps/delete-attribute.js +31 -0
  71. package/.medusa/server/src/workflows/attribute/steps/index.js +21 -0
  72. package/.medusa/server/src/workflows/attribute/steps/update-attributes.js +34 -0
  73. package/.medusa/server/src/workflows/attribute/workflows/create-attribute-possible-values.js +11 -0
  74. package/.medusa/server/src/workflows/attribute/workflows/create-attributes.js +46 -0
  75. package/.medusa/server/src/workflows/attribute/workflows/delete-attribute.js +10 -0
  76. package/.medusa/server/src/workflows/attribute/workflows/index.js +20 -0
  77. package/.medusa/server/src/workflows/attribute/workflows/update-attributes.js +73 -0
  78. package/.medusa/server/src/workflows/attribute-set/steps/batch-link-attribute-set-attributes.js +66 -0
  79. package/.medusa/server/src/workflows/attribute-set/steps/create-attribute-set.js +24 -0
  80. package/.medusa/server/src/workflows/attribute-set/steps/index.js +20 -0
  81. package/.medusa/server/src/workflows/attribute-set/steps/update-attribute-set.js +22 -0
  82. package/.medusa/server/src/workflows/attribute-set/workflows/batch-link-attribute-set-attributes.js +10 -0
  83. package/.medusa/server/src/workflows/attribute-set/workflows/create-attribute-set.js +11 -0
  84. package/.medusa/server/src/workflows/attribute-set/workflows/index.js +20 -0
  85. package/.medusa/server/src/workflows/attribute-set/workflows/update-attribute-set.js +10 -0
  86. package/.medusa/server/src/workflows/attribute-value/steps/create-attribute-value.js +18 -0
  87. package/.medusa/server/src/workflows/attribute-value/steps/delete-attribute-value.js +18 -0
  88. package/.medusa/server/src/workflows/attribute-value/steps/index.js +20 -0
  89. package/.medusa/server/src/workflows/attribute-value/steps/validate-attribute-value.js +53 -0
  90. package/.medusa/server/src/workflows/attribute-value/workflow/create-attribute-value.js +28 -0
  91. package/.medusa/server/src/workflows/attribute-value/workflow/delete-attribute-value.js +38 -0
  92. package/.medusa/server/src/workflows/attribute-value/workflow/index.js +19 -0
  93. package/.medusa/server/src/workflows/attribute_possible_value/index.js +19 -0
  94. package/.medusa/server/src/workflows/attribute_possible_value/steps/index.js +18 -0
  95. package/.medusa/server/src/workflows/attribute_possible_value/steps/update-attribute-possible-value.js +18 -0
  96. package/.medusa/server/src/workflows/attribute_possible_value/workflows/index.js +18 -0
  97. package/.medusa/server/src/workflows/attribute_possible_value/workflows/update-attribute-possible-value.js +11 -0
  98. package/.medusa/server/src/workflows/index.js +18 -0
  99. package/CHANGELOG.md +104 -0
  100. package/README.md +86 -0
  101. package/package.json +90 -0
  102. package/src/admin/README.md +31 -0
  103. package/src/admin/components/metadata-editor/index.tsx +101 -0
  104. package/src/admin/components/section-row.tsx +41 -0
  105. package/src/admin/hooks/api/attribute-set.ts +122 -0
  106. package/src/admin/hooks/api/attributes.ts +126 -0
  107. package/src/admin/hooks/table/columns/index.ts +1 -0
  108. package/src/admin/hooks/table/columns/use-attribute-table-columns.tsx +280 -0
  109. package/src/admin/layouts/single-column.tsx +11 -0
  110. package/src/admin/lib/config.ts +8 -0
  111. package/src/admin/lib/query-key-factory.ts +53 -0
  112. package/src/admin/routes/attributes/[id]/edit/page.tsx +133 -0
  113. package/src/admin/routes/attributes/[id]/edit-possible-value/page.tsx +174 -0
  114. package/src/admin/routes/attributes/[id]/page.tsx +127 -0
  115. package/src/admin/routes/attributes/components/AttributeForm.tsx +301 -0
  116. package/src/admin/routes/attributes/components/AttributeSetTable.tsx +108 -0
  117. package/src/admin/routes/attributes/components/category-selection-modal.tsx +82 -0
  118. package/src/admin/routes/attributes/components/possible-values-table.tsx +119 -0
  119. package/src/admin/routes/attributes/create/components/MultiSelectCategory.tsx +148 -0
  120. package/src/admin/routes/attributes/create/components/PossibleValuesList.tsx +151 -0
  121. package/src/admin/routes/attributes/create/page.tsx +123 -0
  122. package/src/admin/routes/attributes/create-set/page.tsx +110 -0
  123. package/src/admin/routes/attributes/page.tsx +346 -0
  124. package/src/admin/routes/attributes/set/[id]/attributes/page.tsx +35 -0
  125. package/src/admin/routes/attributes/set/[id]/components/AttributeSetAttributesSection.tsx +114 -0
  126. package/src/admin/routes/attributes/set/[id]/components/AttributeSetGeneralSection.tsx +42 -0
  127. package/src/admin/routes/attributes/set/[id]/components/attribute-set-attributes-form.tsx +143 -0
  128. package/src/admin/routes/attributes/set/[id]/components/index.ts +2 -0
  129. package/src/admin/routes/attributes/set/[id]/edit/page.tsx +119 -0
  130. package/src/admin/routes/attributes/set/[id]/page.tsx +45 -0
  131. package/src/admin/tsconfig.json +27 -0
  132. package/src/admin/types/global.d.ts +3 -0
  133. package/src/admin/vite-env.d.ts +1 -0
  134. package/src/api/README.md +133 -0
  135. package/src/api/admin/middlewares.ts +8 -0
  136. package/src/api/admin/plugin/attribute-set/[id]/attributes/route.ts +17 -0
  137. package/src/api/admin/plugin/attribute-set/[id]/route.ts +41 -0
  138. package/src/api/admin/plugin/attribute-set/middlewares.ts +42 -0
  139. package/src/api/admin/plugin/attribute-set/query-config.ts +20 -0
  140. package/src/api/admin/plugin/attribute-set/route.ts +34 -0
  141. package/src/api/admin/plugin/attribute-set/validators.ts +45 -0
  142. package/src/api/admin/plugin/attributes/[id]/route.ts +85 -0
  143. package/src/api/admin/plugin/attributes/[id]/values/[valueId]/route.ts +41 -0
  144. package/src/api/admin/plugin/attributes/[id]/values/route.ts +39 -0
  145. package/src/api/admin/plugin/attributes/middlewares.ts +91 -0
  146. package/src/api/admin/plugin/attributes/query-config.ts +42 -0
  147. package/src/api/admin/plugin/attributes/route.ts +33 -0
  148. package/src/api/admin/plugin/attributes/validators.ts +91 -0
  149. package/src/api/admin/plugin/route.ts +8 -0
  150. package/src/api/middlewares.ts +10 -0
  151. package/src/api/store/middlewares.ts +6 -0
  152. package/src/api/store/plugin/attributes/middlewares.ts +33 -0
  153. package/src/api/store/plugin/attributes/products/middlewares.ts +73 -0
  154. package/src/api/store/plugin/attributes/products/query-config.ts +19 -0
  155. package/src/api/store/plugin/attributes/products/route.ts +68 -0
  156. package/src/api/store/plugin/attributes/products/validators.ts +55 -0
  157. package/src/api/store/plugin/attributes/query-config.ts +19 -0
  158. package/src/api/store/plugin/attributes/route.ts +13 -0
  159. package/src/api/store/plugin/attributes/validators.ts +14 -0
  160. package/src/api/store/plugin/route.ts +8 -0
  161. package/src/api/utils/common-validators.ts +24 -0
  162. package/src/api/utils/constants.ts +2 -0
  163. package/src/api/utils/middlewares.ts +31 -0
  164. package/src/jobs/README.md +36 -0
  165. package/src/links/README.md +26 -0
  166. package/src/links/attribute-product-category.ts +14 -0
  167. package/src/links/attribute-value-product.ts +14 -0
  168. package/src/modules/README.md +116 -0
  169. package/src/modules/attribute/events/index.ts +4 -0
  170. package/src/modules/attribute/index.ts +8 -0
  171. package/src/modules/attribute/migrations/.snapshot-medusa-attribute.json +624 -0
  172. package/src/modules/attribute/migrations/Migration20250319161229.ts +27 -0
  173. package/src/modules/attribute/migrations/Migration20250320182643.ts +15 -0
  174. package/src/modules/attribute/migrations/Migration20250321162638.ts +13 -0
  175. package/src/modules/attribute/migrations/Migration20250505144933.ts +26 -0
  176. package/src/modules/attribute/migrations/Migration20250505201747.ts +23 -0
  177. package/src/modules/attribute/migrations/Migration20250506162300.ts +13 -0
  178. package/src/modules/attribute/migrations/Migration20250611160552.ts +13 -0
  179. package/src/modules/attribute/migrations/Migration20250611173345.ts +17 -0
  180. package/src/modules/attribute/migrations/Migration20250612192857.ts +17 -0
  181. package/src/modules/attribute/models/attribute-possible-value.ts +20 -0
  182. package/src/modules/attribute/models/attribute-set.ts +18 -0
  183. package/src/modules/attribute/models/attribute-value.ts +13 -0
  184. package/src/modules/attribute/models/attribute.ts +23 -0
  185. package/src/modules/attribute/service.ts +102 -0
  186. package/src/modules/attribute/types/attribute/common.ts +94 -0
  187. package/src/modules/attribute/types/attribute/index.ts +1 -0
  188. package/src/modules/attribute/types/attribute-set/index.ts +1 -0
  189. package/src/modules/attribute/types/attribute-set/mutations.ts +7 -0
  190. package/src/modules/attribute/types/attribute-value/index.ts +1 -0
  191. package/src/modules/attribute/types/attribute-value/mutations.ts +5 -0
  192. package/src/modules/attribute/types/index.ts +3 -0
  193. package/src/providers/README.md +30 -0
  194. package/src/subscribers/README.md +59 -0
  195. package/src/types/attribute/common.ts +173 -0
  196. package/src/types/attribute/http/attribute/admin/index.ts +0 -0
  197. package/src/types/attribute/http/attribute/index.ts +42 -0
  198. package/src/types/attribute/http/attribute-set/index.ts +10 -0
  199. package/src/types/attribute/http/index.ts +2 -0
  200. package/src/types/attribute/index.ts +2 -0
  201. package/src/utils/index.ts +1 -0
  202. package/src/utils/products-created-handler.ts +35 -0
  203. package/src/utils/products-updated-handler.ts +74 -0
  204. package/src/utils/validate-attribute-values-to-link.ts +67 -0
  205. package/src/workflows/README.md +79 -0
  206. package/src/workflows/attribute/index.ts +2 -0
  207. package/src/workflows/attribute/steps/create-attribute-possible-values.ts +29 -0
  208. package/src/workflows/attribute/steps/create-attributes.ts +35 -0
  209. package/src/workflows/attribute/steps/delete-attribute.ts +41 -0
  210. package/src/workflows/attribute/steps/index.ts +4 -0
  211. package/src/workflows/attribute/steps/update-attributes.ts +45 -0
  212. package/src/workflows/attribute/workflows/create-attribute-possible-values.ts +17 -0
  213. package/src/workflows/attribute/workflows/create-attributes.ts +56 -0
  214. package/src/workflows/attribute/workflows/delete-attribute.ts +15 -0
  215. package/src/workflows/attribute/workflows/index.ts +3 -0
  216. package/src/workflows/attribute/workflows/update-attributes.ts +103 -0
  217. package/src/workflows/attribute-set/steps/batch-link-attribute-set-attributes.ts +82 -0
  218. package/src/workflows/attribute-set/steps/create-attribute-set.ts +34 -0
  219. package/src/workflows/attribute-set/steps/index.ts +3 -0
  220. package/src/workflows/attribute-set/steps/update-attribute-set.ts +32 -0
  221. package/src/workflows/attribute-set/workflows/batch-link-attribute-set-attributes.ts +12 -0
  222. package/src/workflows/attribute-set/workflows/create-attribute-set.ts +17 -0
  223. package/src/workflows/attribute-set/workflows/index.ts +3 -0
  224. package/src/workflows/attribute-set/workflows/update-attribute-set.ts +14 -0
  225. package/src/workflows/attribute-value/steps/create-attribute-value.ts +26 -0
  226. package/src/workflows/attribute-value/steps/delete-attribute-value.ts +26 -0
  227. package/src/workflows/attribute-value/steps/index.ts +3 -0
  228. package/src/workflows/attribute-value/steps/validate-attribute-value.ts +95 -0
  229. package/src/workflows/attribute-value/workflow/create-attribute-value.ts +36 -0
  230. package/src/workflows/attribute-value/workflow/delete-attribute-value.ts +46 -0
  231. package/src/workflows/attribute-value/workflow/index.ts +2 -0
  232. package/src/workflows/attribute_possible_value/index.ts +2 -0
  233. package/src/workflows/attribute_possible_value/steps/index.ts +1 -0
  234. package/src/workflows/attribute_possible_value/steps/update-attribute-possible-value.ts +25 -0
  235. package/src/workflows/attribute_possible_value/workflows/index.ts +1 -0
  236. package/src/workflows/attribute_possible_value/workflows/update-attribute-possible-value.ts +15 -0
  237. package/src/workflows/index.ts +1 -0
@@ -0,0 +1,39 @@
1
+ import { AdminCreateAttributeValueType, AdminGetAttributeValuesParamsType } from "../../validators";
2
+ import { MedusaRequest, MedusaResponse, refetchEntities, refetchEntity } from "@medusajs/framework";
3
+
4
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils";
5
+ import { createAttributePossibleValuesWorkflow } from "../../../../../../workflows/attribute/workflows/create-attribute-possible-values";
6
+
7
+ export const GET = async (req: MedusaRequest<AdminGetAttributeValuesParamsType>, res: MedusaResponse) => {
8
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
9
+
10
+ const { data: attributePossibleValues, metadata } = await query.graph({
11
+ entity: 'attribute_possible_value',
12
+ filters: {
13
+ attribute_id: req.params.id
14
+ },
15
+ ...req.queryConfig
16
+ })
17
+
18
+ res.status(200).json({ attributePossibleValues, count: metadata?.count, offset: metadata?.skip, limit: metadata?.take })
19
+ }
20
+
21
+ export const POST = async (req: MedusaRequest<AdminCreateAttributeValueType>, res: MedusaResponse) => {
22
+ const attributeId = req.params.id
23
+
24
+ const { result: [createdAttributeValue] } = await createAttributePossibleValuesWorkflow(req.scope).run({
25
+ input: [{
26
+ ...req.validatedBody,
27
+ attribute_id: attributeId
28
+ }]
29
+ })
30
+
31
+ const attributePossibleValue = await refetchEntity(
32
+ 'attribute_possible_value',
33
+ createdAttributeValue.id,
34
+ req.scope,
35
+ req.queryConfig.fields,
36
+ )
37
+
38
+ return res.status(201).json({ attributePossibleValue })
39
+ }
@@ -0,0 +1,91 @@
1
+ import { MiddlewareRoute, validateAndTransformBody, validateAndTransformQuery } from "@medusajs/framework";
2
+ import { AdminCreateAttribute, AdminCreateAttributeValue, AdminGetAttributeParams, AdminGetAttributesParams, AdminGetAttributeValueParams, AdminGetAttributeValuesParams, AdminUpdateAttribute, AdminUpdateAttributeValue } from "./validators";
3
+ import * as QueryConfig from './query-config'
4
+ import { adminAttributesRoutePath } from "../../../utils/constants";
5
+
6
+ export const adminAttributeRoutesMiddlewares: MiddlewareRoute[] = [
7
+ {
8
+ method: ['GET'],
9
+ matcher: adminAttributesRoutePath,
10
+ middlewares: [
11
+ validateAndTransformQuery(
12
+ AdminGetAttributesParams,
13
+ QueryConfig.listAttributeQueryConfig,
14
+ )
15
+ ]
16
+ },
17
+ {
18
+ method: ['POST'],
19
+ matcher: adminAttributesRoutePath,
20
+ middlewares: [
21
+ validateAndTransformBody(AdminCreateAttribute),
22
+ validateAndTransformQuery(
23
+ AdminGetAttributeParams,
24
+ QueryConfig.retrieveAttributeQueryConfig
25
+ )
26
+ ]
27
+ },
28
+ {
29
+ method: ['GET'],
30
+ matcher: `${adminAttributesRoutePath}/:id`,
31
+ middlewares: [
32
+ validateAndTransformQuery(
33
+ AdminGetAttributeParams,
34
+ QueryConfig.retrieveAttributeQueryConfig
35
+ )
36
+ ]
37
+ },
38
+ {
39
+ method: ['POST'],
40
+ matcher: `${adminAttributesRoutePath}/:id`,
41
+ middlewares: [
42
+ validateAndTransformBody(AdminUpdateAttribute),
43
+ validateAndTransformQuery(
44
+ AdminGetAttributeParams,
45
+ QueryConfig.retrieveAttributeQueryConfig
46
+ )
47
+ ]
48
+ },
49
+ {
50
+ method: ['GET'],
51
+ matcher: `${adminAttributesRoutePath}/:id/values`,
52
+ middlewares: [
53
+ validateAndTransformQuery(
54
+ AdminGetAttributeValuesParams,
55
+ QueryConfig.listAttributeValueQueryConfig,
56
+ )
57
+ ]
58
+ },
59
+ {
60
+ method: ['POST'],
61
+ matcher: `${adminAttributesRoutePath}/:id/values`,
62
+ middlewares: [
63
+ validateAndTransformBody(AdminCreateAttributeValue),
64
+ validateAndTransformQuery(
65
+ AdminGetAttributeValueParams,
66
+ QueryConfig.retrieveAttributeValueQueryConfig,
67
+ )
68
+ ]
69
+ },
70
+ {
71
+ method: ['GET'],
72
+ matcher: `${adminAttributesRoutePath}/:id/values/:valueId`,
73
+ middlewares: [
74
+ validateAndTransformQuery(
75
+ AdminGetAttributeValueParams,
76
+ QueryConfig.retrieveAttributeValueQueryConfig
77
+ )
78
+ ]
79
+ },
80
+ {
81
+ method: ['POST'],
82
+ matcher: `${adminAttributesRoutePath}/:id/values/:valueId`,
83
+ middlewares: [
84
+ validateAndTransformBody(AdminUpdateAttributeValue),
85
+ validateAndTransformQuery(
86
+ AdminGetAttributeValueParams,
87
+ QueryConfig.retrieveAttributeValueQueryConfig
88
+ )
89
+ ]
90
+ }
91
+ ]
@@ -0,0 +1,42 @@
1
+ export const defaultAdminAttributeFields = [
2
+ 'id',
3
+ 'name',
4
+ 'description',
5
+ 'is_variant_defining',
6
+ 'is_filterable',
7
+ 'handle',
8
+ 'ui_component',
9
+ 'metadata',
10
+ '*possible_values',
11
+ 'product_categories.id',
12
+ 'product_categories.name',
13
+ ]
14
+
15
+ export const retrieveAttributeQueryConfig = {
16
+ defaults: defaultAdminAttributeFields,
17
+ isList: false,
18
+ }
19
+
20
+ export const listAttributeQueryConfig = {
21
+ ...retrieveAttributeQueryConfig,
22
+ defaultLimit: 50,
23
+ isList: true,
24
+ }
25
+
26
+ export const defaultAdminAttributeValueFields = [
27
+ 'id',
28
+ 'value',
29
+ 'rank',
30
+ 'metadata',
31
+ ]
32
+
33
+ export const retrieveAttributeValueQueryConfig = {
34
+ defaults: defaultAdminAttributeValueFields,
35
+ isList: false,
36
+ }
37
+
38
+ export const listAttributeValueQueryConfig = {
39
+ ...retrieveAttributeValueQueryConfig,
40
+ isList: true,
41
+ defaultLimit: 50,
42
+ }
@@ -0,0 +1,33 @@
1
+ import { MedusaRequest, MedusaResponse, refetchEntities, refetchEntity } from "@medusajs/framework";
2
+ import { AdminCreateAttributeType, AdminGetAttributesParamsType } from "./validators";
3
+ import { createAttributesWorkflow } from "../../../../workflows";
4
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils";
5
+
6
+ export const GET = async (req: MedusaRequest<AdminGetAttributesParamsType>, res: MedusaResponse) => {
7
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
8
+ // TODO: check why, even though *product_categories is in default fields
9
+ // only the id is returned for each category
10
+ const { data: attributes, metadata } = await query.graph({
11
+ entity: 'attribute',
12
+ filters: req.filterableFields,
13
+ ...req.queryConfig
14
+ })
15
+ return res.status(200).json({ attributes, count: metadata?.count, offset: metadata?.skip, limit: metadata?.take })
16
+ }
17
+
18
+ export const POST = async (req: MedusaRequest<AdminCreateAttributeType>, res: MedusaResponse) => {
19
+ const attributeDto = req.validatedBody
20
+
21
+ const { result } = await createAttributesWorkflow(req.scope).run({
22
+ input: { attributes: [attributeDto] },
23
+ })
24
+
25
+ const attribute = await refetchEntity(
26
+ 'attribute',
27
+ result[0].id,
28
+ req.scope,
29
+ req.queryConfig?.fields ?? []
30
+ )
31
+
32
+ res.status(201).json({ attribute })
33
+ }
@@ -0,0 +1,91 @@
1
+ import { createFindParams, createOperatorMap, createSelectParams, WithAdditionalData } from '@medusajs/medusa/api/utils/validators'
2
+
3
+ import { z } from 'zod'
4
+ import { AttributeUIComponent } from '../../../../modules/attribute/types'
5
+ import { applyAndAndOrOperators } from '@medusajs/medusa/api/utils/common-validators/common'
6
+ import { GetAttributeSetsParams } from '../attribute-set/validators'
7
+
8
+ export type AdminGetAttributeValueParamsType = z.infer<typeof AdminGetAttributeValueParams>
9
+ export const AdminGetAttributeValueParams = createSelectParams()
10
+
11
+ export type AdminGetAttributeValuesParamsType = z.infer<typeof AdminGetAttributeValueParams>
12
+ export const AdminGetAttributeValuesParams = createFindParams()
13
+
14
+ export type AdminGetAttributeParamsType = z.infer<typeof AdminGetAttributeParams>
15
+ export const AdminGetAttributeParams = createSelectParams()
16
+
17
+ export const GetAttributesParams = z.object({
18
+ id: z.string().optional(),
19
+ name: z.string().optional(),
20
+ is_variant_defining: z.boolean().optional(),
21
+ is_filterable: z.boolean().optional(),
22
+ handle: z.string().optional(),
23
+ created_at: createOperatorMap().optional(),
24
+ updated_at: createOperatorMap().optional(),
25
+ deleted_at: createOperatorMap().optional(),
26
+ ui_component: z.nativeEnum(AttributeUIComponent).optional(),
27
+ sets: GetAttributeSetsParams.merge(
28
+ applyAndAndOrOperators(GetAttributeSetsParams)
29
+ ).optional()
30
+ })
31
+ export type AdminGetAttributesParamsType = z.infer<typeof AdminGetAttributesParams>
32
+ export const AdminGetAttributesParams = createFindParams({
33
+ offset: 0,
34
+ limit: 50,
35
+ })
36
+ .merge(applyAndAndOrOperators(GetAttributesParams))
37
+ .merge(GetAttributesParams)
38
+
39
+ export type AdminCreateAttributeValueType = z.infer<typeof AdminCreateAttributeValue>
40
+ export const AdminCreateAttributeValue = z.object({
41
+ value: z.string().min(1),
42
+ rank: z.number(),
43
+ metadata: z.record(z.unknown()).optional(),
44
+ })
45
+
46
+ export type AdminUpdateAttributeValueType = z.infer<typeof AdminUpdateAttributeValue>
47
+ export const AdminUpdateAttributeValue = z.object({
48
+ id: z.string().optional(),
49
+ value: z.string().optional(),
50
+ rank: z.number().optional(),
51
+ metadata: z.record(z.unknown()).nullish(),
52
+ })
53
+
54
+ export type AdminUpdateAttributeType = z.infer<typeof AdminUpdateAttribute>
55
+ export const AdminUpdateAttribute = z.object({
56
+ name: z.string().optional(),
57
+ description: z.string().optional(),
58
+ is_variant_defining: z.boolean().optional(),
59
+ is_filterable: z.boolean().optional(),
60
+ handle: z.string().nullish(),
61
+ metadata: z.record(z.unknown()).nullish(),
62
+ ui_component: z.nativeEnum(AttributeUIComponent).optional(),
63
+ product_category_ids: z.array(z.string()).nullish(),
64
+ possible_values: z.array(AdminUpdateAttributeValue).optional()
65
+ }).strict()
66
+
67
+ export type AdminCreateAttributeType = z.infer<typeof CreateAttribute>
68
+ export const CreateAttribute = z.object({
69
+ name: z.string().min(1),
70
+ description: z.string().optional(),
71
+ ui_component: z.nativeEnum(AttributeUIComponent).default(AttributeUIComponent.SELECT),
72
+ is_variant_defining: z.boolean().default(true),
73
+ is_filterable: z.boolean().default(true),
74
+ handle: z.string().optional(),
75
+ metadata: z.record(z.unknown()).nullish(),
76
+ possible_values: z.array(AdminCreateAttributeValue).optional(),
77
+ product_category_ids: z.array(z.string()).optional()
78
+ })
79
+
80
+ export const AdminCreateAttribute = WithAdditionalData(
81
+ CreateAttribute,
82
+ (schema) => {
83
+ return schema.refine(
84
+ (data) => data.ui_component !== AttributeUIComponent.SELECT || (data.possible_values && data.possible_values.length > 0),
85
+ {
86
+ message: "Possible values are required when ui_component is SELECT",
87
+ path: ["possible_values"]
88
+ }
89
+ )
90
+ }
91
+ )
@@ -0,0 +1,8 @@
1
+ import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
2
+
3
+ export async function GET(
4
+ req: MedusaRequest,
5
+ res: MedusaResponse
6
+ ) {
7
+ res.sendStatus(200);
8
+ }
@@ -0,0 +1,10 @@
1
+ import { defineMiddlewares } from "@medusajs/framework";
2
+ import { adminRoutesMiddlewares } from "./admin/middlewares";
3
+ import { storeMiddlewaresRoutes } from "./store/middlewares";
4
+
5
+ export default defineMiddlewares({
6
+ routes: [
7
+ ...adminRoutesMiddlewares,
8
+ ...storeMiddlewaresRoutes,
9
+ ]
10
+ })
@@ -0,0 +1,6 @@
1
+ import { MiddlewareRoute } from "@medusajs/framework";
2
+ import { storeAttributesMiddlewaresRoute } from "./plugin/attributes/middlewares";
3
+
4
+ export const storeMiddlewaresRoutes: MiddlewareRoute[] = [
5
+ ...storeAttributesMiddlewaresRoute
6
+ ]
@@ -0,0 +1,33 @@
1
+ import {
2
+ clearFiltersByKey,
3
+ maybeApplyLinkFilter,
4
+ MiddlewareRoute,
5
+ validateAndTransformQuery,
6
+ } from "@medusajs/framework";
7
+ import { storeAttributesBaseRoute } from "../../../utils/constants";
8
+ import { StoreGetAttributesParams } from "./validators";
9
+ import * as QueryConfig from "./query-config";
10
+ import { storeAttributesProductsMiddlewares } from "./products/middlewares";
11
+ import attributeProductCategory from "../../../../links/attribute-product-category";
12
+ import { addGlobalAttributesIfNecessary } from "../../../utils/middlewares";
13
+
14
+ export const storeAttributesMiddlewaresRoute: MiddlewareRoute[] = [
15
+ {
16
+ methods: ["GET"],
17
+ matcher: storeAttributesBaseRoute,
18
+ middlewares: [
19
+ validateAndTransformQuery(
20
+ StoreGetAttributesParams,
21
+ QueryConfig.storeListAttributesQueryConfig
22
+ ),
23
+ maybeApplyLinkFilter({
24
+ entryPoint: attributeProductCategory.entryPoint,
25
+ resourceId: 'attribute_id',
26
+ filterableField: 'product_category_id'
27
+ }),
28
+ addGlobalAttributesIfNecessary(),
29
+ clearFiltersByKey(['include_globals']),
30
+ ],
31
+ },
32
+ ...storeAttributesProductsMiddlewares,
33
+ ];
@@ -0,0 +1,73 @@
1
+ import { applyDefaultFilters, authenticate, clearFiltersByKey, maybeApplyLinkFilter, MiddlewareRoute, validateAndTransformQuery } from "@medusajs/framework";
2
+ import { FeatureFlag, ProductStatus, isPresent } from "@medusajs/framework/utils";
3
+ import { StoreGetProductsParams } from "@medusajs/medusa/api/store/products/validators";
4
+ import { filterByValidSalesChannels, normalizeDataForContext, setPricingContext, setTaxContext } from "@medusajs/medusa/api/utils/middlewares/index";
5
+ import * as OriginalQueryConfig from "@medusajs/medusa/api/store/products/query-config"
6
+ import { ExtendedStoreGetProductsParams } from "./validators";
7
+ import attributeValueProduct from "../../../../../links/attribute-value-product";
8
+
9
+ // TODO: Remove once https://github.com/medusajs/medusa/pull/13714 is merged and import instead
10
+ const IndexEngineFeatureFlag = {
11
+ key: "index_engine",
12
+ default_val: false,
13
+ env_key: "MEDUSA_FF_INDEX_ENGINE",
14
+ description: "Enable Medusa to use the index engine in some part of the core",
15
+ };
16
+
17
+ export const storeAttributesProductsMiddlewares: MiddlewareRoute[] = [
18
+ {
19
+ method: ["GET"],
20
+ matcher: "/store/plugin/attributes/products",
21
+ middlewares: [
22
+ authenticate("customer", ["session", "bearer"], {
23
+ allowUnauthenticated: true,
24
+ }),
25
+ validateAndTransformQuery(
26
+ ExtendedStoreGetProductsParams,
27
+ OriginalQueryConfig.listProductQueryConfig
28
+ ),
29
+ filterByValidSalesChannels(),
30
+ (req, res, next) => {
31
+ const canUseIndex = !(
32
+ isPresent(req.filterableFields.tags) ||
33
+ isPresent(req.filterableFields.categories)
34
+ )
35
+ if (
36
+ FeatureFlag.isFeatureEnabled(IndexEngineFeatureFlag.key) &&
37
+ canUseIndex
38
+ ) {
39
+ return next()
40
+ }
41
+
42
+ return maybeApplyLinkFilter({
43
+ entryPoint: "product_sales_channel",
44
+ resourceId: "product_id",
45
+ filterableField: "sales_channel_id",
46
+ })(req, res, next)
47
+ },
48
+ applyDefaultFilters({
49
+ status: ProductStatus.PUBLISHED,
50
+ // TODO: the type here seems off and the implementation does not take into account $and and $or possible filters. Might be worth re working (original type used here was StoreGetProductsParamsType)
51
+ categories: (filters: any, fields: string[]) => {
52
+ const categoryIds = filters.category_id
53
+ delete filters.category_id
54
+
55
+ if (!isPresent(categoryIds)) {
56
+ return
57
+ }
58
+
59
+ return { id: categoryIds, is_internal: false, is_active: true }
60
+ },
61
+ }),
62
+ maybeApplyLinkFilter({
63
+ entryPoint: attributeValueProduct.entryPoint,
64
+ filterableField: 'attribute_value_id',
65
+ resourceId: 'product_id'
66
+ }),
67
+ normalizeDataForContext(),
68
+ setPricingContext(),
69
+ setTaxContext(),
70
+ clearFiltersByKey(["region_id", "country_code", "province", "cart_id"]),
71
+ ],
72
+ },
73
+ ]
@@ -0,0 +1,19 @@
1
+ import { defaultStoreProductFields } from "@medusajs/medusa/api/store/products/query-config";
2
+
3
+ const defaultExtendedStoreProductFields = [
4
+ '*attribute_values',
5
+ ]
6
+
7
+ export const retrieveProductQueryConfig = {
8
+ defaults: [
9
+ ...defaultStoreProductFields,
10
+ ...defaultExtendedStoreProductFields
11
+ ],
12
+ isList: false,
13
+ }
14
+
15
+ export const listProductQueryConfig = {
16
+ ...retrieveProductQueryConfig,
17
+ isList: true,
18
+ defaultLimit: 50,
19
+ }
@@ -0,0 +1,68 @@
1
+ // TODO: This is messy, but since Medusa doesn't allow to extend Core GET routes
2
+ // params validators, the only way i see to query core routes with linked
3
+ // custom modules entities, is to recreate route (in a custom one) middleware and
4
+ // apply the custom params validator
5
+
6
+ import { MedusaResponse } from "@medusajs/framework";
7
+ import { HttpTypes } from "@medusajs/framework/types";
8
+ import { isPresent, ContainerRegistrationKeys, remoteQueryObjectFromString } from "@medusajs/framework/utils";
9
+ import { RequestWithContext, wrapProductsWithTaxPrices } from "@medusajs/medusa/api/store/products/helpers";
10
+ import { wrapVariantsWithInventoryQuantityForSalesChannel } from "@medusajs/medusa/api/utils/middlewares/index";
11
+ import { ExtendedStoreGetProductsParamsType } from "./validators";
12
+
13
+ export const GET = async (
14
+ req: RequestWithContext<ExtendedStoreGetProductsParamsType>,
15
+ res: MedusaResponse<HttpTypes.StoreProductListResponse>
16
+ ) => {
17
+ return await getProducts(req as any, res);
18
+ };
19
+
20
+ async function getProducts(
21
+ req: RequestWithContext<HttpTypes.StoreProductListParams>,
22
+ res: MedusaResponse<HttpTypes.StoreProductListResponse>
23
+ ) {
24
+ const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY);
25
+ const context: object = {};
26
+ const withInventoryQuantity = req.queryConfig.fields.some((field) =>
27
+ field.includes("variants.inventory_quantity")
28
+ );
29
+
30
+ if (withInventoryQuantity) {
31
+ req.queryConfig.fields = req.queryConfig.fields.filter(
32
+ (field) => !field.includes("variants.inventory_quantity")
33
+ );
34
+ }
35
+
36
+ if (isPresent(req.pricingContext)) {
37
+ context["variants.calculated_price"] = {
38
+ context: req.pricingContext,
39
+ };
40
+ }
41
+
42
+ const queryObject = remoteQueryObjectFromString({
43
+ entryPoint: "product",
44
+ variables: {
45
+ filters: req.filterableFields,
46
+ ...req.queryConfig.pagination,
47
+ ...context,
48
+ },
49
+ fields: req.queryConfig.fields,
50
+ });
51
+
52
+ const { rows: products, metadata } = await remoteQuery(queryObject);
53
+
54
+ if (withInventoryQuantity) {
55
+ await wrapVariantsWithInventoryQuantityForSalesChannel(
56
+ req,
57
+ products.map((product) => product.variants).flat(1)
58
+ );
59
+ }
60
+
61
+ await wrapProductsWithTaxPrices(req, products);
62
+ res.json({
63
+ products,
64
+ count: metadata.count,
65
+ offset: metadata.skip,
66
+ limit: metadata.take,
67
+ });
68
+ }
@@ -0,0 +1,55 @@
1
+ import {
2
+ StoreGetProductsParamsFields,
3
+ StoreGetProductVariantsParamsFields,
4
+ } from "@medusajs/medusa/api/store/products/validators";
5
+ import {
6
+ applyAndAndOrOperators,
7
+ recursivelyNormalizeSchema,
8
+ } from "@medusajs/medusa/api/utils/common-validators/common";
9
+ import {
10
+ StoreGetProductParamsDirectFields,
11
+ transformProductParams,
12
+ } from "@medusajs/medusa/api/utils/common-validators/index";
13
+ import { createFindParams } from "@medusajs/medusa/api/utils/validators";
14
+ import { z } from "zod";
15
+
16
+ //TODO: this is messy, but since Medusa exports an effect, the only way (AFAIK) to extend the schema
17
+ // and to keep the logic of the effects at the same time, the only way is to recreate
18
+ // the Medusa zod object, merge with the custom one and apply the effect
19
+ const OriginalStoreGetProductsParamsWithoutEffect = createFindParams({
20
+ offset: 0,
21
+ limit: 50,
22
+ })
23
+ .merge(StoreGetProductsParamsFields)
24
+ .merge(
25
+ z
26
+ .object({
27
+ variants: z
28
+ .object({
29
+ options: z
30
+ .object({
31
+ value: z.string().optional(),
32
+ option_id: z.string().optional(),
33
+ })
34
+ .optional(),
35
+ })
36
+ .merge(applyAndAndOrOperators(StoreGetProductVariantsParamsFields))
37
+ .optional(),
38
+ })
39
+ .merge(applyAndAndOrOperators(StoreGetProductParamsDirectFields))
40
+ .strict()
41
+ );
42
+
43
+ const CustomStoreGetProductsParams = z.object({
44
+ attribute_value_id: z.array(z.string()).optional(),
45
+ });
46
+
47
+ export type ExtendedStoreGetProductsParamsType = z.infer<
48
+ typeof OriginalStoreGetProductsParamsWithoutEffect
49
+ >;
50
+ export const ExtendedStoreGetProductsParams =
51
+ OriginalStoreGetProductsParamsWithoutEffect.merge(
52
+ CustomStoreGetProductsParams
53
+ )
54
+ // .merge(applyAndAndOrOperators(CustomStoreGetProductsParams))
55
+ .transform(recursivelyNormalizeSchema(transformProductParams));
@@ -0,0 +1,19 @@
1
+ export const storeDefaultAttributeFields = [
2
+ 'id',
3
+ 'name',
4
+ 'description',
5
+ 'handle',
6
+ 'metadata',
7
+ '*possible_values',
8
+ ]
9
+
10
+ export const retrieveStoreAttributesQueryConfig = {
11
+ defaults: storeDefaultAttributeFields,
12
+ isList: false,
13
+ }
14
+
15
+ export const storeListAttributesQueryConfig = {
16
+ ...retrieveStoreAttributesQueryConfig,
17
+ isList: true,
18
+ defaultLimit: 50,
19
+ }
@@ -0,0 +1,13 @@
1
+ import { MedusaRequest, MedusaResponse } from "@medusajs/framework";
2
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils";
3
+ import { StoreGetAttributesParamsType } from "./validators";
4
+
5
+ export const GET = async (req: MedusaRequest<StoreGetAttributesParamsType>, res: MedusaResponse) => {
6
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
7
+ const { data: attributes, metadata } = await query.graph({
8
+ entity: 'attribute',
9
+ ...req.queryConfig,
10
+ filters: req.filterableFields,
11
+ })
12
+ return res.status(200).json({ attributes, count: metadata?.count, limit: metadata?.take, offset: metadata?.skip })
13
+ }
@@ -0,0 +1,14 @@
1
+ import { createFindParams } from "@medusajs/medusa/api/utils/validators";
2
+ import { z } from "zod";
3
+ import { GetAttributesParams, StoreGetAttributeParamsDirectFields } from "../../../utils/common-validators";
4
+ import { applyAndAndOrOperators } from "@medusajs/medusa/api/utils/common-validators/common";
5
+
6
+ export const StoreGetAttributesParamsFields = GetAttributesParams.strict();
7
+
8
+ export type StoreGetAttributesParamsType = z.infer<typeof StoreGetAttributesParams>
9
+ export const StoreGetAttributesParams = createFindParams({
10
+ offset: 0,
11
+ limit: 50,
12
+ })
13
+ .merge(StoreGetAttributesParamsFields)
14
+ .merge(applyAndAndOrOperators(StoreGetAttributeParamsDirectFields).strict());
@@ -0,0 +1,8 @@
1
+ import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
2
+
3
+ export async function GET(
4
+ req: MedusaRequest,
5
+ res: MedusaResponse
6
+ ) {
7
+ res.sendStatus(200);
8
+ }
@@ -0,0 +1,24 @@
1
+ import { createOperatorMap } from '@medusajs/medusa/api/utils/validators'
2
+ import { z } from 'zod'
3
+
4
+ export const StoreGetAttributeParamsDirectFields = z.object({
5
+ id: z.union([z.string(), z.array(z.string())]).optional(),
6
+ name: z.union([z.string(), z.array(z.string())]).optional(),
7
+ description: z.union([z.string(), z.array(z.string())]).optional(),
8
+ handle: z.union([z.string(), z.array(z.string())]).optional(),
9
+ created_at: createOperatorMap().optional(),
10
+ updated_at: createOperatorMap().optional(),
11
+ deleted_at: createOperatorMap().optional(),
12
+ })
13
+
14
+ export const GetAttributesParams = z
15
+ .object({
16
+ product_category_id: z.union([z.string(), z.array(z.string())]).optional(),
17
+ include_globals: z.preprocess(
18
+ (val) => {
19
+ return val === 'true'
20
+ },
21
+ z.boolean().default(true),
22
+ )
23
+ })
24
+ .merge(StoreGetAttributeParamsDirectFields)
@@ -0,0 +1,2 @@
1
+ export const adminAttributesRoutePath = '/admin/plugin/attributes'
2
+ export const storeAttributesBaseRoute = '/store/plugin/attributes'