@porulle/core 0.10.8 → 0.13.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 (360) hide show
  1. package/dist/auth/auth-schema-guard.d.ts +2444 -0
  2. package/dist/auth/auth-schema-guard.d.ts.map +1 -0
  3. package/dist/auth/auth-schema-guard.js +113 -0
  4. package/dist/auth/auth-schema.d.ts +228 -0
  5. package/dist/auth/auth-schema.d.ts.map +1 -1
  6. package/dist/auth/auth-schema.js +24 -2
  7. package/dist/auth/middleware.d.ts +1 -0
  8. package/dist/auth/middleware.d.ts.map +1 -1
  9. package/dist/auth/middleware.js +13 -5
  10. package/dist/auth/org.d.ts +8 -2
  11. package/dist/auth/org.d.ts.map +1 -1
  12. package/dist/auth/org.js +12 -4
  13. package/dist/auth/organization-guard.d.ts +5 -0
  14. package/dist/auth/organization-guard.d.ts.map +1 -0
  15. package/dist/auth/organization-guard.js +124 -0
  16. package/dist/auth/permissions.d.ts +10 -0
  17. package/dist/auth/permissions.d.ts.map +1 -1
  18. package/dist/auth/permissions.js +31 -7
  19. package/dist/auth/role-authority.d.ts +44 -0
  20. package/dist/auth/role-authority.d.ts.map +1 -0
  21. package/dist/auth/role-authority.js +85 -0
  22. package/dist/auth/setup.d.ts.map +1 -1
  23. package/dist/auth/setup.js +17 -0
  24. package/dist/auth/strict-org-resolution.d.ts.map +1 -1
  25. package/dist/auth/strict-org-resolution.js +9 -1
  26. package/dist/auth/types.d.ts +1 -1
  27. package/dist/auth/types.d.ts.map +1 -1
  28. package/dist/config/defaults.d.ts.map +1 -1
  29. package/dist/config/defaults.js +2 -0
  30. package/dist/config/types.d.ts +33 -4
  31. package/dist/config/types.d.ts.map +1 -1
  32. package/dist/hooks/checkout.d.ts.map +1 -1
  33. package/dist/hooks/checkout.js +10 -9
  34. package/dist/index.d.ts +9 -6
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +5 -3
  37. package/dist/interfaces/rest/audit-middleware.d.ts.map +1 -1
  38. package/dist/interfaces/rest/audit-middleware.js +2 -0
  39. package/dist/interfaces/rest/customer-portal.d.ts.map +1 -1
  40. package/dist/interfaces/rest/customer-portal.js +9 -8
  41. package/dist/interfaces/rest/index.d.ts.map +1 -1
  42. package/dist/interfaces/rest/index.js +4 -0
  43. package/dist/interfaces/rest/route-coverage.d.ts +14 -0
  44. package/dist/interfaces/rest/route-coverage.d.ts.map +1 -0
  45. package/dist/interfaces/rest/route-coverage.js +81 -0
  46. package/dist/interfaces/rest/router.d.ts +7 -2
  47. package/dist/interfaces/rest/router.d.ts.map +1 -1
  48. package/dist/interfaces/rest/router.js +8 -4
  49. package/dist/interfaces/rest/routes/admin/compensation-failures.d.ts.map +1 -1
  50. package/dist/interfaces/rest/routes/admin/compensation-failures.js +7 -5
  51. package/dist/interfaces/rest/routes/admin/custom-field-proposals.d.ts +5 -0
  52. package/dist/interfaces/rest/routes/admin/custom-field-proposals.d.ts.map +1 -0
  53. package/dist/interfaces/rest/routes/admin/custom-field-proposals.js +22 -0
  54. package/dist/interfaces/rest/routes/admin/entity-field-definitions.d.ts +5 -0
  55. package/dist/interfaces/rest/routes/admin/entity-field-definitions.d.ts.map +1 -0
  56. package/dist/interfaces/rest/routes/admin/entity-field-definitions.js +39 -0
  57. package/dist/interfaces/rest/routes/admin/permissions.d.ts +1 -1
  58. package/dist/interfaces/rest/routes/admin/permissions.d.ts.map +1 -1
  59. package/dist/interfaces/rest/routes/admin/permissions.js +2 -0
  60. package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -1
  61. package/dist/interfaces/rest/routes/admin/staff.js +126 -66
  62. package/dist/interfaces/rest/routes/admin-jobs.js +3 -3
  63. package/dist/interfaces/rest/routes/audit.js +3 -3
  64. package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
  65. package/dist/interfaces/rest/routes/carts.js +13 -10
  66. package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
  67. package/dist/interfaces/rest/routes/catalog.js +47 -4
  68. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  69. package/dist/interfaces/rest/routes/checkout.js +30 -35
  70. package/dist/interfaces/rest/routes/documents.d.ts.map +1 -1
  71. package/dist/interfaces/rest/routes/documents.js +10 -5
  72. package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
  73. package/dist/interfaces/rest/routes/inventory.js +2 -0
  74. package/dist/interfaces/rest/routes/media.d.ts.map +1 -1
  75. package/dist/interfaces/rest/routes/media.js +7 -3
  76. package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
  77. package/dist/interfaces/rest/routes/orders.js +26 -8
  78. package/dist/interfaces/rest/routes/pricing.js +2 -2
  79. package/dist/interfaces/rest/routes/promotions.d.ts.map +1 -1
  80. package/dist/interfaces/rest/routes/promotions.js +13 -10
  81. package/dist/interfaces/rest/routes/search.d.ts.map +1 -1
  82. package/dist/interfaces/rest/routes/search.js +14 -1
  83. package/dist/interfaces/rest/schemas/admin-custom-field-proposals.d.ts +134 -0
  84. package/dist/interfaces/rest/schemas/admin-custom-field-proposals.d.ts.map +1 -0
  85. package/dist/interfaces/rest/schemas/admin-custom-field-proposals.js +26 -0
  86. package/dist/interfaces/rest/schemas/admin-entity-field-definitions.d.ts +592 -0
  87. package/dist/interfaces/rest/schemas/admin-entity-field-definitions.d.ts.map +1 -0
  88. package/dist/interfaces/rest/schemas/admin-entity-field-definitions.js +109 -0
  89. package/dist/interfaces/rest/schemas/carts.d.ts +7 -0
  90. package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
  91. package/dist/interfaces/rest/schemas/catalog.d.ts +1364 -401
  92. package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
  93. package/dist/interfaces/rest/schemas/catalog.js +86 -0
  94. package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
  95. package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
  96. package/dist/interfaces/rest/schemas/orders.d.ts +204 -0
  97. package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
  98. package/dist/interfaces/rest/schemas/pricing.d.ts +1 -0
  99. package/dist/interfaces/rest/schemas/pricing.d.ts.map +1 -1
  100. package/dist/interfaces/rest/schemas/responses.d.ts +71 -0
  101. package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
  102. package/dist/interfaces/rest/schemas/search.d.ts +1 -0
  103. package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
  104. package/dist/interfaces/rest/schemas/search.js +1 -0
  105. package/dist/interfaces/rest/utils.d.ts +15 -0
  106. package/dist/interfaces/rest/utils.d.ts.map +1 -1
  107. package/dist/interfaces/rest/utils.js +45 -2
  108. package/dist/kernel/compensation/executor.js +2 -2
  109. package/dist/kernel/database/tx-context.d.ts +8 -0
  110. package/dist/kernel/database/tx-context.d.ts.map +1 -1
  111. package/dist/kernel/database/tx-context.js +13 -0
  112. package/dist/kernel/hooks/create-context.d.ts +2 -0
  113. package/dist/kernel/hooks/create-context.d.ts.map +1 -1
  114. package/dist/kernel/hooks/create-context.js +1 -0
  115. package/dist/kernel/hooks/types.d.ts +2 -0
  116. package/dist/kernel/hooks/types.d.ts.map +1 -1
  117. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  118. package/dist/kernel/plugin/manifest.js +9 -5
  119. package/dist/modules/analytics/service.js +2 -2
  120. package/dist/modules/audit/service.js +3 -3
  121. package/dist/modules/cart/repository/index.d.ts +13 -7
  122. package/dist/modules/cart/repository/index.d.ts.map +1 -1
  123. package/dist/modules/cart/repository/index.js +16 -10
  124. package/dist/modules/cart/schema.d.ts +17 -0
  125. package/dist/modules/cart/schema.d.ts.map +1 -1
  126. package/dist/modules/cart/schema.js +4 -0
  127. package/dist/modules/cart/service.d.ts +22 -9
  128. package/dist/modules/cart/service.d.ts.map +1 -1
  129. package/dist/modules/cart/service.js +57 -33
  130. package/dist/modules/catalog/brand-service.js +7 -7
  131. package/dist/modules/catalog/category-service.js +7 -7
  132. package/dist/modules/catalog/entity-service.d.ts +19 -10
  133. package/dist/modules/catalog/entity-service.d.ts.map +1 -1
  134. package/dist/modules/catalog/entity-service.js +180 -51
  135. package/dist/modules/catalog/module.d.ts +6 -1
  136. package/dist/modules/catalog/module.d.ts.map +1 -1
  137. package/dist/modules/catalog/module.js +6 -1
  138. package/dist/modules/catalog/ownership.d.ts +5 -0
  139. package/dist/modules/catalog/ownership.d.ts.map +1 -0
  140. package/dist/modules/catalog/ownership.js +11 -0
  141. package/dist/modules/catalog/read-policy.d.ts +9 -0
  142. package/dist/modules/catalog/read-policy.d.ts.map +1 -0
  143. package/dist/modules/catalog/read-policy.js +8 -0
  144. package/dist/modules/catalog/repository/index.d.ts +55 -3
  145. package/dist/modules/catalog/repository/index.d.ts.map +1 -1
  146. package/dist/modules/catalog/repository/index.js +335 -6
  147. package/dist/modules/catalog/revision.d.ts +4 -0
  148. package/dist/modules/catalog/revision.d.ts.map +1 -0
  149. package/dist/modules/catalog/revision.js +33 -0
  150. package/dist/modules/catalog/schema.d.ts +979 -110
  151. package/dist/modules/catalog/schema.d.ts.map +1 -1
  152. package/dist/modules/catalog/schema.js +112 -2
  153. package/dist/modules/catalog/schemas.d.ts +2 -0
  154. package/dist/modules/catalog/schemas.d.ts.map +1 -1
  155. package/dist/modules/catalog/schemas.js +2 -0
  156. package/dist/modules/catalog/service.d.ts +80 -15
  157. package/dist/modules/catalog/service.d.ts.map +1 -1
  158. package/dist/modules/catalog/service.js +522 -14
  159. package/dist/modules/channels/adapter.d.ts +85 -0
  160. package/dist/modules/channels/adapter.d.ts.map +1 -1
  161. package/dist/modules/channels/adapter.js +9 -1
  162. package/dist/modules/customers/module.d.ts.map +1 -1
  163. package/dist/modules/customers/module.js +1 -0
  164. package/dist/modules/customers/service.d.ts +2 -0
  165. package/dist/modules/customers/service.d.ts.map +1 -1
  166. package/dist/modules/customers/service.js +21 -20
  167. package/dist/modules/documents/module.d.ts.map +1 -1
  168. package/dist/modules/documents/module.js +1 -0
  169. package/dist/modules/documents/service.d.ts +18 -4
  170. package/dist/modules/documents/service.d.ts.map +1 -1
  171. package/dist/modules/documents/service.js +54 -16
  172. package/dist/modules/fulfillment/module.d.ts.map +1 -1
  173. package/dist/modules/fulfillment/module.js +1 -0
  174. package/dist/modules/fulfillment/service.d.ts +2 -0
  175. package/dist/modules/fulfillment/service.d.ts.map +1 -1
  176. package/dist/modules/fulfillment/service.js +15 -6
  177. package/dist/modules/inventory/service.d.ts.map +1 -1
  178. package/dist/modules/inventory/service.js +15 -14
  179. package/dist/modules/media/module.d.ts +68 -0
  180. package/dist/modules/media/module.d.ts.map +1 -1
  181. package/dist/modules/media/module.js +2 -0
  182. package/dist/modules/media/schema.d.ts +70 -0
  183. package/dist/modules/media/schema.d.ts.map +1 -1
  184. package/dist/modules/media/schema.js +20 -2
  185. package/dist/modules/media/service.d.ts +8 -1
  186. package/dist/modules/media/service.d.ts.map +1 -1
  187. package/dist/modules/media/service.js +71 -23
  188. package/dist/modules/orders/guest-access.d.ts +27 -0
  189. package/dist/modules/orders/guest-access.d.ts.map +1 -0
  190. package/dist/modules/orders/guest-access.js +46 -0
  191. package/dist/modules/orders/module.d.ts.map +1 -1
  192. package/dist/modules/orders/module.js +1 -0
  193. package/dist/modules/orders/quote.d.ts.map +1 -1
  194. package/dist/modules/orders/quote.js +1 -0
  195. package/dist/modules/orders/repository/index.d.ts +1 -1
  196. package/dist/modules/orders/repository/index.d.ts.map +1 -1
  197. package/dist/modules/orders/repository/index.js +2 -2
  198. package/dist/modules/orders/schema.d.ts +17 -0
  199. package/dist/modules/orders/schema.d.ts.map +1 -1
  200. package/dist/modules/orders/schema.js +5 -3
  201. package/dist/modules/orders/service.d.ts +16 -7
  202. package/dist/modules/orders/service.d.ts.map +1 -1
  203. package/dist/modules/orders/service.js +184 -55
  204. package/dist/modules/pricing/module.d.ts.map +1 -1
  205. package/dist/modules/pricing/module.js +1 -0
  206. package/dist/modules/pricing/schema.d.ts +17 -0
  207. package/dist/modules/pricing/schema.d.ts.map +1 -1
  208. package/dist/modules/pricing/schema.js +1 -0
  209. package/dist/modules/pricing/schemas.d.ts +1 -0
  210. package/dist/modules/pricing/schemas.d.ts.map +1 -1
  211. package/dist/modules/pricing/schemas.js +1 -0
  212. package/dist/modules/pricing/service.d.ts +2 -0
  213. package/dist/modules/pricing/service.d.ts.map +1 -1
  214. package/dist/modules/pricing/service.js +18 -12
  215. package/dist/modules/promotions/module.d.ts.map +1 -1
  216. package/dist/modules/promotions/module.js +1 -0
  217. package/dist/modules/promotions/service.d.ts +3 -0
  218. package/dist/modules/promotions/service.d.ts.map +1 -1
  219. package/dist/modules/promotions/service.js +19 -11
  220. package/dist/modules/search/adapter.d.ts +8 -0
  221. package/dist/modules/search/adapter.d.ts.map +1 -1
  222. package/dist/modules/search/module.d.ts.map +1 -1
  223. package/dist/modules/search/module.js +3 -0
  224. package/dist/modules/search/service.d.ts +5 -0
  225. package/dist/modules/search/service.d.ts.map +1 -1
  226. package/dist/modules/search/service.js +131 -11
  227. package/dist/modules/settings/module.d.ts.map +1 -1
  228. package/dist/modules/settings/module.js +1 -0
  229. package/dist/modules/settings/service.d.ts +3 -0
  230. package/dist/modules/settings/service.d.ts.map +1 -1
  231. package/dist/modules/settings/service.js +6 -4
  232. package/dist/modules/shipping/service.js +9 -9
  233. package/dist/modules/tax/module.d.ts.map +1 -1
  234. package/dist/modules/tax/module.js +1 -0
  235. package/dist/modules/tax/service.d.ts +3 -0
  236. package/dist/modules/tax/service.d.ts.map +1 -1
  237. package/dist/modules/tax/service.js +11 -9
  238. package/dist/modules/webhooks/hook.js +2 -2
  239. package/dist/modules/webhooks/module.d.ts.map +1 -1
  240. package/dist/modules/webhooks/module.js +1 -0
  241. package/dist/modules/webhooks/service.d.ts +2 -0
  242. package/dist/modules/webhooks/service.d.ts.map +1 -1
  243. package/dist/modules/webhooks/service.js +4 -4
  244. package/dist/runtime/kernel-modules.d.ts +73 -0
  245. package/dist/runtime/kernel-modules.d.ts.map +1 -1
  246. package/dist/runtime/server.d.ts.map +1 -1
  247. package/dist/runtime/server.js +10 -2
  248. package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
  249. package/dist/test-utils/create-pglite-adapter.js +35 -13
  250. package/dist/test-utils/create-test-config.d.ts.map +1 -1
  251. package/dist/test-utils/create-test-config.js +4 -0
  252. package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
  253. package/dist/test-utils/rest-api-test-utils.js +2 -0
  254. package/dist/test-utils/test-actors.js +2 -2
  255. package/dist/utils/id.d.ts +2 -0
  256. package/dist/utils/id.d.ts.map +1 -1
  257. package/dist/utils/id.js +11 -0
  258. package/package.json +6 -5
  259. package/src/auth/auth-schema-guard.ts +143 -0
  260. package/src/auth/auth-schema.ts +50 -19
  261. package/src/auth/middleware.ts +17 -5
  262. package/src/auth/org.ts +15 -3
  263. package/src/auth/organization-guard.ts +158 -0
  264. package/src/auth/permissions.ts +31 -8
  265. package/src/auth/role-authority.ts +107 -0
  266. package/src/auth/setup.ts +17 -0
  267. package/src/auth/strict-org-resolution.ts +7 -1
  268. package/src/auth/types.ts +1 -1
  269. package/src/config/defaults.ts +2 -0
  270. package/src/config/types.ts +32 -4
  271. package/src/hooks/checkout.ts +19 -12
  272. package/src/index.ts +30 -6
  273. package/src/interfaces/rest/audit-middleware.ts +2 -0
  274. package/src/interfaces/rest/customer-portal.ts +31 -24
  275. package/src/interfaces/rest/index.ts +4 -0
  276. package/src/interfaces/rest/route-coverage.ts +103 -0
  277. package/src/interfaces/rest/router.ts +16 -10
  278. package/src/interfaces/rest/routes/admin/compensation-failures.ts +8 -5
  279. package/src/interfaces/rest/routes/admin/custom-field-proposals.ts +37 -0
  280. package/src/interfaces/rest/routes/admin/entity-field-definitions.ts +89 -0
  281. package/src/interfaces/rest/routes/admin/permissions.ts +3 -1
  282. package/src/interfaces/rest/routes/admin/staff.ts +161 -72
  283. package/src/interfaces/rest/routes/admin-jobs.ts +3 -3
  284. package/src/interfaces/rest/routes/audit.ts +3 -3
  285. package/src/interfaces/rest/routes/carts.ts +17 -7
  286. package/src/interfaces/rest/routes/catalog.ts +96 -0
  287. package/src/interfaces/rest/routes/checkout.ts +41 -38
  288. package/src/interfaces/rest/routes/documents.ts +15 -1
  289. package/src/interfaces/rest/routes/inventory.ts +2 -0
  290. package/src/interfaces/rest/routes/media.ts +8 -3
  291. package/src/interfaces/rest/routes/orders.ts +27 -8
  292. package/src/interfaces/rest/routes/pricing.ts +2 -2
  293. package/src/interfaces/rest/routes/promotions.ts +12 -9
  294. package/src/interfaces/rest/routes/search.ts +19 -1
  295. package/src/interfaces/rest/schemas/admin-custom-field-proposals.ts +29 -0
  296. package/src/interfaces/rest/schemas/admin-entity-field-definitions.ts +120 -0
  297. package/src/interfaces/rest/schemas/catalog.ts +92 -0
  298. package/src/interfaces/rest/schemas/search.ts +2 -0
  299. package/src/interfaces/rest/utils.ts +61 -2
  300. package/src/kernel/compensation/executor.ts +2 -2
  301. package/src/kernel/database/tx-context.ts +25 -0
  302. package/src/kernel/hooks/create-context.ts +3 -0
  303. package/src/kernel/hooks/types.ts +2 -0
  304. package/src/kernel/plugin/manifest.ts +9 -5
  305. package/src/modules/analytics/service.ts +2 -2
  306. package/src/modules/audit/service.ts +3 -3
  307. package/src/modules/cart/repository/index.ts +22 -8
  308. package/src/modules/cart/schema.ts +4 -0
  309. package/src/modules/cart/service.ts +62 -27
  310. package/src/modules/catalog/brand-service.ts +7 -7
  311. package/src/modules/catalog/category-service.ts +7 -7
  312. package/src/modules/catalog/entity-service.ts +188 -53
  313. package/src/modules/catalog/module.ts +15 -0
  314. package/src/modules/catalog/ownership.ts +17 -0
  315. package/src/modules/catalog/read-policy.ts +16 -0
  316. package/src/modules/catalog/repository/index.ts +566 -4
  317. package/src/modules/catalog/revision.ts +35 -0
  318. package/src/modules/catalog/schema.ts +169 -1
  319. package/src/modules/catalog/schemas.ts +2 -0
  320. package/src/modules/catalog/service.ts +766 -26
  321. package/src/modules/channels/adapter.ts +107 -1
  322. package/src/modules/customers/module.ts +2 -0
  323. package/src/modules/customers/service.ts +23 -22
  324. package/src/modules/documents/module.ts +2 -0
  325. package/src/modules/documents/service.ts +74 -11
  326. package/src/modules/fulfillment/module.ts +2 -0
  327. package/src/modules/fulfillment/service.ts +17 -6
  328. package/src/modules/inventory/service.ts +15 -24
  329. package/src/modules/media/module.ts +2 -0
  330. package/src/modules/media/schema.ts +23 -2
  331. package/src/modules/media/service.ts +89 -28
  332. package/src/modules/orders/guest-access.ts +55 -0
  333. package/src/modules/orders/module.ts +1 -0
  334. package/src/modules/orders/quote.ts +1 -0
  335. package/src/modules/orders/repository/index.ts +2 -0
  336. package/src/modules/orders/schema.ts +5 -3
  337. package/src/modules/orders/service.ts +302 -52
  338. package/src/modules/pricing/module.ts +2 -0
  339. package/src/modules/pricing/schema.ts +1 -0
  340. package/src/modules/pricing/schemas.ts +1 -0
  341. package/src/modules/pricing/service.ts +21 -18
  342. package/src/modules/promotions/module.ts +2 -0
  343. package/src/modules/promotions/service.ts +25 -16
  344. package/src/modules/search/adapter.ts +8 -0
  345. package/src/modules/search/module.ts +3 -0
  346. package/src/modules/search/service.ts +142 -12
  347. package/src/modules/settings/module.ts +2 -0
  348. package/src/modules/settings/service.ts +8 -4
  349. package/src/modules/shipping/service.ts +9 -9
  350. package/src/modules/tax/module.ts +1 -0
  351. package/src/modules/tax/service.ts +13 -9
  352. package/src/modules/webhooks/hook.ts +2 -2
  353. package/src/modules/webhooks/module.ts +2 -0
  354. package/src/modules/webhooks/service.ts +6 -4
  355. package/src/runtime/server.ts +16 -2
  356. package/src/test-utils/create-pglite-adapter.ts +34 -12
  357. package/src/test-utils/create-test-config.ts +10 -6
  358. package/src/test-utils/rest-api-test-utils.ts +2 -0
  359. package/src/test-utils/test-actors.ts +2 -2
  360. package/src/utils/id.ts +20 -0
