@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,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 type { Actor } from "../../auth/types.js";
4
4
  import type { CommerceConfig } from "../../config/types.js";
@@ -57,7 +57,7 @@ export class InventoryService {
57
57
  ): Promise<string> {
58
58
  const orgId =
59
59
  orgIdOverride ??
60
- resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
60
+ resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
61
61
  const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
62
62
  const sorted = warehouses.sort((a, b) => a.priority - b.priority);
63
63
  if (sorted.length > 0) {
@@ -90,9 +90,8 @@ export class InventoryService {
90
90
  );
91
91
  }
92
92
 
93
- const orgId = resolveOrgId(
93
+ const orgId = resolveOrgIdForCommerce(
94
94
  actor ?? ctx?.actor ?? null,
95
- undefined,
96
95
  this.deps.config,
97
96
  );
98
97
 
@@ -113,9 +112,8 @@ export class InventoryService {
113
112
  }
114
113
 
115
114
  async listWarehouses(actor?: Actor | null, ctx?: TxContext): Promise<Result<Warehouse[]>> {
116
- const orgId = resolveOrgId(
115
+ const orgId = resolveOrgIdForCommerce(
117
116
  actor ?? ctx?.actor ?? null,
118
- undefined,
119
117
  this.deps.config,
120
118
  );
121
119
  const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
@@ -128,9 +126,8 @@ export class InventoryService {
128
126
  ctx?: TxContext,
129
127
  actor?: Actor | null,
130
128
  ): Promise<Result<number>> {
131
- const orgId = resolveOrgId(
129
+ const orgId = resolveOrgIdForCommerce(
132
130
  actor ?? ctx?.actor ?? null,
133
- undefined,
134
131
  this.deps.config,
135
132
  );
136
133
  const available = await this.repo.getAvailableQuantity(
@@ -147,9 +144,8 @@ export class InventoryService {
147
144
  actor?: Actor | null,
148
145
  ctx?: TxContext,
149
146
  ): Promise<Result<InventoryLevel[]>> {
150
- const orgId = resolveOrgId(
147
+ const orgId = resolveOrgIdForCommerce(
151
148
  actor ?? ctx?.actor ?? null,
152
- undefined,
153
149
  this.deps.config,
154
150
  );
155
151
  if (params?.entityId) {
@@ -177,9 +173,8 @@ export class InventoryService {
177
173
  actor?: Actor | null,
178
174
  ctx?: TxContext,
179
175
  ): Promise<Result<Record<string, number>>> {
180
- const orgId = resolveOrgId(
176
+ const orgId = resolveOrgIdForCommerce(
181
177
  actor ?? ctx?.actor ?? null,
182
- undefined,
183
178
  this.deps.config,
184
179
  );
185
180
  const data = await this.repo.getAvailableQuantities(orgId, entityIds, ctx);
@@ -191,9 +186,8 @@ export class InventoryService {
191
186
  ctx?: TxContext,
192
187
  actor?: Actor | null,
193
188
  ): Promise<Result<InventoryLevel[]>> {
194
- const orgId = resolveOrgId(
189
+ const orgId = resolveOrgIdForCommerce(
195
190
  actor ?? ctx?.actor ?? null,
196
- undefined,
197
191
  this.deps.config,
198
192
  );
199
193
  const levels = await this.repo.findLevelsByEntityId(orgId, entityId, ctx);
@@ -213,9 +207,8 @@ export class InventoryService {
213
207
  );
214
208
  }
215
209
 
216
- const orgId = resolveOrgId(
210
+ const orgId = resolveOrgIdForCommerce(
217
211
  actor ?? ctx?.actor ?? null,
218
- undefined,
219
212
  this.deps.config,
220
213
  );
221
214
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
@@ -267,9 +260,8 @@ export class InventoryService {
267
260
  actor?: Actor | null,
268
261
  ctx?: TxContext,
269
262
  ): Promise<Result<void>> {
270
- const orgId = resolveOrgId(
263
+ const orgId = resolveOrgIdForCommerce(
271
264
  actor ?? ctx?.actor ?? null,
272
- undefined,
273
265
  this.deps.config,
274
266
  );
275
267
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
@@ -360,7 +352,7 @@ export class InventoryService {
360
352
  const performedBy = input.performedBy ?? actor?.userId ?? "system";
361
353
 
362
354
  const doAdjust = async (txCtx: TxContext) => {
363
- const orgId = resolveOrgId(actor ?? txCtx.actor ?? null, undefined, this.deps.config);
355
+ const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor ?? null, this.deps.config);
364
356
 
365
357
  // Lock the level first so `before` and the write are atomic.
366
358
  const existing = await this.repo.findLevelForUpdate(
@@ -444,6 +436,7 @@ export class InventoryService {
444
436
  services: this.deps.services,
445
437
  context: { moduleName: "inventory" },
446
438
  database: { db: this.deps.database.db as PluginDb },
439
+ commerceConfig: this.deps.config,
447
440
  });
448
441
 
449
442
  const afterHooks = this.deps.hooks.resolve("inventory.afterAdjust");
@@ -496,9 +489,8 @@ export class InventoryService {
496
489
  ctx?: TxContext,
497
490
  ): Promise<Result<InventoryLevel>> {
498
491
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
499
- const orgId = resolveOrgId(
492
+ const orgId = resolveOrgIdForCommerce(
500
493
  actor ?? ctx?.actor ?? null,
501
- undefined,
502
494
  this.deps.config,
503
495
  );
504
496
 
@@ -551,7 +543,7 @@ export class InventoryService {
551
543
  ): Promise<Result<void>> {
552
544
  const orgId =
553
545
  input.orgId ??
554
- resolveOrgId(ctx?.actor ?? null, undefined, this.deps.config);
546
+ resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
555
547
  const warehouseId =
556
548
  input.warehouseId ?? (await this.pickWarehouse(null, ctx, orgId));
557
549
  const variantId = input.variantId ?? null;
@@ -602,9 +594,8 @@ export class InventoryService {
602
594
  variantId?: string,
603
595
  ctx?: TxContext,
604
596
  ): Promise<Result<InventoryLevel>> {
605
- const orgId = resolveOrgId(
597
+ const orgId = resolveOrgIdForCommerce(
606
598
  ctx?.actor ?? null,
607
- undefined,
608
599
  this.deps.config,
609
600
  );
610
601
  const level = await this.repo.findLevelByKey(
@@ -20,6 +20,8 @@ export const mediaModule = defineModule({
20
20
  catalogRepository: new CatalogRepository(db),
21
21
  storage,
22
22
  config: deps.config as CommerceConfig,
23
+ database: deps.db,
24
+ services: deps.services,
23
25
  });
24
26
  },
25
27
  });
@@ -1,7 +1,12 @@
1
- import { index, integer, jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
1
+ import type { AnyPgColumn } from "drizzle-orm/pg-core";
2
+ import { sql } from "drizzle-orm";
3
+ import { index, integer, jsonb, numeric, pgEnum, pgTable, text, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core";
2
4
  import { organization } from "../../auth/auth-schema.js";
3
5
  import { sellableEntities, variants } from "../catalog/schema.js";
4
6
 
7
+ export const mediaAssetOrigin = pgEnum("media_asset_origin", ["merchant", "generated", "imported"]);
8
+ export type MediaAssetOrigin = (typeof mediaAssetOrigin.enumValues)[number];
9
+
5
10
  export const mediaAssets = pgTable(
6
11
  "media_assets",
7
12
  {
@@ -17,6 +22,11 @@ export const mediaAssets = pgTable(
17
22
  height: integer("height"),
18
23
  alt: text("alt"),
19
24
  metadata: jsonb("metadata").$type<Record<string, unknown>>().default({}),
25
+ origin: mediaAssetOrigin("origin").notNull().default("merchant"),
26
+ confidence: numeric("confidence", { precision: 4, scale: 3 }),
27
+ derivedFromAssetId: uuid("derived_from_asset_id").references((): AnyPgColumn => mediaAssets.id, {
28
+ onDelete: "set null",
29
+ }),
20
30
  uploadedAt: timestamp("uploaded_at", { withTimezone: true }).defaultNow().notNull(),
21
31
  },
22
32
  (table) => ({
@@ -38,4 +48,15 @@ export const entityMedia = pgTable("entity_media", {
38
48
  enum: ["primary", "gallery", "thumbnail", "video", "document"],
39
49
  }).notNull(),
40
50
  sortOrder: integer("sort_order").notNull().default(0),
41
- });
51
+ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
52
+ }, (table) => ({
53
+ // Two partial indexes instead of one NULLS DISTINCT index: Postgres treats
54
+ // null variant ids as distinct, so a single index cannot reject duplicate
55
+ // entity-level rows.
56
+ entityLevelUnique: uniqueIndex("entity_media_entity_level_unique")
57
+ .on(table.entityId, table.mediaAssetId)
58
+ .where(sql`${table.variantId} IS NULL`),
59
+ variantLevelUnique: uniqueIndex("entity_media_variant_level_unique")
60
+ .on(table.entityId, table.variantId, table.mediaAssetId)
61
+ .where(sql`${table.variantId} IS NOT NULL`),
62
+ }));
@@ -1,16 +1,22 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
+ import { assertPermission } from "../../auth/permissions.js";
2
3
  import type { Actor } from "../../auth/types.js";
3
4
  import type { CommerceConfig } from "../../config/types.js";
4
5
  import type { StorageAdapter, StoredFile } from "./adapter.js";
5
6
  import { Err, Ok, type Result } from "../../kernel/result.js";
6
7
  import {
8
+ CommerceConflictError,
7
9
  CommerceNotFoundError,
8
10
  CommerceValidationError,
11
+ toCommerceError,
9
12
  } from "../../kernel/errors.js";
10
- import type { MediaRepository } from "./repository/index.js";
13
+ import type { MediaRepository, MediaAsset } from "./repository/index.js";
11
14
  import type { CatalogRepository } from "../catalog/repository/index.js";
12
15
  import type { TxContext } from "../../kernel/database/tx-context.js";
16
+ import { createTxContext } from "../../kernel/database/tx-context.js";
17
+ import type { DatabaseAdapter } from "../../kernel/database/adapter.js";
13
18
  import { makeId } from "../../utils/id.js";
19
+ import type { MediaAssetOrigin } from "./schema.js";
14
20
 
15
21
  export interface UploadMediaInput {
16
22
  filename: string;
@@ -18,6 +24,7 @@ export interface UploadMediaInput {
18
24
  data: ArrayBuffer;
19
25
  alt?: string;
20
26
  metadata?: Record<string, unknown>;
27
+ origin?: MediaAssetOrigin;
21
28
  }
22
29
 
23
30
  export interface AttachMediaInput {
@@ -43,6 +50,8 @@ interface MediaServiceDeps {
43
50
  catalogRepository: CatalogRepository;
44
51
  storage: StorageAdapter;
45
52
  config: CommerceConfig;
53
+ database?: DatabaseAdapter;
54
+ services?: Record<string, unknown>;
46
55
  }
47
56
 
48
57
  const DEFAULT_ALLOWED_MIME_TYPES = [
@@ -53,6 +62,17 @@ const DEFAULT_ALLOWED_MIME_TYPES = [
53
62
  "application/pdf",
54
63
  ];
55
64
 
65
+ export function assertMediaWritable(asset: Pick<MediaAsset, "origin">, actor: Actor | null): void {
66
+ if (asset.origin === "merchant") assertPermission(actor, "media:write");
67
+ }
68
+
69
+ function isUniqueViolation(error: unknown): boolean {
70
+ if (error == null || typeof error !== "object") return false;
71
+ const value = error as { code?: unknown; cause?: unknown };
72
+ if (value.code === "23505") return true;
73
+ return isUniqueViolation(value.cause);
74
+ }
75
+
56
76
  function isSvgOrXml(buffer: Uint8Array): boolean {
57
77
  const prefix = new TextDecoder()
58
78
  .decode(buffer.slice(0, 256))
@@ -97,6 +117,16 @@ export class MediaService {
97
117
  this.catalogRepo = deps.catalogRepository;
98
118
  }
99
119
 
120
+ private async withTransaction<T>(
121
+ actor: Actor | null,
122
+ ctx: TxContext | undefined,
123
+ fn: (txCtx: TxContext) => Promise<T>,
124
+ ): Promise<T> {
125
+ if (ctx?.tx != null) return fn(ctx);
126
+ if (this.deps.database == null) throw new Error("Database is required for media mutations.");
127
+ return this.deps.database.transaction(async (tx) => fn(createTxContext(tx, { actor })));
128
+ }
129
+
100
130
  async upload(
101
131
  input: UploadMediaInput,
102
132
  actor?: Actor | null,
@@ -108,7 +138,7 @@ export class MediaService {
108
138
  );
109
139
  }
110
140
 
111
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
141
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
112
142
  const bytes = new Uint8Array(input.data);
113
143
  const detectedMime = detectMimeFromBuffer(bytes);
114
144
  const allowSvg = this.deps.config.media?.allowSvg === true;
@@ -148,6 +178,7 @@ export class MediaService {
148
178
  contentType: effectiveMime,
149
179
  size: input.data.byteLength,
150
180
  metadata: input.metadata ?? {},
181
+ origin: input.origin ?? "merchant",
151
182
  uploadedAt: new Date(),
152
183
  ...(input.alt !== undefined ? { alt: input.alt } : {}),
153
184
  },
@@ -172,7 +203,7 @@ export class MediaService {
172
203
  actor?: Actor | null,
173
204
  ctx?: TxContext,
174
205
  ): Promise<Result<string>> {
175
- const orgId = resolveOrgId(actor ?? null);
206
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
176
207
  const asset = await this.repo.findAssetById(id, ctx, orgId);
177
208
  if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
178
209
  return this.deps.storage.getUrl(asset.storageKey);
@@ -184,7 +215,7 @@ export class MediaService {
184
215
  actor?: Actor | null,
185
216
  ctx?: TxContext,
186
217
  ): Promise<Result<string>> {
187
- const orgId = resolveOrgId(actor ?? null);
218
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
188
219
  const asset = await this.repo.findAssetById(id, ctx, orgId);
189
220
  if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
190
221
  return this.deps.storage.getSignedUrl(asset.storageKey, expiresIn);
@@ -195,10 +226,16 @@ export class MediaService {
195
226
  actor?: Actor | null,
196
227
  ctx?: TxContext,
197
228
  ): Promise<Result<void>> {
198
- const orgId = resolveOrgId(actor ?? null);
229
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
199
230
  const asset = await this.repo.findAssetById(id, ctx, orgId);
200
231
  if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
201
232
 
233
+ try {
234
+ assertMediaWritable(asset, actor ?? ctx?.actor ?? null);
235
+ } catch (error) {
236
+ return Err(toCommerceError(error));
237
+ }
238
+
202
239
  const deleted = await this.deps.storage.delete(asset.storageKey);
203
240
  if (!deleted.ok) return deleted;
204
241
 
@@ -218,31 +255,55 @@ export class MediaService {
218
255
  actor?: Actor | null,
219
256
  ctx?: TxContext,
220
257
  ): Promise<Result<void>> {
221
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
222
- const entity = await this.catalogRepo.findEntityById(input.entityId, ctx, orgId);
223
- if (!entity) {
224
- return Err(new CommerceNotFoundError("Entity not found."));
225
- }
258
+ try {
259
+ return await this.withTransaction(actor ?? ctx?.actor ?? null, ctx, async (txCtx) => {
260
+ const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor, this.deps.config);
261
+ const entity = await this.catalogRepo.findEntityById(input.entityId, txCtx, orgId);
262
+ if (!entity) return Err(new CommerceNotFoundError("Entity not found."));
226
263
 
227
- const asset = await this.repo.findAssetById(input.mediaAssetId, ctx, orgId);
228
- if (!asset) {
229
- return Err(new CommerceNotFoundError("Media asset not found."));
230
- }
264
+ const asset = await this.repo.findAssetById(input.mediaAssetId, txCtx, orgId);
265
+ if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
231
266
 
232
- await this.repo.createEntityMedia(
233
- {
234
- entityId: input.entityId,
235
- mediaAssetId: input.mediaAssetId,
236
- role: input.role,
237
- sortOrder: input.sortOrder ?? 0,
238
- ...(input.variantId !== undefined
239
- ? { variantId: input.variantId }
240
- : {}),
241
- },
242
- ctx,
243
- );
267
+ const existing = await this.repo.findEntityMedia(input.entityId, input.variantId, txCtx);
268
+ if (existing.some((link) => link.mediaAssetId === input.mediaAssetId)) {
269
+ return Err(new CommerceConflictError("Media asset is already attached at this level."));
270
+ }
244
271
 
245
- return Ok(undefined);
272
+ await this.repo.createEntityMedia(
273
+ {
274
+ entityId: input.entityId,
275
+ mediaAssetId: input.mediaAssetId,
276
+ role: input.role,
277
+ sortOrder: input.sortOrder ?? 0,
278
+ ...(input.variantId !== undefined
279
+ ? { variantId: input.variantId }
280
+ : {}),
281
+ },
282
+ txCtx,
283
+ );
284
+
285
+ const catalog = this.deps.services?.catalog;
286
+ if (catalog == null || typeof catalog !== "object") {
287
+ throw new Error("Catalog service is required for media revision capture.");
288
+ }
289
+ const catalogService = catalog as {
290
+ recordEntityRevision: (
291
+ entityId: string,
292
+ actor: Actor | null,
293
+ reason?: "create" | "update" | "import" | "enrichment" | "push" | "restore",
294
+ ctx?: TxContext,
295
+ ) => Promise<Result<unknown>>;
296
+ };
297
+ const revision = await catalogService.recordEntityRevision(input.entityId, actor ?? txCtx.actor, "update", txCtx);
298
+ if (!revision.ok) throw revision.error;
299
+ return Ok(undefined);
300
+ });
301
+ } catch (error) {
302
+ if (isUniqueViolation(error)) {
303
+ return Err(new CommerceConflictError("Media asset is already attached at this level."));
304
+ }
305
+ return Err(toCommerceError(error));
306
+ }
246
307
  }
247
308
 
248
309
  /**
@@ -0,0 +1,55 @@
1
+ import type { GuestOrderAccessStrategy } from "../../config/types.js";
2
+
3
+ const UNIT_MS: Record<string, number> = {
4
+ s: 1_000,
5
+ m: 60_000,
6
+ h: 3_600_000,
7
+ d: 86_400_000,
8
+ };
9
+
10
+ /**
11
+ * Parses a window like `"7d"`, `"2h"`, `"30m"`, `"45s"`.
12
+ * Throws at configuration time rather than silently admitting everything —
13
+ * a typo in a security window must not read as "no limit".
14
+ */
15
+ export function parseAccessWindow(duration: string): number {
16
+ const match = /^(\d+)(s|m|h|d)$/.exec(duration.trim());
17
+ if (!match) {
18
+ throw new Error(
19
+ `Invalid guest order access window "${duration}". Use a whole number followed by s, m, h, or d — for example "7d".`,
20
+ );
21
+ }
22
+ return Number(match[1]) * UNIT_MS[match[2]!]!;
23
+ }
24
+
25
+ /**
26
+ * Grants a guest bearer credential access to a placed order for a fixed window
27
+ * after it was placed.
28
+ *
29
+ * Anchored on `placedAt`, never on the cart's expiry: a shopper who checks out
30
+ * on the sixth day of a seven-day cart would otherwise get one day of receipt
31
+ * access. The two lifetimes are independent by construction.
32
+ */
33
+ export function windowedGuestOrderAccess(duration: string): GuestOrderAccessStrategy {
34
+ const windowMs = parseAccessWindow(duration);
35
+ return {
36
+ canAccessOrder(order, now) {
37
+ const placedAt =
38
+ order.placedAt instanceof Date ? order.placedAt : new Date(order.placedAt);
39
+ const elapsed = now.getTime() - placedAt.getTime();
40
+ return Number.isFinite(elapsed) && elapsed <= windowMs;
41
+ },
42
+ };
43
+ }
44
+
45
+ /**
46
+ * The default window. Seven days matches `config.cart.ttlMinutes` so the
47
+ * product carries one number rather than two.
48
+ *
49
+ * Deliberately not Vendure's two hours: that figure is calibrated for a
50
+ * guessable order code, and a cart secret is a 122-bit random UUID. Guessing is
51
+ * not the exposure here — a secret that leaked through a referrer, a shared
52
+ * link or a log line is, and a bounded window is what expires it.
53
+ */
54
+ export const defaultGuestOrderAccess: GuestOrderAccessStrategy =
55
+ windowedGuestOrderAccess("7d");
@@ -52,6 +52,7 @@ export const ordersModule = defineModule<
52
52
  return new OrderService({
53
53
  repository: new OrdersRepository(deps.db.db as DrizzleDatabase),
54
54
  hooks: deps.hooks,
55
+ config,
55
56
  services: deps.services,
56
57
  database: deps.db,
57
58
  ...(config.orders?.customTransitions
@@ -101,6 +101,7 @@ export async function computeOrderPricing(
101
101
  context: { moduleName: "orders" },
102
102
  origin: "rest",
103
103
  database: { db: kernel.database.db as PluginDb },
104
+ commerceConfig: kernel.config,
104
105
  });
105
106
  if (tx !== undefined) context.tx = tx as typeof context.tx;
106
107
 
@@ -166,6 +166,7 @@ export class OrdersRepository {
166
166
  async findByIdempotencyKey(
167
167
  orgId: string,
168
168
  idempotencyKey: string,
169
+ idempotencyScope: string,
169
170
  ctx?: TxContext,
170
171
  ): Promise<Order | undefined> {
171
172
  const db = this.getDb(ctx);
@@ -175,6 +176,7 @@ export class OrdersRepository {
175
176
  .where(
176
177
  and(
177
178
  eq(orders.organizationId, orgId),
179
+ eq(orders.idempotencyScope, idempotencyScope),
178
180
  eq(orders.idempotencyKey, idempotencyKey),
179
181
  ),
180
182
  );
@@ -21,6 +21,8 @@ export const orders = pgTable("orders", {
21
21
  // Client-supplied key making order creation safely retryable (offline POS
22
22
  // queues, network retries) — replays return the original order.
23
23
  idempotencyKey: text("idempotency_key"),
24
+ // Hash of the authenticated actor or guest credential that owns the key.
25
+ idempotencyScope: text("idempotency_scope"),
24
26
  metadata: jsonb("metadata").$type<Record<string, unknown>>().default({}),
25
27
  placedAt: timestamp("placed_at", { withTimezone: true }).defaultNow().notNull(),
26
28
  fulfilledAt: timestamp("fulfilled_at", { withTimezone: true }),
@@ -32,9 +34,9 @@ export const orders = pgTable("orders", {
32
34
  customerIdIdx: index("idx_orders_customer_id").on(table.customerId),
33
35
  placedAtIdx: index("idx_orders_placed_at").on(table.placedAt),
34
36
  paymentIntentIdx: index("idx_orders_payment_intent").on(table.paymentIntentId),
35
- orgIdempotencyKeyUnique: uniqueIndex("orders_org_idempotency_key_unique")
36
- .on(table.organizationId, table.idempotencyKey)
37
- .where(sql`idempotency_key IS NOT NULL`),
37
+ orgIdempotencyKeyUnique: uniqueIndex("orders_org_idempotency_scope_key_unique")
38
+ .on(table.organizationId, table.idempotencyScope, table.idempotencyKey)
39
+ .where(sql`idempotency_scope IS NOT NULL AND idempotency_key IS NOT NULL`),
38
40
  }));
39
41
 
40
42
  export const orderLineItems = pgTable("order_line_items", {