@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,173 @@
1
+ /**
2
+ * @interface
3
+ *
4
+ * The data to update the attribute.
5
+ */
6
+ export interface UpdateAttributeDTO {
7
+ /**
8
+ * The id of the attribute to update.
9
+ */
10
+ id: string
11
+
12
+ /**
13
+ * The name of the attribute.
14
+ */
15
+ name?: string
16
+
17
+ /**
18
+ * The description of the attribute.
19
+ */
20
+ description?: string
21
+
22
+ /**
23
+ * Whether the attribute should be used as a Blueprint for options
24
+ * when creating them a product variant.
25
+ */
26
+ is_variant_defining?: boolean
27
+
28
+ /**
29
+ * Whether the attribute can be used to filter products.
30
+ */
31
+ is_filterable?: boolean
32
+
33
+ /**
34
+ * The handle of the attribute. The handle can be used to create slug URL paths.
35
+ * If not supplied, the value of the `handle` attribute of the attribute is set to the slug version of the `name` property.
36
+ */
37
+ handle?: string
38
+
39
+ /**
40
+ * Holds custom data in key-value pairs.
41
+ */
42
+ metadata?: Record<string, unknown>
43
+
44
+ /**
45
+ * The associated attribute values to create or update. If "id" is not provided, it will try to update an existent attribute,
46
+ * matching by "value", if not found, it will create a new one and "value" is required.
47
+ */
48
+ possible_values?: UpsertAttributeValueDTO[]
49
+
50
+ /**
51
+ * The associated product categories.
52
+ */
53
+ product_category_ids?: { id: string }[]
54
+ }
55
+
56
+ /**
57
+ * @interface
58
+ *
59
+ * The data to update or create an attribute value.
60
+ */
61
+ export interface UpsertAttributeValueDTO {
62
+ /**
63
+ * The id of the attribute value to update.
64
+ */
65
+ id?: string
66
+
67
+ /**
68
+ * The value of the attribute value.
69
+ */
70
+ value?: string
71
+
72
+ /**
73
+ * The rank of the attribute value. Useful to visually order it on dropdowns.
74
+ */
75
+ rank?: number
76
+
77
+ /**
78
+ * Holds custom data in key-value pairs.
79
+ */
80
+ metadata?: Record<string, unknown>
81
+
82
+ /**
83
+ * The id of the associated attribute.
84
+ */
85
+ attribute_id?: string
86
+ }
87
+
88
+ /**
89
+ * @interface
90
+ *
91
+ * The data to create the attribute value.
92
+ */
93
+ export interface CreateAttributeValueDTO {
94
+ value: string
95
+ rank: number
96
+ attribute_id: string
97
+ metadata?: Record<string, unknown>
98
+ }
99
+
100
+ /**
101
+ * @interface
102
+ *
103
+ * The data to update or create an attribute value.
104
+ */
105
+ export interface UpsertAttributeValueDTO {
106
+ /**
107
+ * The id of the attribute value to update.
108
+ */
109
+ id?: string
110
+
111
+ /**
112
+ * The value of the attribute value.
113
+ */
114
+ value?: string
115
+
116
+ /**
117
+ * The rank of the attribute value. Useful to visually order it on dropdowns.
118
+ */
119
+ rank?: number
120
+
121
+ /**
122
+ * Holds custom data in key-value pairs.
123
+ */
124
+ metadata?: Record<string, unknown>
125
+
126
+ /**
127
+ * The id of the associated attribute.
128
+ */
129
+ attribute_id?: string
130
+ }
131
+
132
+ /**
133
+ * @interface
134
+ *
135
+ * The data to update an attribute value
136
+ */
137
+ export interface UpdateAttributeValueDTO {
138
+ /**
139
+ * The id of the attribute value to update.
140
+ */
141
+ id: string
142
+
143
+ /**
144
+ * The value of the attribute value.
145
+ */
146
+ value?: string
147
+
148
+ /**
149
+ * The rank of the attribute value. Useful to visually order it on dropdowns.
150
+ */
151
+ rank?: number
152
+
153
+ /**
154
+ * Holds custom data in key-value pairs.
155
+ */
156
+ metadata?: Record<string, unknown>
157
+
158
+ /**
159
+ * The id of the associated attribute.
160
+ */
161
+ attribute_id?: string
162
+ }
163
+
164
+ export interface ProductAttributeValueDTO {
165
+ /**
166
+ * The value of the attribute value.
167
+ */
168
+ value: string;
169
+ /**
170
+ * The id of the associated attribute.
171
+ */
172
+ attribute_id: string;
173
+ }
@@ -0,0 +1,42 @@
1
+ import { AttributeUIComponent } from '../../../../modules/attribute/types'
2
+ import { AttributeSet } from '../attribute-set'
3
+
4
+ export interface Attribute {
5
+ id: string
6
+ name: string
7
+ description: string | null
8
+ is_variant_defining: boolean
9
+ is_filterable: boolean
10
+ handle: string
11
+ ui_component: AttributeUIComponent
12
+ metadata: Record<string, unknown> | null
13
+ possible_values?: AttributePossibleValue[]
14
+ created_at: string
15
+ updated_at: string
16
+ values?: Array<{
17
+ id: string
18
+ value: string
19
+ }>
20
+ sets?: AttributeSet[]
21
+ product_categories?: Array<{
22
+ id: string
23
+ name: string
24
+ }>
25
+ }
26
+
27
+ export interface AttributePossibleValue {
28
+ id: string
29
+ value: string
30
+ rank: number
31
+ created_at: string
32
+ metadata: Record<string, unknown> | null
33
+ }
34
+
35
+ export interface AttributesResponse {
36
+ attributes: Attribute[]
37
+ count: number
38
+ offset: number
39
+ limit: number
40
+ }
41
+
42
+ export * from './admin'
@@ -0,0 +1,10 @@
1
+ import { Attribute } from "../attribute"
2
+
3
+ export type AttributeSet = {
4
+ id: string
5
+ name: string
6
+ description?: string
7
+ handle: string
8
+ metadata: Record<string, unknown> | null
9
+ attributes: Attribute[]
10
+ }
@@ -0,0 +1,2 @@
1
+ export * from './attribute'
2
+ export * from './attribute-set'
@@ -0,0 +1,2 @@
1
+ export * from './http'
2
+ export * from './common'
@@ -0,0 +1 @@
1
+ export * from './products-created-handler'
@@ -0,0 +1,35 @@
1
+ import {
2
+ MedusaContainer,
3
+ ProductDTO,
4
+ } from "@medusajs/framework/types";
5
+
6
+ import { ProductAttributeValueDTO } from "../types/attribute";
7
+ import { createAttributeValueWorkflow } from "../workflows/attribute-value/workflow";
8
+ import { validateAttributeValuesToLink } from "./validate-attribute-values-to-link";
9
+
10
+ export const productsCreatedHookHandler = async ({
11
+ products,
12
+ additional_data,
13
+ container,
14
+ }: {
15
+ products: ProductDTO[];
16
+ additional_data: Record<string, unknown> | undefined;
17
+ container: MedusaContainer;
18
+ }) => {
19
+ const attributeValues = (additional_data?.values ?? []) as ProductAttributeValueDTO[];
20
+ const productIds = products.map((prod) => prod.id);
21
+
22
+ if (!attributeValues.length) {
23
+ return [];
24
+ }
25
+
26
+ await Promise.all(productIds.flatMap(prodId => attributeValues.map(async attrVal => {
27
+ return createAttributeValueWorkflow(container).run({
28
+ input: {
29
+ attribute_id: attrVal.attribute_id,
30
+ value: attrVal.value,
31
+ product_id: prodId,
32
+ }
33
+ })
34
+ })))
35
+ };
@@ -0,0 +1,74 @@
1
+ import { createAttributeValueWorkflow, deleteAttributeValueWorkflow } from "../workflows/attribute-value/workflow";
2
+
3
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils";
4
+ import { MedusaContainer } from "@medusajs/framework";
5
+ import { ProductAttributeValueDTO } from "../types/attribute";
6
+ import { ProductDTO } from "@medusajs/framework/types";
7
+ import attributeValueProduct from "../links/attribute-value-product";
8
+ import { validateAttributeValuesToLink } from "./validate-attribute-values-to-link";
9
+
10
+ export const productsUpdatedHookHandler = async ({
11
+ products,
12
+ additional_data,
13
+ container,
14
+ }: {
15
+ products: ProductDTO[];
16
+ additional_data: Record<string, unknown> | undefined;
17
+ container: MedusaContainer;
18
+ }) => {
19
+ const query = container.resolve(ContainerRegistrationKeys.QUERY)
20
+
21
+ const attributeValues = (additional_data?.values ?? []) as ProductAttributeValueDTO[];
22
+ const productIds = products.map((prod) => prod.id);
23
+
24
+ if (!attributeValues.length) {
25
+ return [];
26
+ }
27
+
28
+ const updatedValueIds = (await Promise.all(productIds.map(async prodId => {
29
+ const { data: productValues } = await query.graph({
30
+ entity: attributeValueProduct.entryPoint,
31
+ fields: ['attribute_value.id', 'attribute_value.value', 'attribute_value.attribute_id'],
32
+ filters: {
33
+ product_id: prodId
34
+ }
35
+ })
36
+
37
+ return Promise.all(attributeValues.map(async attrVal => {
38
+ const unchangedProductValue = productValues.find(prodVal =>
39
+ prodVal.attribute_value.value === attrVal.value && prodVal.attribute_value.attribute_id === attrVal.attribute_id
40
+ )
41
+ if (unchangedProductValue) {
42
+ return unchangedProductValue.attribute_value.id as string
43
+ }
44
+
45
+ const { result } = await createAttributeValueWorkflow(container).run({
46
+ input: {
47
+ attribute_id: attrVal.attribute_id,
48
+ value: attrVal.value,
49
+ product_id: prodId,
50
+ }
51
+ })
52
+ return result.id
53
+ }))
54
+ }))).flat()
55
+
56
+ const { data: attributeValuesToDelete } = await query.graph({
57
+ entity: attributeValueProduct.entryPoint,
58
+ fields: ['attribute_value_id'],
59
+ filters: {
60
+ attribute_value_id: {
61
+ $nin: updatedValueIds
62
+ },
63
+ product_id: productIds
64
+ }
65
+ })
66
+
67
+ if (!attributeValuesToDelete.length) {
68
+ return;
69
+ }
70
+
71
+ await deleteAttributeValueWorkflow(container).run({
72
+ input: attributeValuesToDelete.map(val => val.attribute_value_id)
73
+ })
74
+ };
@@ -0,0 +1,67 @@
1
+ import {
2
+ ContainerRegistrationKeys,
3
+ MedusaError,
4
+ MedusaErrorTypes,
5
+ } from "@medusajs/framework/utils";
6
+ import { InferTypeOf, MedusaContainer, ProductCategoryDTO, ProductDTO } from "@medusajs/framework/types";
7
+
8
+ import Attribute from "../modules/attribute/models/attribute";
9
+ import { ProductAttributeValueDTO } from "../types/attribute";
10
+
11
+ export const validateAttributeValuesToLink = async ({
12
+ attributeValues,
13
+ products,
14
+ container,
15
+ }: {
16
+ attributeValues: ProductAttributeValueDTO[];
17
+ products: ProductDTO[];
18
+ container: MedusaContainer;
19
+ }) => {
20
+ const query = container.resolve(ContainerRegistrationKeys.QUERY);
21
+
22
+ const attributeMap = new Map<string, InferTypeOf<typeof Attribute> & { product_categories?: ProductCategoryDTO[] }>()
23
+
24
+ for (const attrVal of attributeValues) {
25
+ const id = attrVal.attribute_id
26
+
27
+ if (!attributeMap.get(id)) {
28
+ const { data: [attribute] } = await query.graph({
29
+ entity: 'attribute',
30
+ fields: ['product_categories.*', 'possible_values.*'],
31
+ filters: {
32
+ id: id
33
+ }
34
+ })
35
+
36
+ attributeMap.set(id, attribute)
37
+ }
38
+
39
+ const allowedValues = attributeMap.get(id)?.possible_values?.map(posVal => posVal.value)
40
+
41
+ if (allowedValues?.length && !allowedValues.includes(attrVal.value)) {
42
+ throw new MedusaError(MedusaErrorTypes.INVALID_DATA, `Attribute ${attrVal.attribute_id} doesn't define ${attrVal.value} as a possible_value`)
43
+ }
44
+ }
45
+
46
+ const attributeCategoryIds = Array.from(new Set(
47
+ Array.from(attributeMap.values())
48
+ .flatMap(attr => attr.product_categories?.map(cat => cat.id) || [])
49
+ ))
50
+
51
+ if (!attributeCategoryIds.length) {
52
+ // If all attributes are global, we don't enforce for product.categories to include the attribute.product_categories, since there are none
53
+ return;
54
+ }
55
+
56
+ const invalidProductIds: string[] = []
57
+ for (const product of products) {
58
+ const productCategoryIds = product.categories?.map(cat => cat.id)
59
+ if (!productCategoryIds?.some(prodCatId => attributeCategoryIds.includes(prodCatId))) {
60
+ invalidProductIds.push(product.id)
61
+ }
62
+ }
63
+
64
+ if (invalidProductIds.length) {
65
+ throw new MedusaError(MedusaErrorTypes.INVALID_DATA, `The following products aren't linked to any category from the requested attributes:\n${invalidProductIds.join(', ')}`)
66
+ }
67
+ };
@@ -0,0 +1,79 @@
1
+ # Custom Workflows
2
+
3
+ A workflow is a series of queries and actions that complete a task.
4
+
5
+ The workflow is created in a TypeScript or JavaScript file under the `src/workflows` directory.
6
+
7
+ For example:
8
+
9
+ ```ts
10
+ import {
11
+ createStep,
12
+ createWorkflow,
13
+ WorkflowResponse,
14
+ StepResponse,
15
+ } from "@medusajs/framework/workflows-sdk"
16
+
17
+ const step1 = createStep("step-1", async () => {
18
+ return new StepResponse(`Hello from step one!`)
19
+ })
20
+
21
+ type WorkflowInput = {
22
+ name: string
23
+ }
24
+
25
+ const step2 = createStep(
26
+ "step-2",
27
+ async ({ name }: WorkflowInput) => {
28
+ return new StepResponse(`Hello ${name} from step two!`)
29
+ }
30
+ )
31
+
32
+ type WorkflowOutput = {
33
+ message1: string
34
+ message2: string
35
+ }
36
+
37
+ const helloWorldWorkflow = createWorkflow(
38
+ "hello-world",
39
+ (input: WorkflowInput) => {
40
+ const greeting1 = step1()
41
+ const greeting2 = step2(input)
42
+
43
+ return new WorkflowResponse({
44
+ message1: greeting1,
45
+ message2: greeting2
46
+ })
47
+ }
48
+ )
49
+
50
+ export default helloWorldWorkflow
51
+ ```
52
+
53
+ ## Execute Workflow
54
+
55
+ You can execute the workflow from other resources, such as API routes, scheduled jobs, or subscribers.
56
+
57
+ For example, to execute the workflow in an API route:
58
+
59
+ ```ts
60
+ import type {
61
+ MedusaRequest,
62
+ MedusaResponse,
63
+ } from "@medusajs/framework"
64
+ import myWorkflow from "../../../workflows/hello-world"
65
+
66
+ export async function GET(
67
+ req: MedusaRequest,
68
+ res: MedusaResponse
69
+ ) {
70
+ const { result } = await myWorkflow(req.scope)
71
+ .run({
72
+ input: {
73
+ name: req.query.name as string,
74
+ },
75
+ })
76
+
77
+ res.send(result)
78
+ }
79
+ ```
@@ -0,0 +1,2 @@
1
+ export * from './workflows'
2
+ export * from './steps'
@@ -0,0 +1,29 @@
1
+ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
2
+
3
+ import { ATTRIBUTE_MODULE } from "../../../modules/attribute"
4
+ import AttributeModuleService from "../../../modules/attribute/service"
5
+ import { CreateAttributeValueDTO } from "../../../types/attribute"
6
+
7
+ export const createAttributePossibleValuesStepId = 'create-attribute-possible-values'
8
+
9
+ export type CreateAttributePossibleValuesStepInput = CreateAttributeValueDTO[]
10
+
11
+ export const createAttributePossibleValuesStep = createStep(
12
+ createAttributePossibleValuesStepId,
13
+ async (data: CreateAttributePossibleValuesStepInput, { container }) => {
14
+ const service = container.resolve<AttributeModuleService>(ATTRIBUTE_MODULE)
15
+
16
+ const values = await service.createAttributePossibleValues(data)
17
+
18
+ return new StepResponse(values, values.map(val => val.id))
19
+ },
20
+ async (ids, { container }) => {
21
+ if (!ids?.length) {
22
+ return
23
+ }
24
+
25
+ const service = container.resolve<AttributeModuleService>(ATTRIBUTE_MODULE)
26
+
27
+ await service.deleteAttributeValues(ids)
28
+ }
29
+ )
@@ -0,0 +1,35 @@
1
+ import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
2
+ import { CreateAttributeStepInput } from "../../../modules/attribute/types/attribute/common"
3
+ import AttributeModuleService from "../../../modules/attribute/service"
4
+ import attribute, { ATTRIBUTE_MODULE } from "../../../modules/attribute"
5
+ import { kebabCase, toHandle } from "@medusajs/framework/utils"
6
+
7
+ export const createAttributesStepId = 'create-attributes'
8
+
9
+ export const createAttributesStep = createStep(
10
+ createAttributesStepId,
11
+ async (data: CreateAttributeStepInput, { container }) => {
12
+ const service = container.resolve<AttributeModuleService>(ATTRIBUTE_MODULE)
13
+
14
+ const validated = data.map(attribute => {
15
+ let result = { ...attribute }
16
+ if (!attribute.handle) {
17
+ result.handle = toHandle(attribute.name)
18
+ }
19
+ return result
20
+ })
21
+
22
+ //@ts-expect-error
23
+ const created = await service.createAttributes(validated) as any[]
24
+ return new StepResponse(created, created.map(attribute => attribute.id))
25
+ },
26
+ async (createdIds: string[] | undefined, { container }) => {
27
+ if(!createdIds?.length) {
28
+ return
29
+ }
30
+
31
+ const service = container.resolve<AttributeModuleService>(ATTRIBUTE_MODULE)
32
+
33
+ await service.deleteAttributes(createdIds)
34
+ }
35
+ )
@@ -0,0 +1,41 @@
1
+ import { createStep, StepResponse } from "@medusajs/workflows-sdk"
2
+ import { ATTRIBUTE_MODULE } from "../../../modules/attribute"
3
+ import AttributeModuleService from "../../../modules/attribute/service"
4
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
5
+
6
+ export const deleteAttributeStepId = 'delete-attribute-step'
7
+
8
+ type DeleteAttributeStepInput = {
9
+ id: string
10
+ }
11
+
12
+ export const deleteAttributeStep = createStep(
13
+ deleteAttributeStepId,
14
+ async ({ id }: DeleteAttributeStepInput, { container }) => {
15
+ const attributeModuleService = container.resolve(ATTRIBUTE_MODULE) as AttributeModuleService
16
+ const link = container.resolve(ContainerRegistrationKeys.LINK)
17
+
18
+ await attributeModuleService.softDeleteAttributes(id)
19
+ await link.delete({
20
+ [ATTRIBUTE_MODULE]: {
21
+ attribute_id: id,
22
+ }
23
+ })
24
+ return new StepResponse(undefined, id)
25
+ },
26
+ async (id: string | undefined, { container }) => {
27
+ if (!id) {
28
+ return
29
+ }
30
+
31
+ const attributeModuleService = container.resolve(ATTRIBUTE_MODULE) as AttributeModuleService
32
+ const link = container.resolve(ContainerRegistrationKeys.LINK)
33
+
34
+ await attributeModuleService.restoreAttributes(id)
35
+ await link.restore({
36
+ [ATTRIBUTE_MODULE]: {
37
+ attribute_id: id
38
+ }
39
+ })
40
+ }
41
+ )
@@ -0,0 +1,4 @@
1
+ export * from './create-attributes'
2
+ export * from './update-attributes'
3
+ export * from './create-attribute-possible-values'
4
+ export * from './delete-attribute'
@@ -0,0 +1,45 @@
1
+ import { StepResponse, WorkflowData, createStep } from "@medusajs/framework/workflows-sdk"
2
+
3
+ import { ATTRIBUTE_MODULE } from "../../../modules/attribute"
4
+ import AttributeModuleService from "../../../modules/attribute/service"
5
+ import { UpdateAttributeDTO } from "../../../types/attribute"
6
+
7
+ const updateAttributesStepId = 'update-attributes'
8
+
9
+ export const updateAttributesStep = createStep(
10
+ updateAttributesStepId,
11
+ async (data: WorkflowData<UpdateAttributeDTO[]>, { container }) => {
12
+ const service = container.resolve<AttributeModuleService>(ATTRIBUTE_MODULE)
13
+
14
+ const prevData = await service.listAttributes({
15
+ id: data.map(attribute => attribute.id)
16
+ })
17
+
18
+ const normalized = data.map(attr => {
19
+ const { possible_values: values, ...attribute } = attr;
20
+ const valuesWithAttribute = values?.map(val => ({ ...val, attribute_id: attribute.id }))
21
+ return {
22
+ ...attr,
23
+ possible_values: valuesWithAttribute
24
+ }
25
+ })
26
+
27
+ const attributes = normalized.map((element) => {
28
+ const { product_category_ids, ...attr } = element
29
+ return attr
30
+ })
31
+
32
+ await service.updateAttributeWithUpsertOrReplacePossibleValues(normalized)
33
+
34
+ return new StepResponse(attributes, prevData)
35
+ },
36
+ async (prevData, { container }) => {
37
+ if (!prevData?.length) {
38
+ return
39
+ }
40
+
41
+ const service = container.resolve<AttributeModuleService>(ATTRIBUTE_MODULE)
42
+ //@ts-expect-error
43
+ await service.updateAttributes(prevData)
44
+ }
45
+ )
@@ -0,0 +1,17 @@
1
+ import { WorkflowResponse, createWorkflow } from "@medusajs/framework/workflows-sdk"
2
+
3
+ import { CreateAttributeValueDTO } from "../../../types/attribute"
4
+ import { createAttributePossibleValuesStep } from "../steps/create-attribute-possible-values"
5
+
6
+ const createAttributePossibleValuesWorkflowId = 'create-attribute-possible-values'
7
+
8
+ export type CreateAttributePossibleValuesWorkflowInput = CreateAttributeValueDTO[]
9
+
10
+ export const createAttributePossibleValuesWorkflow = createWorkflow(
11
+ createAttributePossibleValuesWorkflowId,
12
+ (input: CreateAttributePossibleValuesWorkflowInput) => {
13
+ const createdValues = createAttributePossibleValuesStep(input)
14
+
15
+ return new WorkflowResponse(createdValues)
16
+ }
17
+ )