@@ -1,6 +1,7 @@
1
1
  import { createHmac } from "node:crypto";
2
- import { resolveOrgId } from "../../auth/org.js";
3
- import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
2
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
3
+ import { assertPermission } from "../../auth/permissions.js";
4
+ import { CommerceNotFoundError, CommerceValidationError, toCommerceError } from "../../kernel/errors.js";
4
5
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
5
6
  import { createHookContext } from "../../kernel/hooks/create-context.js";
6
7
  import { Err, Ok } from "../../kernel/result.js";
@@ -133,7 +134,7 @@ export class FulfillmentService {
133
134
  this.strategies.set("appointment", new AppointmentFulfillmentStrategy());
134
135
  }
135
136
  async fulfillOrder(orderId, actor, ctx) {
136
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
137
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
137
138
  const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
138
139
  if (!order)
139
140
  return Err(new CommerceNotFoundError("Order not found."));
@@ -185,6 +186,7 @@ export class FulfillmentService {
185
186
  services: this.deps.services,
186
187
  context: { moduleName: "fulfillment" },
187
188
  database: { db: this.deps.database.db },
189
+ commerceConfig: this.deps.config,
188
190
  });
189
191
  await runAfterHooks(afterHooks, null, record, "create", hookCtx);
190
192
  // Create a fulfillment line item linking this fulfillment to the order line item
