@endora-commerce/mod-catalog 0.100.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 (443) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/dist/admin/components/PackagingUnitsEditor.d.ts +12 -0
  4. package/dist/admin/components/PackagingUnitsEditor.d.ts.map +1 -0
  5. package/dist/admin/components/PackagingUnitsEditor.js +99 -0
  6. package/dist/admin/components/PackagingUnitsEditor.js.map +1 -0
  7. package/dist/admin/components/ProductAttributesTab.d.ts +13 -0
  8. package/dist/admin/components/ProductAttributesTab.d.ts.map +1 -0
  9. package/dist/admin/components/ProductAttributesTab.js +140 -0
  10. package/dist/admin/components/ProductAttributesTab.js.map +1 -0
  11. package/dist/admin/components/ProductInventoryTab.d.ts +14 -0
  12. package/dist/admin/components/ProductInventoryTab.d.ts.map +1 -0
  13. package/dist/admin/components/ProductInventoryTab.js +284 -0
  14. package/dist/admin/components/ProductInventoryTab.js.map +1 -0
  15. package/dist/admin/components/ProductScopeEditor.d.ts +94 -0
  16. package/dist/admin/components/ProductScopeEditor.d.ts.map +1 -0
  17. package/dist/admin/components/ProductScopeEditor.js +395 -0
  18. package/dist/admin/components/ProductScopeEditor.js.map +1 -0
  19. package/dist/admin/components/ProductsBulkEditDialog.d.ts +11 -0
  20. package/dist/admin/components/ProductsBulkEditDialog.d.ts.map +1 -0
  21. package/dist/admin/components/ProductsBulkEditDialog.js +304 -0
  22. package/dist/admin/components/ProductsBulkEditDialog.js.map +1 -0
  23. package/dist/admin/index.d.ts +45 -0
  24. package/dist/admin/index.d.ts.map +1 -0
  25. package/dist/admin/index.js +184 -0
  26. package/dist/admin/index.js.map +1 -0
  27. package/dist/admin/lib/resolve-product-selection.d.ts +21 -0
  28. package/dist/admin/lib/resolve-product-selection.d.ts.map +1 -0
  29. package/dist/admin/lib/resolve-product-selection.js +25 -0
  30. package/dist/admin/lib/resolve-product-selection.js.map +1 -0
  31. package/dist/admin/pages/AttachmentTypesPage.d.ts +18 -0
  32. package/dist/admin/pages/AttachmentTypesPage.d.ts.map +1 -0
  33. package/dist/admin/pages/AttachmentTypesPage.js +92 -0
  34. package/dist/admin/pages/AttachmentTypesPage.js.map +1 -0
  35. package/dist/admin/pages/AttributeSetsPage.d.ts +21 -0
  36. package/dist/admin/pages/AttributeSetsPage.d.ts.map +1 -0
  37. package/dist/admin/pages/AttributeSetsPage.js +158 -0
  38. package/dist/admin/pages/AttributeSetsPage.js.map +1 -0
  39. package/dist/admin/pages/AttributesManager.d.ts +9 -0
  40. package/dist/admin/pages/AttributesManager.d.ts.map +1 -0
  41. package/dist/admin/pages/AttributesManager.js +305 -0
  42. package/dist/admin/pages/AttributesManager.js.map +1 -0
  43. package/dist/admin/pages/BulkOperationDetailPage.d.ts +9 -0
  44. package/dist/admin/pages/BulkOperationDetailPage.d.ts.map +1 -0
  45. package/dist/admin/pages/BulkOperationDetailPage.js +187 -0
  46. package/dist/admin/pages/BulkOperationDetailPage.js.map +1 -0
  47. package/dist/admin/pages/BulkOperationsPage.d.ts +9 -0
  48. package/dist/admin/pages/BulkOperationsPage.d.ts.map +1 -0
  49. package/dist/admin/pages/BulkOperationsPage.js +98 -0
  50. package/dist/admin/pages/BulkOperationsPage.js.map +1 -0
  51. package/dist/admin/pages/CategoriesTree.d.ts +9 -0
  52. package/dist/admin/pages/CategoriesTree.d.ts.map +1 -0
  53. package/dist/admin/pages/CategoriesTree.js +176 -0
  54. package/dist/admin/pages/CategoriesTree.js.map +1 -0
  55. package/dist/admin/pages/ProductEditor.d.ts +13 -0
  56. package/dist/admin/pages/ProductEditor.d.ts.map +1 -0
  57. package/dist/admin/pages/ProductEditor.js +1050 -0
  58. package/dist/admin/pages/ProductEditor.js.map +1 -0
  59. package/dist/admin/pages/ProductsList.d.ts +9 -0
  60. package/dist/admin/pages/ProductsList.d.ts.map +1 -0
  61. package/dist/admin/pages/ProductsList.js +399 -0
  62. package/dist/admin/pages/ProductsList.js.map +1 -0
  63. package/dist/backend/commands/attribute-commands.d.ts +111 -0
  64. package/dist/backend/commands/attribute-commands.d.ts.map +1 -0
  65. package/dist/backend/commands/attribute-commands.js +482 -0
  66. package/dist/backend/commands/attribute-commands.js.map +1 -0
  67. package/dist/backend/demo/reset.d.ts +23 -0
  68. package/dist/backend/demo/reset.d.ts.map +1 -0
  69. package/dist/backend/demo/reset.js +41 -0
  70. package/dist/backend/demo/reset.js.map +1 -0
  71. package/dist/backend/demo/rows.d.ts +103 -0
  72. package/dist/backend/demo/rows.d.ts.map +1 -0
  73. package/dist/backend/demo/rows.js +162 -0
  74. package/dist/backend/demo/rows.js.map +1 -0
  75. package/dist/backend/demo/seed.d.ts +35 -0
  76. package/dist/backend/demo/seed.d.ts.map +1 -0
  77. package/dist/backend/demo/seed.js +177 -0
  78. package/dist/backend/demo/seed.js.map +1 -0
  79. package/dist/backend/entities/attachment-type.entity.d.ts +16 -0
  80. package/dist/backend/entities/attachment-type.entity.d.ts.map +1 -0
  81. package/dist/backend/entities/attachment-type.entity.js +57 -0
  82. package/dist/backend/entities/attachment-type.entity.js.map +1 -0
  83. package/dist/backend/entities/attribute-set-attribute.entity.d.ts +26 -0
  84. package/dist/backend/entities/attribute-set-attribute.entity.d.ts.map +1 -0
  85. package/dist/backend/entities/attribute-set-attribute.entity.js +55 -0
  86. package/dist/backend/entities/attribute-set-attribute.entity.js.map +1 -0
  87. package/dist/backend/entities/attribute-set.entity.d.ts +22 -0
  88. package/dist/backend/entities/attribute-set.entity.d.ts.map +1 -0
  89. package/dist/backend/entities/attribute-set.entity.js +67 -0
  90. package/dist/backend/entities/attribute-set.entity.js.map +1 -0
  91. package/dist/backend/entities/bulk-operation.entity.d.ts +78 -0
  92. package/dist/backend/entities/bulk-operation.entity.d.ts.map +1 -0
  93. package/dist/backend/entities/bulk-operation.entity.js +138 -0
  94. package/dist/backend/entities/bulk-operation.entity.js.map +1 -0
  95. package/dist/backend/entities/bundle-slot-option.entity.d.ts +23 -0
  96. package/dist/backend/entities/bundle-slot-option.entity.d.ts.map +1 -0
  97. package/dist/backend/entities/bundle-slot-option.entity.js +68 -0
  98. package/dist/backend/entities/bundle-slot-option.entity.js.map +1 -0
  99. package/dist/backend/entities/bundle-slot.entity.d.ts +25 -0
  100. package/dist/backend/entities/bundle-slot.entity.d.ts.map +1 -0
  101. package/dist/backend/entities/bundle-slot.entity.js +74 -0
  102. package/dist/backend/entities/bundle-slot.entity.js.map +1 -0
  103. package/dist/backend/entities/category.entity.d.ts +26 -0
  104. package/dist/backend/entities/category.entity.d.ts.map +1 -0
  105. package/dist/backend/entities/category.entity.js +119 -0
  106. package/dist/backend/entities/category.entity.js.map +1 -0
  107. package/dist/backend/entities/gallery-item-label.entity.d.ts +22 -0
  108. package/dist/backend/entities/gallery-item-label.entity.d.ts.map +1 -0
  109. package/dist/backend/entities/gallery-item-label.entity.js +50 -0
  110. package/dist/backend/entities/gallery-item-label.entity.js.map +1 -0
  111. package/dist/backend/entities/gallery-item.entity.d.ts +17 -0
  112. package/dist/backend/entities/gallery-item.entity.d.ts.map +1 -0
  113. package/dist/backend/entities/gallery-item.entity.js +58 -0
  114. package/dist/backend/entities/gallery-item.entity.js.map +1 -0
  115. package/dist/backend/entities/grouped-item.entity.d.ts +23 -0
  116. package/dist/backend/entities/grouped-item.entity.d.ts.map +1 -0
  117. package/dist/backend/entities/grouped-item.entity.js +68 -0
  118. package/dist/backend/entities/grouped-item.entity.js.map +1 -0
  119. package/dist/backend/entities/product-attachment.entity.d.ts +23 -0
  120. package/dist/backend/entities/product-attachment.entity.d.ts.map +1 -0
  121. package/dist/backend/entities/product-attachment.entity.js +77 -0
  122. package/dist/backend/entities/product-attachment.entity.js.map +1 -0
  123. package/dist/backend/entities/product-attribute.entity.d.ts +72 -0
  124. package/dist/backend/entities/product-attribute.entity.d.ts.map +1 -0
  125. package/dist/backend/entities/product-attribute.entity.js +161 -0
  126. package/dist/backend/entities/product-attribute.entity.js.map +1 -0
  127. package/dist/backend/entities/product-editor-preference.entity.d.ts +28 -0
  128. package/dist/backend/entities/product-editor-preference.entity.d.ts.map +1 -0
  129. package/dist/backend/entities/product-editor-preference.entity.js +63 -0
  130. package/dist/backend/entities/product-editor-preference.entity.js.map +1 -0
  131. package/dist/backend/entities/product-link.entity.d.ts +25 -0
  132. package/dist/backend/entities/product-link.entity.d.ts.map +1 -0
  133. package/dist/backend/entities/product-link.entity.js +70 -0
  134. package/dist/backend/entities/product-link.entity.js.map +1 -0
  135. package/dist/backend/entities/product-packaging-unit.entity.d.ts +26 -0
  136. package/dist/backend/entities/product-packaging-unit.entity.d.ts.map +1 -0
  137. package/dist/backend/entities/product-packaging-unit.entity.js +76 -0
  138. package/dist/backend/entities/product-packaging-unit.entity.js.map +1 -0
  139. package/dist/backend/entities/product-value-override.entity.d.ts +43 -0
  140. package/dist/backend/entities/product-value-override.entity.d.ts.map +1 -0
  141. package/dist/backend/entities/product-value-override.entity.js +90 -0
  142. package/dist/backend/entities/product-value-override.entity.js.map +1 -0
  143. package/dist/backend/entities/product-variant.entity.d.ts +18 -0
  144. package/dist/backend/entities/product-variant.entity.d.ts.map +1 -0
  145. package/dist/backend/entities/product-variant.entity.js +68 -0
  146. package/dist/backend/entities/product-variant.entity.js.map +1 -0
  147. package/dist/backend/entities/product.entity.d.ts +108 -0
  148. package/dist/backend/entities/product.entity.d.ts.map +1 -0
  149. package/dist/backend/entities/product.entity.js +230 -0
  150. package/dist/backend/entities/product.entity.js.map +1 -0
  151. package/dist/backend/index.d.ts +262 -0
  152. package/dist/backend/index.d.ts.map +1 -0
  153. package/dist/backend/index.js +642 -0
  154. package/dist/backend/index.js.map +1 -0
  155. package/dist/backend/plugin.d.ts +216 -0
  156. package/dist/backend/plugin.d.ts.map +1 -0
  157. package/dist/backend/plugin.js +223 -0
  158. package/dist/backend/plugin.js.map +1 -0
  159. package/dist/backend/prompt-tools.d.ts +47 -0
  160. package/dist/backend/prompt-tools.d.ts.map +1 -0
  161. package/dist/backend/prompt-tools.js +284 -0
  162. package/dist/backend/prompt-tools.js.map +1 -0
  163. package/dist/backend/routes.admin.d.ts +105 -0
  164. package/dist/backend/routes.admin.d.ts.map +1 -0
  165. package/dist/backend/routes.admin.js +1162 -0
  166. package/dist/backend/routes.admin.js.map +1 -0
  167. package/dist/backend/routes.api-key.d.ts +33 -0
  168. package/dist/backend/routes.api-key.d.ts.map +1 -0
  169. package/dist/backend/routes.api-key.js +43 -0
  170. package/dist/backend/routes.api-key.js.map +1 -0
  171. package/dist/backend/routes.external.d.ts +32 -0
  172. package/dist/backend/routes.external.d.ts.map +1 -0
  173. package/dist/backend/routes.external.js +115 -0
  174. package/dist/backend/routes.external.js.map +1 -0
  175. package/dist/backend/routes.public.d.ts +46 -0
  176. package/dist/backend/routes.public.d.ts.map +1 -0
  177. package/dist/backend/routes.public.js +318 -0
  178. package/dist/backend/routes.public.js.map +1 -0
  179. package/dist/backend/services/asset-references.d.ts +4 -0
  180. package/dist/backend/services/asset-references.d.ts.map +1 -0
  181. package/dist/backend/services/asset-references.js +104 -0
  182. package/dist/backend/services/asset-references.js.map +1 -0
  183. package/dist/backend/services/attachment.service.d.ts +45 -0
  184. package/dist/backend/services/attachment.service.d.ts.map +1 -0
  185. package/dist/backend/services/attachment.service.js +268 -0
  186. package/dist/backend/services/attachment.service.js.map +1 -0
  187. package/dist/backend/services/attribute-option-validator.d.ts +47 -0
  188. package/dist/backend/services/attribute-option-validator.d.ts.map +1 -0
  189. package/dist/backend/services/attribute-option-validator.js +69 -0
  190. package/dist/backend/services/attribute-option-validator.js.map +1 -0
  191. package/dist/backend/services/attribute-set-validations.d.ts +65 -0
  192. package/dist/backend/services/attribute-set-validations.d.ts.map +1 -0
  193. package/dist/backend/services/attribute-set-validations.js +89 -0
  194. package/dist/backend/services/attribute-set-validations.js.map +1 -0
  195. package/dist/backend/services/attribute-set.service.d.ts +50 -0
  196. package/dist/backend/services/attribute-set.service.d.ts.map +1 -0
  197. package/dist/backend/services/attribute-set.service.js +401 -0
  198. package/dist/backend/services/attribute-set.service.js.map +1 -0
  199. package/dist/backend/services/attribute-type-mapping.d.ts +66 -0
  200. package/dist/backend/services/attribute-type-mapping.d.ts.map +1 -0
  201. package/dist/backend/services/attribute-type-mapping.js +121 -0
  202. package/dist/backend/services/attribute-type-mapping.js.map +1 -0
  203. package/dist/backend/services/attribute-value-key.service.d.ts +48 -0
  204. package/dist/backend/services/attribute-value-key.service.d.ts.map +1 -0
  205. package/dist/backend/services/attribute-value-key.service.js +118 -0
  206. package/dist/backend/services/attribute-value-key.service.js.map +1 -0
  207. package/dist/backend/services/audit-references.d.ts +13 -0
  208. package/dist/backend/services/audit-references.d.ts.map +1 -0
  209. package/dist/backend/services/audit-references.js +51 -0
  210. package/dist/backend/services/audit-references.js.map +1 -0
  211. package/dist/backend/services/bulk-operation-queue.d.ts +26 -0
  212. package/dist/backend/services/bulk-operation-queue.d.ts.map +1 -0
  213. package/dist/backend/services/bulk-operation-queue.js +34 -0
  214. package/dist/backend/services/bulk-operation-queue.js.map +1 -0
  215. package/dist/backend/services/bulk-operation.service.d.ts +195 -0
  216. package/dist/backend/services/bulk-operation.service.d.ts.map +1 -0
  217. package/dist/backend/services/bulk-operation.service.js +510 -0
  218. package/dist/backend/services/bulk-operation.service.js.map +1 -0
  219. package/dist/backend/services/bundle.service.d.ts +87 -0
  220. package/dist/backend/services/bundle.service.d.ts.map +1 -0
  221. package/dist/backend/services/bundle.service.js +286 -0
  222. package/dist/backend/services/bundle.service.js.map +1 -0
  223. package/dist/backend/services/catalog-admin.service.d.ts +398 -0
  224. package/dist/backend/services/catalog-admin.service.d.ts.map +1 -0
  225. package/dist/backend/services/catalog-admin.service.js +1516 -0
  226. package/dist/backend/services/catalog-admin.service.js.map +1 -0
  227. package/dist/backend/services/catalog-attribute-read.service.d.ts +78 -0
  228. package/dist/backend/services/catalog-attribute-read.service.d.ts.map +1 -0
  229. package/dist/backend/services/catalog-attribute-read.service.js +216 -0
  230. package/dist/backend/services/catalog-attribute-read.service.js.map +1 -0
  231. package/dist/backend/services/catalog-bulk-import.service.d.ts +30 -0
  232. package/dist/backend/services/catalog-bulk-import.service.d.ts.map +1 -0
  233. package/dist/backend/services/catalog-bulk-import.service.js +136 -0
  234. package/dist/backend/services/catalog-bulk-import.service.js.map +1 -0
  235. package/dist/backend/services/catalog-bulk-update.service.d.ts +91 -0
  236. package/dist/backend/services/catalog-bulk-update.service.d.ts.map +1 -0
  237. package/dist/backend/services/catalog-bulk-update.service.js +330 -0
  238. package/dist/backend/services/catalog-bulk-update.service.js.map +1 -0
  239. package/dist/backend/services/catalog-category-read.service.d.ts +66 -0
  240. package/dist/backend/services/catalog-category-read.service.d.ts.map +1 -0
  241. package/dist/backend/services/catalog-category-read.service.js +248 -0
  242. package/dist/backend/services/catalog-category-read.service.js.map +1 -0
  243. package/dist/backend/services/catalog-org-price-decorator.d.ts +90 -0
  244. package/dist/backend/services/catalog-org-price-decorator.d.ts.map +1 -0
  245. package/dist/backend/services/catalog-org-price-decorator.js +184 -0
  246. package/dist/backend/services/catalog-org-price-decorator.js.map +1 -0
  247. package/dist/backend/services/catalog-product-filter.service.d.ts +82 -0
  248. package/dist/backend/services/catalog-product-filter.service.d.ts.map +1 -0
  249. package/dist/backend/services/catalog-product-filter.service.js +275 -0
  250. package/dist/backend/services/catalog-product-filter.service.js.map +1 -0
  251. package/dist/backend/services/catalog-product-read.service.d.ts +46 -0
  252. package/dist/backend/services/catalog-product-read.service.d.ts.map +1 -0
  253. package/dist/backend/services/catalog-product-read.service.js +197 -0
  254. package/dist/backend/services/catalog-product-read.service.js.map +1 -0
  255. package/dist/backend/services/catalog-query.service.d.ts +444 -0
  256. package/dist/backend/services/catalog-query.service.d.ts.map +1 -0
  257. package/dist/backend/services/catalog-query.service.js +1633 -0
  258. package/dist/backend/services/catalog-query.service.js.map +1 -0
  259. package/dist/backend/services/catalog-quick-search.service.d.ts +78 -0
  260. package/dist/backend/services/catalog-quick-search.service.d.ts.map +1 -0
  261. package/dist/backend/services/catalog-quick-search.service.js +159 -0
  262. package/dist/backend/services/catalog-quick-search.service.js.map +1 -0
  263. package/dist/backend/services/catalog-write-ports.d.ts +25 -0
  264. package/dist/backend/services/catalog-write-ports.d.ts.map +1 -0
  265. package/dist/backend/services/catalog-write-ports.js +63 -0
  266. package/dist/backend/services/catalog-write-ports.js.map +1 -0
  267. package/dist/backend/services/category-admin.service.d.ts +102 -0
  268. package/dist/backend/services/category-admin.service.d.ts.map +1 -0
  269. package/dist/backend/services/category-admin.service.js +271 -0
  270. package/dist/backend/services/category-admin.service.js.map +1 -0
  271. package/dist/backend/services/gallery.service.d.ts +85 -0
  272. package/dist/backend/services/gallery.service.d.ts.map +1 -0
  273. package/dist/backend/services/gallery.service.js +326 -0
  274. package/dist/backend/services/gallery.service.js.map +1 -0
  275. package/dist/backend/services/grouped.service.d.ts +39 -0
  276. package/dist/backend/services/grouped.service.d.ts.map +1 -0
  277. package/dist/backend/services/grouped.service.js +136 -0
  278. package/dist/backend/services/grouped.service.js.map +1 -0
  279. package/dist/backend/services/label-resolver.d.ts +16 -0
  280. package/dist/backend/services/label-resolver.d.ts.map +1 -0
  281. package/dist/backend/services/label-resolver.js +43 -0
  282. package/dist/backend/services/label-resolver.js.map +1 -0
  283. package/dist/backend/services/packaging-unit.service.d.ts +28 -0
  284. package/dist/backend/services/packaging-unit.service.d.ts.map +1 -0
  285. package/dist/backend/services/packaging-unit.service.js +197 -0
  286. package/dist/backend/services/packaging-unit.service.js.map +1 -0
  287. package/dist/backend/services/primary-asset-url.d.ts +4 -0
  288. package/dist/backend/services/primary-asset-url.d.ts.map +1 -0
  289. package/dist/backend/services/primary-asset-url.js +55 -0
  290. package/dist/backend/services/primary-asset-url.js.map +1 -0
  291. package/dist/backend/services/product-editor-preferences.service.d.ts +20 -0
  292. package/dist/backend/services/product-editor-preferences.service.d.ts.map +1 -0
  293. package/dist/backend/services/product-editor-preferences.service.js +44 -0
  294. package/dist/backend/services/product-editor-preferences.service.js.map +1 -0
  295. package/dist/backend/services/product-link.service.d.ts +169 -0
  296. package/dist/backend/services/product-link.service.d.ts.map +1 -0
  297. package/dist/backend/services/product-link.service.js +297 -0
  298. package/dist/backend/services/product-link.service.js.map +1 -0
  299. package/dist/backend/services/product-overrides.service.d.ts +77 -0
  300. package/dist/backend/services/product-overrides.service.d.ts.map +1 -0
  301. package/dist/backend/services/product-overrides.service.js +204 -0
  302. package/dist/backend/services/product-overrides.service.js.map +1 -0
  303. package/dist/backend/services/product-scope-context.service.d.ts +36 -0
  304. package/dist/backend/services/product-scope-context.service.d.ts.map +1 -0
  305. package/dist/backend/services/product-scope-context.service.js +106 -0
  306. package/dist/backend/services/product-scope-context.service.js.map +1 -0
  307. package/dist/backend/services/product-type-validations.d.ts +42 -0
  308. package/dist/backend/services/product-type-validations.d.ts.map +1 -0
  309. package/dist/backend/services/product-type-validations.js +55 -0
  310. package/dist/backend/services/product-type-validations.js.map +1 -0
  311. package/dist/backend/services/product-value-resolver.service.d.ts +59 -0
  312. package/dist/backend/services/product-value-resolver.service.d.ts.map +1 -0
  313. package/dist/backend/services/product-value-resolver.service.js +111 -0
  314. package/dist/backend/services/product-value-resolver.service.js.map +1 -0
  315. package/dist/backend/services/system-attribute-scopes.d.ts +18 -0
  316. package/dist/backend/services/system-attribute-scopes.d.ts.map +1 -0
  317. package/dist/backend/services/system-attribute-scopes.js +18 -0
  318. package/dist/backend/services/system-attribute-scopes.js.map +1 -0
  319. package/dist/backend/services/viewer-organization.d.ts +25 -0
  320. package/dist/backend/services/viewer-organization.d.ts.map +1 -0
  321. package/dist/backend/services/viewer-organization.js +31 -0
  322. package/dist/backend/services/viewer-organization.js.map +1 -0
  323. package/dist/manifest.d.ts +204 -0
  324. package/dist/manifest.d.ts.map +1 -0
  325. package/dist/manifest.js +686 -0
  326. package/dist/manifest.js.map +1 -0
  327. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts +33 -0
  328. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.d.ts.map +1 -0
  329. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js +118 -0
  330. package/dist/migrations/20260429T064146_catalog_attribute_sets_init.js.map +1 -0
  331. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts +24 -0
  332. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.d.ts.map +1 -0
  333. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js +31 -0
  334. package/dist/migrations/20260429T070004_catalog_product_attribute_extensions.js.map +1 -0
  335. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts +32 -0
  336. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.d.ts.map +1 -0
  337. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js +58 -0
  338. package/dist/migrations/20260429T102322_catalog_product_type_and_virtual_fields.js.map +1 -0
  339. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts +22 -0
  340. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.d.ts.map +1 -0
  341. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js +66 -0
  342. package/dist/migrations/20260429T111839_catalog_gallery_items_and_labels.js.map +1 -0
  343. package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts +18 -0
  344. package/dist/migrations/20260429T112543_catalog_product_attachments.d.ts.map +1 -0
  345. package/dist/migrations/20260429T112543_catalog_product_attachments.js +73 -0
  346. package/dist/migrations/20260429T112543_catalog_product_attachments.js.map +1 -0
  347. package/dist/migrations/20260429T123726_catalog_product_links.d.ts +21 -0
  348. package/dist/migrations/20260429T123726_catalog_product_links.d.ts.map +1 -0
  349. package/dist/migrations/20260429T123726_catalog_product_links.js +48 -0
  350. package/dist/migrations/20260429T123726_catalog_product_links.js.map +1 -0
  351. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts +23 -0
  352. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.d.ts.map +1 -0
  353. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js +94 -0
  354. package/dist/migrations/20260429T130803_catalog_grouped_and_bundle.js.map +1 -0
  355. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts +24 -0
  356. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.d.ts.map +1 -0
  357. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js +31 -0
  358. package/dist/migrations/20260501T185835_catalog_product_attribute_is_comparable.js.map +1 -0
  359. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts +31 -0
  360. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.d.ts.map +1 -0
  361. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js +133 -0
  362. package/dist/migrations/20260505T060113_catalog_attribute_options_and_flags.js.map +1 -0
  363. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts +16 -0
  364. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.d.ts.map +1 -0
  365. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js +23 -0
  366. package/dist/migrations/20260515T082629_catalog_attribute_mass_editable.js.map +1 -0
  367. package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts +10 -0
  368. package/dist/migrations/20260526T124736_catalog_product_status_inactive.d.ts.map +1 -0
  369. package/dist/migrations/20260526T124736_catalog_product_status_inactive.js +22 -0
  370. package/dist/migrations/20260526T124736_catalog_product_status_inactive.js.map +1 -0
  371. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts +38 -0
  372. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.d.ts.map +1 -0
  373. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js +98 -0
  374. package/dist/migrations/20260611T140346_catalog_product_value_overrides_init.js.map +1 -0
  375. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts +13 -0
  376. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.d.ts.map +1 -0
  377. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js +17 -0
  378. package/dist/migrations/20260611T140400_catalog_attribute_quick_searchable.js.map +1 -0
  379. package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts +16 -0
  380. package/dist/migrations/20260611T140407_catalog_bulk_operations.d.ts.map +1 -0
  381. package/dist/migrations/20260611T140407_catalog_bulk_operations.js +42 -0
  382. package/dist/migrations/20260611T140407_catalog_bulk_operations.js.map +1 -0
  383. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts +14 -0
  384. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.d.ts.map +1 -0
  385. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js +18 -0
  386. package/dist/migrations/20260611T140408_catalog_bulk_operation_logs.js.map +1 -0
  387. package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts +11 -0
  388. package/dist/migrations/20260611T140412_catalog_product_packaging_units.d.ts.map +1 -0
  389. package/dist/migrations/20260611T140412_catalog_product_packaging_units.js +29 -0
  390. package/dist/migrations/20260611T140412_catalog_product_packaging_units.js.map +1 -0
  391. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts +23 -0
  392. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.d.ts.map +1 -0
  393. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js +35 -0
  394. package/dist/migrations/20260718T060659_catalog_bulk_operation_revert_state.js.map +1 -0
  395. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts +12 -0
  396. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.d.ts.map +1 -0
  397. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js +16 -0
  398. package/dist/migrations/20260718T200343_catalog_category_custom_field_values.js.map +1 -0
  399. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts +32 -0
  400. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.d.ts.map +1 -0
  401. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js +286 -0
  402. package/dist/migrations/20260723T230401_catalog_attributes_on_custom_fields.js.map +1 -0
  403. package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts +36 -0
  404. package/dist/migrations/20260804T152604_catalog_widen_product_sku.d.ts.map +1 -0
  405. package/dist/migrations/20260804T152604_catalog_widen_product_sku.js +63 -0
  406. package/dist/migrations/20260804T152604_catalog_widen_product_sku.js.map +1 -0
  407. package/dist/migrations/20260804T160244_catalog_category_activation.d.ts +18 -0
  408. package/dist/migrations/20260804T160244_catalog_category_activation.d.ts.map +1 -0
  409. package/dist/migrations/20260804T160244_catalog_category_activation.js +22 -0
  410. package/dist/migrations/20260804T160244_catalog_category_activation.js.map +1 -0
  411. package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts +27 -0
  412. package/dist/migrations/20260912T094557_catalog_sales_channel_products.d.ts.map +1 -0
  413. package/dist/migrations/20260912T094557_catalog_sales_channel_products.js +44 -0
  414. package/dist/migrations/20260912T094557_catalog_sales_channel_products.js.map +1 -0
  415. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts +27 -0
  416. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.d.ts.map +1 -0
  417. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js +44 -0
  418. package/dist/migrations/20260912T094623_catalog_sales_channel_categories.js.map +1 -0
  419. package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts +36 -0
  420. package/dist/migrations/20260925T125527_catalog_inventory_columns.d.ts.map +1 -0
  421. package/dist/migrations/20260925T125527_catalog_inventory_columns.js +87 -0
  422. package/dist/migrations/20260925T125527_catalog_inventory_columns.js.map +1 -0
  423. package/dist/migrations/index.d.ts +55 -0
  424. package/dist/migrations/index.d.ts.map +1 -0
  425. package/dist/migrations/index.js +80 -0
  426. package/dist/migrations/index.js.map +1 -0
  427. package/dist/ports/index.d.ts +96 -0
  428. package/dist/ports/index.d.ts.map +1 -0
  429. package/dist/ports/index.js +2 -0
  430. package/dist/ports/index.js.map +1 -0
  431. package/docs/catalog/attachments.md +69 -0
  432. package/docs/catalog/attribute-sets.md +63 -0
  433. package/docs/catalog/attributes.md +244 -0
  434. package/docs/catalog/composite-products.md +115 -0
  435. package/docs/catalog/gallery-and-labels.md +73 -0
  436. package/docs/catalog/packaging-units.md +67 -0
  437. package/docs/catalog/per-channel-per-language-overrides.md +234 -0
  438. package/docs/catalog/product-links.md +79 -0
  439. package/docs/catalog.md +207 -0
  440. package/i18n/en.json +649 -0
  441. package/i18n/pl.json +649 -0
  442. package/package.json +109 -0
  443. package/tailwind.css +14 -0