@@ -204,7 +206,13 @@ export class FulfillmentService {
204
206
  * fulfillment (per-line quantities) and multiple fulfillments per order.
205
207
  */
206
208
  async createFulfillment(input, actor, ctx) {
207
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
209
+ try {
210
+ assertPermission(actor ?? null, "orders:update");
211
+ }
212
+ catch (error) {
213
+ return Err(toCommerceError(error));
214
+ }
215
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
208
216
  const order = await this.deps.ordersRepository.findById(orgId, input.orderId, ctx);
209
217
  if (!order)
210
218
  return Err(new CommerceNotFoundError("Order not found."));
@@ -246,7 +254,7 @@ export class FulfillmentService {
246
254
  fulfillmentId: created.id,
247
255
  eventType: "created",
248
256
  toStatus: status,
249
- ...(actor?.userId !== undefined ? { actorId: actor.userId } : {}),
257
+ ...(actor?.userId != null ? { actorId: actor.userId } : {}),
250
258
  description: input.trackingNumber
251
259
  ? `Shipment recorded (${input.trackingNumber})`
252
260
  : "Fulfillment recorded",
@@ -278,6 +286,7 @@ export class FulfillmentService {
278
286
  services: this.deps.services,
279
287
  context: { moduleName: "fulfillment" },
280
288
  database: { db: this.deps.database.db },
289
+ commerceConfig: this.deps.config,
281
290
  });
282
291
  await runAfterHooks(afterHooks, null, record, "create", hookCtx);
283
292
  return Ok(record);
@@ -328,7 +337,7 @@ export class FulfillmentService {
328
337
  if (!matchedRecord) {
329
338
  return Err(new CommerceNotFoundError("Digital download not found."));
330
339
  }
331
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
340
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
332
341
  const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
333
342
  if (!order || order.customerId !== userId) {
334
343
  return Err(new CommerceNotFoundError("Order not found."));
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/inventory/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/inventory/service.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
2
  import { assertPermission } from "../../auth/permissions.js";
3
3
  import { CommerceInventoryRecordNotFoundError, CommerceNotFoundError, CommerceValidationError, INVENTORY_RECORD_NOT_FOUND_MESSAGE, toCommerceError, } from "../../kernel/errors.js";
4
4
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
@@ -20,7 +20,7 @@ export class InventoryService {
20
20
  }
21
21
  async pickWarehouse(actor, ctx, orgIdOverride) {
22
22
  const orgId = orgIdOverride ??
23
- resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
23
+ resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
24
24
  const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
25
25
  const sorted = warehouses.sort((a, b) => a.priority - b.priority);
26
26
  if (sorted.length > 0) {
@@ -41,7 +41,7 @@ export class InventoryService {
41
41
  if (!input.name || !input.code) {
42
42
  return Err(new CommerceValidationError("Warehouse name and code are required."));
43
43
  }
44
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
44
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
45
45
  const warehouse = await this.repo.createWarehouse({
46
46
  organizationId: orgId,
47
47
  name: input.name,
@@ -54,17 +54,17 @@ export class InventoryService {
54
54
  return Ok(warehouse);
55
55
  }
56
56
  async listWarehouses(actor, ctx) {
57
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
57
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
58
58
  const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
59
59
  return Ok(warehouses.sort((a, b) => a.priority - b.priority));
60
60
  }
61
61
  async getAvailable(entityId, variantId, ctx, actor) {
62
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
62
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
63
63
  const available = await this.repo.getAvailableQuantity(orgId, entityId, variantId, ctx);
64
64
  return Ok(available);
65
65
  }
66
66
  async listLevels(params, actor, ctx) {
67
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
67
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
68
68
  if (params?.entityId) {
69
69
  const levels = await this.repo.findLevelsByEntityId(orgId, params.entityId, ctx);
70
70
  return Ok(levels);
@@ -77,12 +77,12 @@ export class InventoryService {
77
77
  return Ok(levels);
78
78
  }
79
79
  async checkMultiple(entityIds, actor, ctx) {
80
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
80
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
81
81
  const data = await this.repo.getAvailableQuantities(orgId, entityIds, ctx);
82
82
  return Ok(data);
83
83
  }
84
84
  async getLevelsByEntityId(entityId, ctx, actor) {
85
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
85
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
86
86
  const levels = await this.repo.findLevelsByEntityId(orgId, entityId, ctx);
87
87
  return Ok(levels);
88
88
  }
@@ -90,7 +90,7 @@ export class InventoryService {
90
90
  if (input.quantity <= 0) {
91
91
  return Err(new CommerceValidationError("Reservation quantity must be greater than zero."));
92
92
  }
93
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
93
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
94
94
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
95
95
  const performedBy = input.performedBy ?? actor?.userId ?? "system";
96
96
  const variantId = input.variantId ?? null;
@@ -119,7 +119,7 @@ export class InventoryService {
119
119
  });
120
120
  }
121
121
  async release(input, actor, ctx) {
122
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
122
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
123
123
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
124
124
  const performedBy = input.performedBy ?? actor?.userId ?? "system";
125
125
  const variantId = input.variantId ?? null;
@@ -177,7 +177,7 @@ export class InventoryService {
177
177
  const variantId = input.variantId ?? null;
178
178
  const performedBy = input.performedBy ?? actor?.userId ?? "system";
179
179
  const doAdjust = async (txCtx) => {
180
- const orgId = resolveOrgId(actor ?? txCtx.actor ?? null, undefined, this.deps.config);
180
+ const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor ?? null, this.deps.config);
181
181
  // Lock the level first so `before` and the write are atomic.
182
182
  const existing = await this.repo.findLevelForUpdate(orgId, input.entityId, variantId, warehouseId, txCtx);
183
183
  const before = existing?.quantityOnHand ?? 0;
@@ -237,6 +237,7 @@ export class InventoryService {
237
237
  services: this.deps.services,
238
238
  context: { moduleName: "inventory" },
239
239
  database: { db: this.deps.database.db },
240
+ commerceConfig: this.deps.config,
240
241
  });
241
242
  const afterHooks = this.deps.hooks.resolve("inventory.afterAdjust");
242
243
  await runAfterHooks(afterHooks, null, level, "update", hookCtx);
@@ -264,7 +265,7 @@ export class InventoryService {
264
265
  */
265
266
  async setAbsolute(input, actor, ctx) {
266
267
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
267
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
268
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
268
269
  const existingLevel = await this.repo.findLevelByKey(orgId, input.entityId, warehouseId, input.variantId, ctx);
269
270
  const currentOnHand = existingLevel?.quantityOnHand ?? 0;
270
271
  const delta = input.quantity - currentOnHand;
@@ -290,7 +291,7 @@ export class InventoryService {
290
291
  */
291
292
  async deductForFulfillment(input, ctx) {
292
293
  const orgId = input.orgId ??
293
- resolveOrgId(ctx?.actor ?? null, undefined, this.deps.config);
294
+ resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
294
295
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(null, ctx, orgId));
295
296
  const variantId = input.variantId ?? null;
296
297
  const level = await this.repo.findLevelByKey(orgId, input.entityId, warehouseId, variantId != null ? variantId : undefined, ctx);
@@ -314,7 +315,7 @@ export class InventoryService {
314
315
  return Ok(undefined);
315
316
  }
316
317
  async setUnitCost(entityId, warehouseId, unitCost, variantId, ctx) {
317
- const orgId = resolveOrgId(ctx?.actor ?? null, undefined, this.deps.config);
318
+ const orgId = resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
318
319
  const level = await this.repo.findLevelByKey(orgId, entityId, warehouseId, variantId, ctx);
319
320
  if (!level) {
320
321
  return Err(new CommerceNotFoundError(`Inventory level not found for entity ${entityId} at warehouse ${warehouseId}.`));
@@ -176,6 +176,57 @@ export declare const mediaModule: import("../../kernel/module/define.js").AppMod
176
176
  }, {}, {
177
177
  $type: Record<string, unknown>;
178
178
  }>;
179
+ origin: import("drizzle-orm/pg-core").PgColumn<{
180
+ name: "origin";
181
+ tableName: "media_assets";
182
+ dataType: "string";
183
+ columnType: "PgEnumColumn";
184
+ data: "generated" | "merchant" | "imported";
185
+ driverParam: string;
186
+ notNull: true;
187
+ hasDefault: true;
188
+ isPrimaryKey: false;
189
+ isAutoincrement: false;
190
+ hasRuntimeDefault: false;
191
+ enumValues: ["merchant", "generated", "imported"];
192
+ baseColumn: never;
193
+ identity: undefined;
194
+ generated: undefined;
195
+ }, {}, {}>;
196
+ confidence: import("drizzle-orm/pg-core").PgColumn<{
197
+ name: "confidence";
198
+ tableName: "media_assets";
199
+ dataType: "string";
200
+ columnType: "PgNumeric";
201
+ data: string;
202
+ driverParam: string;
203
+ notNull: false;
204
+ hasDefault: false;
205
+ isPrimaryKey: false;
206
+ isAutoincrement: false;
207
+ hasRuntimeDefault: false;
208
+ enumValues: undefined;
209
+ baseColumn: never;
210
+ identity: undefined;
211
+ generated: undefined;
212
+ }, {}, {}>;
213
+ derivedFromAssetId: import("drizzle-orm/pg-core").PgColumn<{
214
+ name: "derived_from_asset_id";
215
+ tableName: "media_assets";
216
+ dataType: "string";
217
+ columnType: "PgUUID";
218
+ data: string;
219
+ driverParam: string;
220
+ notNull: false;
221
+ hasDefault: false;
222
+ isPrimaryKey: false;
223
+ isAutoincrement: false;
224
+ hasRuntimeDefault: false;
225
+ enumValues: undefined;
226
+ baseColumn: never;
227
+ identity: undefined;
228
+ generated: undefined;
229
+ }, {}, {}>;
179
230
  uploadedAt: import("drizzle-orm/pg-core").PgColumn<{
180
231
  name: "uploaded_at";
181
232
  tableName: "media_assets";
@@ -285,6 +336,23 @@ export declare const mediaModule: import("../../kernel/module/define.js").AppMod
285
336
  identity: undefined;
286
337
  generated: undefined;
287
338
  }, {}, {}>;
339
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
340
+ name: "created_at";
341
+ tableName: "entity_media";
342
+ dataType: "date";
343
+ columnType: "PgTimestamp";
344
+ data: Date;
345
+ driverParam: string;
346
+ notNull: true;
347
+ hasDefault: true;
348
+ isPrimaryKey: false;
349
+ isAutoincrement: false;
350
+ hasRuntimeDefault: false;
351
+ enumValues: undefined;
352
+ baseColumn: never;
353
+ identity: undefined;
354
+ generated: undefined;
355
+ }, {}, {}>;
288
356
  };
289
357
  dialect: "pg";
290
358
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/media/module.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAgBtB,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/media/module.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yCAkBtB,CAAC"}
@@ -17,6 +17,8 @@ export const mediaModule = defineModule({
17
17
  catalogRepository: new CatalogRepository(db),
18
18
  storage,
19
19
  config: deps.config,
20
+ database: deps.db,
21
+ services: deps.services,
20
22
  });
21
23
  },
22
24
  });
@@ -1,3 +1,5 @@
1
+ export declare const mediaAssetOrigin: import("drizzle-orm/pg-core").PgEnum<["merchant", "generated", "imported"]>;
2
+ export type MediaAssetOrigin = (typeof mediaAssetOrigin.enumValues)[number];
1
3
  export declare const mediaAssets: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
4
  name: "media_assets";
3
5
  schema: undefined;
@@ -174,6 +176,57 @@ export declare const mediaAssets: import("drizzle-orm/pg-core").PgTableWithColum
174
176
  }, {}, {
175
177
  $type: Record<string, unknown>;
176
178
  }>;
179
+ origin: import("drizzle-orm/pg-core").PgColumn<{
180
+ name: "origin";
181
+ tableName: "media_assets";
182
+ dataType: "string";
183
+ columnType: "PgEnumColumn";
184
+ data: "generated" | "merchant" | "imported";
185
+ driverParam: string;
186
+ notNull: true;
187
+ hasDefault: true;
188
+ isPrimaryKey: false;
189
+ isAutoincrement: false;
190
+ hasRuntimeDefault: false;
191
+ enumValues: ["merchant", "generated", "imported"];
192
+ baseColumn: never;
193
+ identity: undefined;
194
+ generated: undefined;
195
+ }, {}, {}>;
196
+ confidence: import("drizzle-orm/pg-core").PgColumn<{
197
+ name: "confidence";
198
+ tableName: "media_assets";
199
+ dataType: "string";
200
+ columnType: "PgNumeric";
201
+ data: string;
202
+ driverParam: string;
203
+ notNull: false;
204
+ hasDefault: false;
205
+ isPrimaryKey: false;
206
+ isAutoincrement: false;
207
+ hasRuntimeDefault: false;
208
+ enumValues: undefined;
209
+ baseColumn: never;
210
+ identity: undefined;
211
+ generated: undefined;
212
+ }, {}, {}>;
213
+ derivedFromAssetId: import("drizzle-orm/pg-core").PgColumn<{
214
+ name: "derived_from_asset_id";
215
+ tableName: "media_assets";
216
+ dataType: "string";
217
+ columnType: "PgUUID";
218
+ data: string;
219
+ driverParam: string;
220
+ notNull: false;
221
+ hasDefault: false;
222
+ isPrimaryKey: false;
223
+ isAutoincrement: false;
224
+ hasRuntimeDefault: false;
225
+ enumValues: undefined;
226
+ baseColumn: never;
227
+ identity: undefined;
228
+ generated: undefined;
229
+ }, {}, {}>;
177
230
  uploadedAt: import("drizzle-orm/pg-core").PgColumn<{
178
231
  name: "uploaded_at";
179
232
  tableName: "media_assets";
@@ -283,6 +336,23 @@ export declare const entityMedia: import("drizzle-orm/pg-core").PgTableWithColum
283
336
  identity: undefined;
284
337
  generated: undefined;
285
338
  }, {}, {}>;
339
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
340
+ name: "created_at";
341
+ tableName: "entity_media";
342
+ dataType: "date";
343
+ columnType: "PgTimestamp";
344
+ data: Date;
345
+ driverParam: string;
346
+ notNull: true;
347
+ hasDefault: true;
348
+ isPrimaryKey: false;
349
+ isAutoincrement: false;
350
+ hasRuntimeDefault: false;
351
+ enumValues: undefined;
352
+ baseColumn: never;
353
+ identity: undefined;
354
+ generated: undefined;
355
+ }, {}, {}>;
286
356
  };
287
357
  dialect: "pg";
288
358
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/modules/media/schema.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBvB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EActB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/modules/media/schema.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gBAAgB,6EAAsE,CAAC;AACpG,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBvB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBrB,CAAC"}
@@ -1,6 +1,8 @@
1
- import { index, integer, jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
1
+ import { sql } from "drizzle-orm";
2
+ import { index, integer, jsonb, numeric, pgEnum, pgTable, text, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core";
2
3
  import { organization } from "../../auth/auth-schema.js";
3
4
  import { sellableEntities, variants } from "../catalog/schema.js";
5
+ export const mediaAssetOrigin = pgEnum("media_asset_origin", ["merchant", "generated", "imported"]);
4
6
  export const mediaAssets = pgTable("media_assets", {
5
7
  id: uuid("id").defaultRandom().primaryKey(),
6
8
  organizationId: text("organization_id")
@@ -14,6 +16,11 @@ export const mediaAssets = pgTable("media_assets", {
14
16
  height: integer("height"),
15
17
  alt: text("alt"),
16
18
  metadata: jsonb("metadata").$type().default({}),
19
+ origin: mediaAssetOrigin("origin").notNull().default("merchant"),
20
+ confidence: numeric("confidence", { precision: 4, scale: 3 }),
21
+ derivedFromAssetId: uuid("derived_from_asset_id").references(() => mediaAssets.id, {
22
+ onDelete: "set null",
23
+ }),
17
24
  uploadedAt: timestamp("uploaded_at", { withTimezone: true }).defaultNow().notNull(),
18
25
  }, (table) => ({
19
26
  orgIdx: index("idx_media_assets_org").on(table.organizationId),
@@ -32,4 +39,15 @@ export const entityMedia = pgTable("entity_media", {
32
39
  enum: ["primary", "gallery", "thumbnail", "video", "document"],
33
40
  }).notNull(),
34
41
  sortOrder: integer("sort_order").notNull().default(0),
35
- });
42
+ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
43
+ }, (table) => ({
44
+ // Two partial indexes instead of one NULLS DISTINCT index: Postgres treats
45
+ // null variant ids as distinct, so a single index cannot reject duplicate
46
+ // entity-level rows.
47
+ entityLevelUnique: uniqueIndex("entity_media_entity_level_unique")
48
+ .on(table.entityId, table.mediaAssetId)
49
+ .where(sql `${table.variantId} IS NULL`),
50
+ variantLevelUnique: uniqueIndex("entity_media_variant_level_unique")
51
+ .on(table.entityId, table.variantId, table.mediaAssetId)
52
+ .where(sql `${table.variantId} IS NOT NULL`),
53
+ }));
@@ -2,15 +2,18 @@ import type { Actor } from "../../auth/types.js";
2
2
  import type { CommerceConfig } from "../../config/types.js";
3
3
  import type { StorageAdapter, StoredFile } from "./adapter.js";
4
4
  import { type Result } from "../../kernel/result.js";
5
- import type { MediaRepository } from "./repository/index.js";
5
+ import type { MediaRepository, MediaAsset } from "./repository/index.js";
6
6
  import type { CatalogRepository } from "../catalog/repository/index.js";
7
7
  import type { TxContext } from "../../kernel/database/tx-context.js";
8
+ import type { DatabaseAdapter } from "../../kernel/database/adapter.js";
9
+ import type { MediaAssetOrigin } from "./schema.js";
8
10
  export interface UploadMediaInput {
9
11
  filename: string;
10
12
  contentType: string;
11
13
  data: ArrayBuffer;
12
14
  alt?: string;
13
15
  metadata?: Record<string, unknown>;
16
+ origin?: MediaAssetOrigin;
14
17
  }
15
18
  export interface AttachMediaInput {
16
19
  entityId: string;
@@ -33,13 +36,17 @@ interface MediaServiceDeps {
33
36
  catalogRepository: CatalogRepository;
34
37
  storage: StorageAdapter;
35
38
  config: CommerceConfig;
39
+ database?: DatabaseAdapter;
40
+ services?: Record<string, unknown>;
36
41
  }
42
+ export declare function assertMediaWritable(asset: Pick<MediaAsset, "origin">, actor: Actor | null): void;
37
43
  export declare function detectMimeFromBuffer(buffer: Uint8Array): string | null;
38
44
  export declare class MediaService {
39
45
  private deps;
40
46
  private readonly repo;
41
47
  private readonly catalogRepo;
42
48
  constructor(deps: MediaServiceDeps);
49
+ private withTransaction;
43
50
  upload(input: UploadMediaInput, actor?: Actor | null, ctx?: TxContext): Promise<Result<{
44
51
  id: string;
45
52
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/media/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/media/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,UAAU,CAAC;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,gBAAgB;IACxB,UAAU,EAAE,eAAe,CAAC;IAC5B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAUD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAEhG;AAiBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAyBtE;AAED,qBAAa,YAAY;IAIX,OAAO,CAAC,IAAI;IAHxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;gBAE5B,IAAI,EAAE,gBAAgB;YAK5B,eAAe;IAUvB,MAAM,CACV,KAAK,EAAE,gBAAgB,EACvB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAmEzC,MAAM,CACV,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAOpB,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,SAAS,SAAU,EACnB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAOpB,MAAM,CACV,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAmBlB,IAAI,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAMhD,cAAc,CAClB,KAAK,EAAE,gBAAgB,EACvB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAoDxB;;;;OAIG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAC7C,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;CAoBpC"}
@@ -1,6 +1,8 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
+ import { assertPermission } from "../../auth/permissions.js";
2
3
  import { Err, Ok } from "../../kernel/result.js";
3
- import { CommerceNotFoundError, CommerceValidationError, } from "../../kernel/errors.js";
4
+ import { CommerceConflictError, CommerceNotFoundError, CommerceValidationError, toCommerceError, } from "../../kernel/errors.js";
5
+ import { createTxContext } from "../../kernel/database/tx-context.js";
4
6
  import { makeId } from "../../utils/id.js";
5
7
  const DEFAULT_ALLOWED_MIME_TYPES = [
6
8
  "image/png",
@@ -9,6 +11,18 @@ const DEFAULT_ALLOWED_MIME_TYPES = [
9
11
  "image/webp",
10
12
  "application/pdf",
11
13
  ];
14
+ export function assertMediaWritable(asset, actor) {
15
+ if (asset.origin === "merchant")
16
+ assertPermission(actor, "media:write");
17
+ }
18
+ function isUniqueViolation(error) {
19
+ if (error == null || typeof error !== "object")
20
+ return false;
21
+ const value = error;
22
+ if (value.code === "23505")
23
+ return true;
24
+ return isUniqueViolation(value.cause);
25
+ }
12
26
  function isSvgOrXml(buffer) {
13
27
  const prefix = new TextDecoder()
14
28
  .decode(buffer.slice(0, 256))
@@ -46,11 +60,18 @@ export class MediaService {
46
60
  this.repo = deps.repository;
47
61
  this.catalogRepo = deps.catalogRepository;
48
62
  }
63
+ async withTransaction(actor, ctx, fn) {
64
+ if (ctx?.tx != null)
65
+ return fn(ctx);
66
+ if (this.deps.database == null)
67
+ throw new Error("Database is required for media mutations.");
68
+ return this.deps.database.transaction(async (tx) => fn(createTxContext(tx, { actor })));
69
+ }
49
70
  async upload(input, actor, ctx) {
50
71
  if (!input.filename || !input.contentType) {
51
72
  return Err(new CommerceValidationError("filename and contentType are required."));
52
73
  }
53
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
74
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
54
75
  const bytes = new Uint8Array(input.data);
55
76
  const detectedMime = detectMimeFromBuffer(bytes);
56
77
  const allowSvg = this.deps.config.media?.allowSvg === true;
@@ -78,6 +99,7 @@ export class MediaService {
78
99
  contentType: effectiveMime,
79
100
  size: input.data.byteLength,
80
101
  metadata: input.metadata ?? {},
102
+ origin: input.origin ?? "merchant",
81
103
  uploadedAt: new Date(),
82
104
  ...(input.alt !== undefined ? { alt: input.alt } : {}),
83
105
  }, ctx);
@@ -94,24 +116,30 @@ export class MediaService {
94
116
  // and delete additionally requires the actor to pass cross-tenant
95
117
  // ownership (any actor without *:* must be in the asset's org).
96
118
  async getUrl(id, actor, ctx) {
97
- const orgId = resolveOrgId(actor ?? null);
119
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
98
120
  const asset = await this.repo.findAssetById(id, ctx, orgId);
99
121
  if (!asset)
100
122
  return Err(new CommerceNotFoundError("Media asset not found."));
101
123
  return this.deps.storage.getUrl(asset.storageKey);
102
124
  }
103
125
  async getSignedUrl(id, expiresIn = 60 * 15, actor, ctx) {
104
- const orgId = resolveOrgId(actor ?? null);
126
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
105
127
  const asset = await this.repo.findAssetById(id, ctx, orgId);
106
128
  if (!asset)
107
129
  return Err(new CommerceNotFoundError("Media asset not found."));
108
130
  return this.deps.storage.getSignedUrl(asset.storageKey, expiresIn);
109
131
  }
110
132
  async delete(id, actor, ctx) {
111
- const orgId = resolveOrgId(actor ?? null);
133
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
112
134
  const asset = await this.repo.findAssetById(id, ctx, orgId);
113
135
  if (!asset)
114
136
  return Err(new CommerceNotFoundError("Media asset not found."));
137
+ try {
138
+ assertMediaWritable(asset, actor ?? ctx?.actor ?? null);
139
+ }
140
+ catch (error) {
141
+ return Err(toCommerceError(error));
142
+ }
115
143
  const deleted = await this.deps.storage.delete(asset.storageKey);
116
144
  if (!deleted.ok)
117
145
  return deleted;
@@ -126,25 +154,45 @@ export class MediaService {
126
154
  return Ok(listed.value);
127
155
  }
128
156
  async attachToEntity(input, actor, ctx) {
129
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
130
- const entity = await this.catalogRepo.findEntityById(input.entityId, ctx, orgId);
131
- if (!entity) {
132
- return Err(new CommerceNotFoundError("Entity not found."));
157
+ try {
158
+ return await this.withTransaction(actor ?? ctx?.actor ?? null, ctx, async (txCtx) => {
159
+ const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor, this.deps.config);
160
+ const entity = await this.catalogRepo.findEntityById(input.entityId, txCtx, orgId);
161
+ if (!entity)
162
+ return Err(new CommerceNotFoundError("Entity not found."));
163
+ const asset = await this.repo.findAssetById(input.mediaAssetId, txCtx, orgId);
164
+ if (!asset)
165
+ return Err(new CommerceNotFoundError("Media asset not found."));
166
+ const existing = await this.repo.findEntityMedia(input.entityId, input.variantId, txCtx);
167
+ if (existing.some((link) => link.mediaAssetId === input.mediaAssetId)) {
168
+ return Err(new CommerceConflictError("Media asset is already attached at this level."));
169
+ }
170
+ await this.repo.createEntityMedia({
171
+ entityId: input.entityId,
172
+ mediaAssetId: input.mediaAssetId,
173
+ role: input.role,
174
+ sortOrder: input.sortOrder ?? 0,
175
+ ...(input.variantId !== undefined
176
+ ? { variantId: input.variantId }
177
+ : {}),
178
+ }, txCtx);
179
+ const catalog = this.deps.services?.catalog;
180
+ if (catalog == null || typeof catalog !== "object") {
181
+ throw new Error("Catalog service is required for media revision capture.");
182
+ }
183
+ const catalogService = catalog;
184
+ const revision = await catalogService.recordEntityRevision(input.entityId, actor ?? txCtx.actor, "update", txCtx);
185
+ if (!revision.ok)
186
+ throw revision.error;
187
+ return Ok(undefined);
188
+ });
133
189
  }
134
- const asset = await this.repo.findAssetById(input.mediaAssetId, ctx, orgId);
135
- if (!asset) {
136
- return Err(new CommerceNotFoundError("Media asset not found."));
190
+ catch (error) {
191
+ if (isUniqueViolation(error)) {
192
+ return Err(new CommerceConflictError("Media asset is already attached at this level."));
193
+ }
194
+ return Err(toCommerceError(error));
137
195
  }
138
- await this.repo.createEntityMedia({
139
- entityId: input.entityId,
140
- mediaAssetId: input.mediaAssetId,
141
- role: input.role,
142
- sortOrder: input.sortOrder ?? 0,
143
- ...(input.variantId !== undefined
144
- ? { variantId: input.variantId }
145
- : {}),
146
- }, ctx);
147
- return Ok(undefined);
148
196
  }
149
197
  /**
150
198
  * Media attached to an entity, resolved to public URLs and ordered by