@@ -0,0 +1,197 @@
1
+ /**
2
+ * PackagingUnitService — admin CRUD for product packaging units (feature 043).
3
+ *
4
+ * A packaging unit is a named ordering unit on a product (e.g. "Paleta" = 480
5
+ * pieces). Units apply only to physical, purchasable product types
6
+ * (simple / configurable). At most one unit per product is the default
7
+ * presented on the storefront; setting a new default clears the previous one
8
+ * (last write wins). Names are unique within a product. Hard delete is safe
9
+ * because cart/order/RFQ lines snapshot their own copy.
10
+ */
11
+ import { randomUUID } from 'node:crypto';
12
+ import { UniqueConstraintViolationException } from '@mikro-orm/core';
13
+ import { ERROR_CODES, } from '@endora-commerce/contracts';
14
+ import { HttpError } from '@endora-commerce/platform/http';
15
+ import { Product } from '../entities/product.entity.js';
16
+ import { ProductPackagingUnit } from '../entities/product-packaging-unit.entity.js';
17
+ const ELIGIBLE_TYPES = new Set(['simple', 'configurable']);
18
+ export class PackagingUnitService {
19
+ emFactory;
20
+ commandBus;
21
+ constructor(emFactory,
22
+ /** Feature 054 — audits packaging-unit writes co-transactionally when provided. */
23
+ commandBus) {
24
+ this.emFactory = emFactory;
25
+ this.commandBus = commandBus;
26
+ }
27
+ /** Feature 054 — run a write through the Command Bus (co-transactional audit). */
28
+ async #audited(action, objectId, write) {
29
+ if (this.commandBus) {
30
+ return this.commandBus.run({
31
+ action,
32
+ objectType: 'packaging_unit',
33
+ objectId,
34
+ run: async ({ em }) => {
35
+ const w = await write(em);
36
+ return { result: w.result, before: w.before, after: w.after };
37
+ },
38
+ });
39
+ }
40
+ const em = this.emFactory();
41
+ const w = await write(em);
42
+ await em.flush();
43
+ return w.result;
44
+ }
45
+ async list(productId) {
46
+ const em = this.emFactory();
47
+ await this.#assertProductExists(em, productId);
48
+ const items = await em.find(ProductPackagingUnit, { productId }, { orderBy: { position: 'asc', name: 'asc' } });
49
+ return items.map((i) => this.#dto(i));
50
+ }
51
+ async create(productId, req) {
52
+ const id = randomUUID();
53
+ const unit = await this.#audited('packaging_unit.create', id, async (em) => {
54
+ await this.#assertProductEligible(em, productId);
55
+ const position = req.position ?? (await this.#nextPosition(em, productId));
56
+ const u = em.create(ProductPackagingUnit, {
57
+ id,
58
+ productId,
59
+ name: req.name.trim(),
60
+ baseQuantity: req.baseQuantity,
61
+ position,
62
+ isDefault: req.isDefault ?? false,
63
+ });
64
+ try {
65
+ await em.flush();
66
+ }
67
+ catch (err) {
68
+ throw this.#mapUniqueViolation(err, u.name);
69
+ }
70
+ if (u.isDefault)
71
+ await this.#clearOtherDefaults(em, productId, u.id);
72
+ return {
73
+ result: u,
74
+ before: null,
75
+ after: { productId, name: u.name, baseQuantity: u.baseQuantity, isDefault: u.isDefault },
76
+ };
77
+ });
78
+ return this.#dto(unit);
79
+ }
80
+ async update(productId, unitId, req) {
81
+ const unit = await this.#audited('packaging_unit.update', unitId, async (em) => {
82
+ const u = await this.#findOwned(em, productId, unitId);
83
+ const before = { name: u.name, baseQuantity: u.baseQuantity, isDefault: u.isDefault };
84
+ if (req.name !== undefined)
85
+ u.name = req.name.trim();
86
+ if (req.baseQuantity !== undefined)
87
+ u.baseQuantity = req.baseQuantity;
88
+ if (req.position !== undefined)
89
+ u.position = req.position;
90
+ if (req.isDefault !== undefined)
91
+ u.isDefault = req.isDefault;
92
+ try {
93
+ await em.flush();
94
+ }
95
+ catch (err) {
96
+ throw this.#mapUniqueViolation(err, u.name);
97
+ }
98
+ if (req.isDefault === true)
99
+ await this.#clearOtherDefaults(em, productId, u.id);
100
+ return {
101
+ result: u,
102
+ before,
103
+ after: { name: u.name, baseQuantity: u.baseQuantity, isDefault: u.isDefault },
104
+ };
105
+ });
106
+ return this.#dto(unit);
107
+ }
108
+ async delete(productId, unitId) {
109
+ await this.#audited('packaging_unit.delete', unitId, async (em) => {
110
+ const unit = await this.#findOwned(em, productId, unitId);
111
+ const before = { productId, name: unit.name };
112
+ em.remove(unit);
113
+ return { result: undefined, before, after: null };
114
+ });
115
+ }
116
+ async reorder(productId, req) {
117
+ await this.#audited('packaging_unit.reorder', productId, async (em) => {
118
+ await this.#assertProductExists(em, productId);
119
+ const items = await em.find(ProductPackagingUnit, { productId });
120
+ const byId = new Map(items.map((i) => [i.id, i]));
121
+ let position = 0;
122
+ for (const id of req.orderedIds) {
123
+ const unit = byId.get(id);
124
+ if (!unit) {
125
+ throw new HttpError(404, ERROR_CODES.PACKAGING_UNIT_NOT_FOUND, `Packaging unit ${id} not found under Product ${productId}.`);
126
+ }
127
+ unit.position = position++;
128
+ }
129
+ return { result: undefined, before: null, after: { productId, count: req.orderedIds.length } };
130
+ });
131
+ return this.list(productId);
132
+ }
133
+ // -- INTERNALS ------------------------------------------------------------
134
+ async #assertProductExists(em, productId) {
135
+ const product = await em.findOne(Product, { id: productId });
136
+ if (!product) {
137
+ throw new HttpError(404, ERROR_CODES.PRODUCT_NOT_FOUND, `Product ${productId} not found.`);
138
+ }
139
+ return product;
140
+ }
141
+ async #assertProductEligible(em, productId) {
142
+ const product = await this.#assertProductExists(em, productId);
143
+ if (!ELIGIBLE_TYPES.has(product.type)) {
144
+ throw new HttpError(422, ERROR_CODES.PACKAGING_UNIT_NOT_SUPPORTED_FOR_TYPE, `Packaging units are only supported for simple or configurable products; got "${product.type}".`);
145
+ }
146
+ }
147
+ async #findOwned(em, productId, unitId) {
148
+ const unit = await em.findOne(ProductPackagingUnit, { id: unitId, productId });
149
+ if (!unit) {
150
+ throw new HttpError(404, ERROR_CODES.PACKAGING_UNIT_NOT_FOUND, `Packaging unit ${unitId} not found under Product ${productId}.`);
151
+ }
152
+ return unit;
153
+ }
154
+ /** Clear `isDefault` on every other unit of the product (last write wins). */
155
+ async #clearOtherDefaults(em, productId, keepId) {
156
+ const others = await em.find(ProductPackagingUnit, {
157
+ productId,
158
+ isDefault: true,
159
+ id: { $ne: keepId },
160
+ });
161
+ if (others.length === 0)
162
+ return;
163
+ // No flush here — the enclosing #audited command (or its bus-less fallback)
164
+ // commits these together with the create/update.
165
+ for (const o of others)
166
+ o.isDefault = false;
167
+ }
168
+ /**
169
+ * `em.execute`, not `em.getConnection().execute`: `create` calls this on the
170
+ * Command's `em`, so the next free position is computed from the rows that
171
+ * transaction can see rather than from a pooled connection's older view
172
+ * (issue #207).
173
+ */
174
+ async #nextPosition(em, productId) {
175
+ const rows = (await em.execute(`select coalesce(max(position), -1) + 1 as next_position from product_packaging_units where product_id = ?`, [productId]));
176
+ return rows[0]?.next_position ?? 0;
177
+ }
178
+ #mapUniqueViolation(err, name) {
179
+ if (err instanceof UniqueConstraintViolationException) {
180
+ return new HttpError(409, ERROR_CODES.PACKAGING_UNIT_NAME_CONFLICT, `A packaging unit named "${name}" already exists for this product.`);
181
+ }
182
+ return err;
183
+ }
184
+ #dto(u) {
185
+ return {
186
+ id: u.id,
187
+ productId: u.productId,
188
+ name: u.name,
189
+ baseQuantity: u.baseQuantity,
190
+ position: u.position,
191
+ isDefault: u.isDefault,
192
+ createdAt: u.createdAt.toISOString(),
193
+ updatedAt: u.updatedAt.toISOString(),
194
+ };
195
+ }
196
+ }
197
+ //# sourceMappingURL=packaging-unit.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packaging-unit.service.js","sourceRoot":"","sources":["../../../src/backend/services/packaging-unit.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { AssetReadPort } from '@endora-commerce/contracts';
3
+ export declare function resolvePrimaryAssetUrls(em: EntityManager, assets: AssetReadPort, productIds: readonly string[]): Promise<Map<string, string | null>>;
4
+ //# sourceMappingURL=primary-asset-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primary-asset-url.d.ts","sourceRoot":"","sources":["../../../src/backend/services/primary-asset-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAqDhE,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,aAAa,EACjB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAuDrC"}
@@ -0,0 +1,55 @@
1
+ export async function resolvePrimaryAssetUrls(em, assets, productIds) {
2
+ const result = new Map();
3
+ for (const id of productIds)
4
+ result.set(id, null);
5
+ if (productIds.length === 0)
6
+ return result;
7
+ const ids = [...productIds];
8
+ const galleryRows = await em.execute(`select gi.product_id::text as product_id,
9
+ gi.asset_id::text as asset_id,
10
+ gil.label
11
+ from gallery_items gi
12
+ left join gallery_item_labels gil on gil.gallery_item_id = gi.id
13
+ where gi.product_id in (${ids.map(() => '?').join(',')})
14
+ order by gi.product_id, gi.position asc, gi.id asc`, ids);
15
+ // One call to the owner for every gallery candidate on the page.
16
+ // `assets_library` is a binding dependency of this module, so an absent owner
17
+ // fails closed here rather than quietly rendering an imageless catalogue.
18
+ const galleryUrls = await urlsFor(assets, galleryRows);
19
+ const galleryByProduct = new Map();
20
+ for (const row of galleryRows) {
21
+ if (!galleryUrls.has(row.asset_id))
22
+ continue;
23
+ const list = galleryByProduct.get(row.product_id) ?? [];
24
+ list.push(row);
25
+ galleryByProduct.set(row.product_id, list);
26
+ }
27
+ for (const [productId, rows] of galleryByProduct) {
28
+ const byLabel = (label) => galleryUrls.get(rows.find((r) => r.label === label)?.asset_id ?? '');
29
+ const first = rows[0] ? galleryUrls.get(rows[0].asset_id) : undefined;
30
+ result.set(productId, byLabel('thumbnail') ?? byLabel('base_image') ?? first ?? null);
31
+ }
32
+ const missing = ids.filter((id) => !galleryByProduct.has(id));
33
+ if (missing.length === 0)
34
+ return result;
35
+ const legacyRows = await em.execute(`select pa.product_id::text as product_id, pa.asset_id::text as asset_id, null::text as label
36
+ from product_assets pa
37
+ where pa.product_id in (${missing.map(() => '?').join(',')})
38
+ order by pa.product_id, pa.position asc`, missing);
39
+ const legacyUrls = await urlsFor(assets, legacyRows);
40
+ for (const row of legacyRows) {
41
+ if (result.get(row.product_id))
42
+ continue;
43
+ const url = legacyUrls.get(row.asset_id);
44
+ if (url !== undefined)
45
+ result.set(row.product_id, url);
46
+ }
47
+ return result;
48
+ }
49
+ async function urlsFor(assets, rows) {
50
+ const ids = [...new Set(rows.map((r) => r.asset_id))];
51
+ if (ids.length === 0)
52
+ return new Map();
53
+ return new Map((await assets.findByIds(ids)).map((asset) => [asset.id, asset.storageUrl]));
54
+ }
55
+ //# sourceMappingURL=primary-asset-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primary-asset-url.js","sourceRoot":"","sources":["../../../src/backend/services/primary-asset-url.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import { ProductEditorPreference } from '../entities/product-editor-preference.entity.js';
3
+ /**
4
+ * Feature 022 — per-(admin user, product) memory of the last
5
+ * Sales Channel + Language the editor selected on the product edit
6
+ * page. Read on page load to seed the switchers; upserted on
7
+ * switcher change.
8
+ */
9
+ export declare class ProductEditorPreferencesService {
10
+ private readonly emFactory;
11
+ constructor(emFactory: () => EntityManager);
12
+ /** Fetch the editor's last-selected context for this product. */
13
+ find(adminUserId: string, productId: string): Promise<ProductEditorPreference | null>;
14
+ /** Idempotent upsert. Returns the post-write row. */
15
+ upsert(adminUserId: string, productId: string, fields: {
16
+ lastChannelId: string | null;
17
+ lastLanguageCode: string | null;
18
+ }): Promise<ProductEditorPreference>;
19
+ }
20
+ //# sourceMappingURL=product-editor-preferences.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-editor-preferences.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/product-editor-preferences.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAE1F;;;;;GAKG;AACH,qBAAa,+BAA+B;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAE3D,iEAAiE;IAC3D,IAAI,CACR,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC;IAK1C,qDAAqD;IAC/C,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,GACA,OAAO,CAAC,uBAAuB,CAAC;CAwBpC"}
@@ -0,0 +1,44 @@
1
+ import { ProductEditorPreference } from '../entities/product-editor-preference.entity.js';
2
+ /**
3
+ * Feature 022 — per-(admin user, product) memory of the last
4
+ * Sales Channel + Language the editor selected on the product edit
5
+ * page. Read on page load to seed the switchers; upserted on
6
+ * switcher change.
7
+ */
8
+ export class ProductEditorPreferencesService {
9
+ emFactory;
10
+ constructor(emFactory) {
11
+ this.emFactory = emFactory;
12
+ }
13
+ /** Fetch the editor's last-selected context for this product. */
14
+ async find(adminUserId, productId) {
15
+ const em = this.emFactory();
16
+ return em.findOne(ProductEditorPreference, { adminUserId, productId });
17
+ }
18
+ /** Idempotent upsert. Returns the post-write row. */
19
+ async upsert(adminUserId, productId, fields) {
20
+ // command-coverage-ignore: per-admin UI editor state (last-selected channel +
21
+ // language on the product edit page) — a personal preference, not a catalog
22
+ // domain mutation, so it is not an admin-audit target.
23
+ const em = this.emFactory();
24
+ const existing = await em.findOne(ProductEditorPreference, {
25
+ adminUserId,
26
+ productId,
27
+ });
28
+ if (existing) {
29
+ existing.lastChannelId = fields.lastChannelId;
30
+ existing.lastLanguageCode = fields.lastLanguageCode;
31
+ await em.flush();
32
+ return existing;
33
+ }
34
+ const row = em.create(ProductEditorPreference, {
35
+ adminUserId,
36
+ productId,
37
+ lastChannelId: fields.lastChannelId,
38
+ lastLanguageCode: fields.lastLanguageCode,
39
+ });
40
+ await em.persistAndFlush(row);
41
+ return row;
42
+ }
43
+ }
44
+ //# sourceMappingURL=product-editor-preferences.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-editor-preferences.service.js","sourceRoot":"","sources":["../../../src/backend/services/product-editor-preferences.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,OAAO,+BAA+B;IACb;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,iEAAiE;IACjE,KAAK,CAAC,IAAI,CACR,WAAmB,EACnB,SAAiB;QAEjB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,qDAAqD;IACrD,KAAK,CAAC,MAAM,CACV,WAAmB,EACnB,SAAiB,EACjB,MAGC;QAED,8EAA8E;QAC9E,4EAA4E;QAC5E,uDAAuD;QACvD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE;YACzD,WAAW;YACX,SAAS;SACV,CAAC,CAAC;QACH,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;YAC9C,QAAQ,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;YACpD,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,EAAE;YAC7C,WAAW;YACX,SAAS;YACT,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;SAC1C,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
@@ -0,0 +1,169 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import { type AssetReadPort, type ListingPricePort, type OrganizationDetailsPort, type ProductAudience } from '@endora-commerce/contracts';
3
+ import type { SalesChannelMembershipPort } from '@endora-commerce/platform/kernel';
4
+ import type { CommandBus } from '@endora-commerce/platform/commands';
5
+ import { type ProductLinkKind } from '../entities/product-link.entity.js';
6
+ interface StorefrontContext {
7
+ /**
8
+ * The request's resolved sales channel (feature 053 / FR-002). Always
9
+ * present — the canonical resolver guarantees a concrete channel — so
10
+ * cross/up-sell filtering is unconditional and fails closed (Principle XII).
11
+ * `isPublic` is the price-visibility flag, and `defaultCurrency` is the
12
+ * currency the link tiles quote in — it used to be the literal `'PLN'`, which
13
+ * mislabelled every amount on a channel trading in anything else.
14
+ */
15
+ resolvedChannel: {
16
+ id: string;
17
+ code: string;
18
+ isPublic: boolean;
19
+ defaultCurrency: string;
20
+ };
21
+ /**
22
+ * Who is asking. A cross-sell tile is a card with an Add-to-cart on it, and
23
+ * the cart line it leads to is priced for the buyer's organisation — so a
24
+ * strip quoting the channel price beside a listing quoting the buyer's would
25
+ * put two prices for two products on one page, arrived at two different ways.
26
+ *
27
+ * **Required, not defaulted**, for the reason `CatalogQueryContext` states:
28
+ * the safe default is the anonymous audience, and a caller that forgot to
29
+ * resolve its viewer would then quietly quote every buyer the channel price
30
+ * — a defect that reads as "the negotiated list does not work" and is found
31
+ * by nobody. Both call sites pass it; `tsc` names a third.
32
+ *
33
+ * It is read for the **price** and not, today, for the tile's visibility:
34
+ * `listForStorefront` filters by status and channel membership and has never
35
+ * applied `isProductVisibleTo`, which is issue #227 residue this change does
36
+ * not close. Do not read the presence of this field as the entitlement
37
+ * question having been answered here.
38
+ */
39
+ audience: ProductAudience;
40
+ preferredLanguage?: string | undefined;
41
+ }
42
+ /**
43
+ * ProductLinkService — admin CRUD + storefront read for related/up-sell/
44
+ * cross-sell pairings (feature 002 US4, T104).
45
+ *
46
+ * The service lives between the routes and the DB: routes pass parsed
47
+ * payloads, the service enforces business invariants (no self-link, no
48
+ * dup, target must exist), and surfaces typed errors with the matching
49
+ * ERROR_CODES so route handlers can map them to HTTP responses without
50
+ * sniffing message strings.
51
+ *
52
+ * `bulkCreate` is all-or-nothing: a single bad entry rolls back the whole
53
+ * batch (research §US4: admins curate links in the UI in chunks; partial
54
+ * inserts would surprise them).
55
+ *
56
+ * `listForStorefront` filters out targets whose product is not active,
57
+ * which is what the PDP/cart actually wants — admins should see archived
58
+ * targets in the admin list (so they can clean them up), the storefront
59
+ * shouldn't.
60
+ */
61
+ export interface CreateLinkInput {
62
+ targetProductId: string;
63
+ kind: ProductLinkKind;
64
+ position?: number | undefined;
65
+ }
66
+ export interface ProductLinkRow {
67
+ id: string;
68
+ sourceProductId: string;
69
+ targetProductId: string;
70
+ kind: ProductLinkKind;
71
+ position: number;
72
+ }
73
+ export interface StorefrontLinkSummary {
74
+ id: string;
75
+ kind: ProductLinkKind;
76
+ position: number;
77
+ product: {
78
+ id: string;
79
+ sku: string;
80
+ slug: string;
81
+ name: string;
82
+ primaryAssetUrl: string | null;
83
+ price: {
84
+ amount: number;
85
+ currency: string;
86
+ } | null;
87
+ };
88
+ }
89
+ export declare class ProductLinkService {
90
+ #private;
91
+ private readonly emFactory;
92
+ /** Feature 054 — audits product-link writes co-transactionally when provided. */
93
+ private readonly commandBus?;
94
+ /**
95
+ * Issue #132 — the pricing engine, through the `pricingService` port. A
96
+ * related-product tile is a listing: it prices through the same chain as the
97
+ * catalogue grid, not off the catalogue's legacy default-price attribute.
98
+ */
99
+ private readonly listingPrices?;
100
+ /**
101
+ * Feature 075 — `assets_library`'s read port. The two `join assets` clauses
102
+ * this service used to write are gone; the tile's image is resolved by the
103
+ * shared `resolvePrimaryAssetUrls` helper, which asks the owner for the
104
+ * asset row and keeps the bridge query on this module's own tables.
105
+ */
106
+ private readonly assets?;
107
+ /**
108
+ * Issue #185 — the kernel's channel-membership accessor. The storefront
109
+ * link read below asked `sales_channel_products` in raw SQL, which crosses
110
+ * the boundary while naming no import specifier and is the read
111
+ * Constitution XII reserves to this service.
112
+ *
113
+ * Optional only in the signature, like the two above; a link read that
114
+ * reaches it unwired fails loudly rather than quietly answering the
115
+ * cross-channel set.
116
+ */
117
+ private readonly channelMembership?;
118
+ /**
119
+ * `organizations`' read model — the customer group a group-targeted price
120
+ * list is selected by, which lives on the organisation row. Optional only
121
+ * in the signature, and never reached by an anonymous strip.
122
+ */
123
+ private readonly organizationDetails?;
124
+ constructor(emFactory: () => EntityManager,
125
+ /** Feature 054 — audits product-link writes co-transactionally when provided. */
126
+ commandBus?: CommandBus | undefined,
127
+ /**
128
+ * Issue #132 — the pricing engine, through the `pricingService` port. A
129
+ * related-product tile is a listing: it prices through the same chain as the
130
+ * catalogue grid, not off the catalogue's legacy default-price attribute.
131
+ */
132
+ listingPrices?: ListingPricePort | undefined,
133
+ /**
134
+ * Feature 075 — `assets_library`'s read port. The two `join assets` clauses
135
+ * this service used to write are gone; the tile's image is resolved by the
136
+ * shared `resolvePrimaryAssetUrls` helper, which asks the owner for the
137
+ * asset row and keeps the bridge query on this module's own tables.
138
+ */
139
+ assets?: AssetReadPort | undefined,
140
+ /**
141
+ * Issue #185 — the kernel's channel-membership accessor. The storefront
142
+ * link read below asked `sales_channel_products` in raw SQL, which crosses
143
+ * the boundary while naming no import specifier and is the read
144
+ * Constitution XII reserves to this service.
145
+ *
146
+ * Optional only in the signature, like the two above; a link read that
147
+ * reaches it unwired fails loudly rather than quietly answering the
148
+ * cross-channel set.
149
+ */
150
+ channelMembership?: SalesChannelMembershipPort | undefined,
151
+ /**
152
+ * `organizations`' read model — the customer group a group-targeted price
153
+ * list is selected by, which lives on the organisation row. Optional only
154
+ * in the signature, and never reached by an anonymous strip.
155
+ */
156
+ organizationDetails?: OrganizationDetailsPort | undefined);
157
+ listForAdmin(sourceProductId: string, kind?: ProductLinkKind): Promise<ProductLinkRow[]>;
158
+ bulkCreate(sourceProductId: string, inputs: CreateLinkInput[]): Promise<ProductLinkRow[]>;
159
+ removeLink(sourceProductId: string, linkId: string): Promise<void>;
160
+ /**
161
+ * Storefront read — drops links whose target product is not active or
162
+ * not visible in the requested sales channel; localizes name to the
163
+ * caller's preferred language.
164
+ */
165
+ listForStorefront(sourceProductId: string, ctx: StorefrontContext, kind?: ProductLinkKind): Promise<StorefrontLinkSummary[]>;
166
+ reorderForKind(sourceProductId: string, kind: ProductLinkKind, linkIds: string[]): Promise<void>;
167
+ }
168
+ export {};
169
+ //# sourceMappingURL=product-link.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-link.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/product-link.service.ts"],"names":[],"mappings":"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"}