@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,10 +1,10 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
2
  import { CommerceNotFoundError, CommerceValidationError, } from "../../kernel/errors.js";
3
3
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
4
4
  import { createHookContext } from "../../kernel/hooks/create-context.js";
5
5
  import { Err, Ok } from "../../kernel/result.js";
6
6
  import { createLogger } from "../../utils/logger.js";
7
- function hookContext(actor, services, database, tx) {
7
+ function hookContext(actor, services, database, config, tx) {
8
8
  return createHookContext({
9
9
  actor,
10
10
  tx,
@@ -12,6 +12,7 @@ function hookContext(actor, services, database, tx) {
12
12
  services,
13
13
  context: { moduleName: "pricing" },
14
14
  database: { db: database.db },
15
+ commerceConfig: config,
15
16
  });
16
17
  }
17
18
  function matchesQuantity(min, max, quantity) {
@@ -103,7 +104,7 @@ export class PricingService {
103
104
  if (input.amount < 0) {
104
105
  return Err(new CommerceValidationError("Base price amount cannot be negative."));
105
106
  }
106
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
107
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
107
108
  const entity = await this.catalogRepo.findEntityById(input.entityId, ctx, orgId);
108
109
  if (!entity) {
109
110
  return Err(new CommerceNotFoundError("Entity not found for price assignment."));
@@ -113,6 +114,7 @@ export class PricingService {
113
114
  entityId: input.entityId,
114
115
  currency: normalizeCurrency(input.currency),
115
116
  amount: input.amount,
117
+ ...(input.compareAtAmount !== undefined ? { compareAtAmount: input.compareAtAmount } : {}),
116
118
  metadata: input.metadata ?? {},
117
119
  variantId: input.variantId ?? null,
118
120
  customerGroupId: input.customerGroupId ?? null,
@@ -133,10 +135,14 @@ export class PricingService {
133
135
  sameNaturalKeyDate(p.validFrom, priceData.validFrom ?? null) &&
134
136
  sameNaturalKeyDate(p.validUntil, priceData.validUntil ?? null));
135
137
  const record = existing
136
- ? (await this.repo.updatePrice(existing.id, { amount: priceData.amount, metadata: priceData.metadata }, ctx)) ?? existing
138
+ ? (await this.repo.updatePrice(existing.id, {
139
+ amount: priceData.amount,
140
+ ...(priceData.compareAtAmount !== undefined ? { compareAtAmount: priceData.compareAtAmount } : {}),
141
+ metadata: priceData.metadata,
142
+ }, ctx)) ?? existing
137
143
  : await this.repo.createPrice(priceData, ctx);
138
144
  const afterHooks = this.deps.hooks.resolve("pricing.afterCreate");
139
- const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
145
+ const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
140
146
  await runAfterHooks(afterHooks, null, record, "create", hctx);
141
147
  return Ok(record);
142
148
  }
@@ -154,7 +160,7 @@ export class PricingService {
154
160
  if (!validTypes.includes(input.type)) {
155
161
  return Err(new CommerceValidationError(`Invalid modifier type "${input.type}". Must be one of: ${validTypes.join(", ")}`));
156
162
  }
157
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
163
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
158
164
  const modifierData = {
159
165
  organizationId: orgId,
160
166
  name: input.name,
@@ -174,12 +180,12 @@ export class PricingService {
174
180
  };
175
181
  const modifier = await this.repo.createModifier(modifierData, ctx);
176
182
  const afterHooks = this.deps.hooks.resolve("pricing.afterCreate");
177
- const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
183
+ const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
178
184
  await runAfterHooks(afterHooks, null, modifier, "create", hctx);
179
185
  return Ok(modifier);
180
186
  }
181
187
  async listModifiers(filter, actor, ctx) {
182
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
188
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
183
189
  const rows = await this.repo.findModifiers(orgId, {
184
190
  ...(filter?.entityId !== undefined ? { entityId: filter.entityId } : {}),
185
191
  ...(filter?.currency !== undefined
@@ -190,7 +196,7 @@ export class PricingService {
190
196
  return Ok(rows);
191
197
  }
192
198
  async updateModifier(id, patch, actor, ctx) {
193
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
199
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
194
200
  const existing = await this.repo.findModifierById(orgId, id, ctx);
195
201
  if (!existing) {
196
202
  return Err(new CommerceNotFoundError("Price modifier not found."));
@@ -208,7 +214,7 @@ export class PricingService {
208
214
  return Ok(updated);
209
215
  }
210
216
  async deleteModifier(id, actor, ctx) {
211
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
217
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
212
218
  const existing = await this.repo.findModifierById(orgId, id, ctx);
213
219
  if (!existing) {
214
220
  return Err(new CommerceNotFoundError("Price modifier not found."));
@@ -217,7 +223,7 @@ export class PricingService {
217
223
  return Ok({ deleted: true });
218
224
  }
219
225
  async listPrices(filter, actor, ctx) {
220
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
226
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
221
227
  // Get all prices for the entity if specified, or filter after retrieval
222
228
  let prices = [];
223
229
  if (filter?.entityId) {
@@ -256,7 +262,7 @@ export class PricingService {
256
262
  return Ok({ prices, modifiers });
257
263
  }
258
264
  async resolve(input, actor, ctx) {
259
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
265
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
260
266
  const entity = await this.catalogRepo.findEntityById(input.entityId, ctx, orgId);
261
267
  if (!entity) {
262
268
  return Err(new CommerceNotFoundError(`Entity ${input.entityId} not found.`));
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/promotions/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,gBAAgB;gBACb,OAAO,UAAU;qBAAmB,OAAO,eAAe;0CAgBxE,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/promotions/module.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,gBAAgB;gBACb,OAAO,UAAU;qBAAmB,OAAO,eAAe;0CAiBxE,CAAC"}
@@ -12,6 +12,7 @@ export const promotionsModule = defineModule({
12
12
  catalogRepository: deps.services.catalog.repository,
13
13
  ordersRepository: new OrdersRepository(deps.db.db),
14
14
  hooks: deps.hooks,
15
+ config: deps.config,
15
16
  services: deps.services,
16
17
  database: deps.db,
17
18
  }),
@@ -6,6 +6,7 @@ import type { PromotionsRepository, Promotion, PromotionUsage } from "./reposito
6
6
  import type { CatalogRepository } from "../catalog/repository/index.js";
7
7
  import type { OrdersRepository } from "../orders/repository/index.js";
8
8
  import type { Actor } from "../../auth/types.js";
9
+ import type { CommerceConfig } from "../../config/types.js";
9
10
  import { type PromotionType } from "./schemas.js";
10
11
  export type { PromotionType };
11
12
  /** Filter status for listing promotions. Used by the REST API and service layer. */
@@ -15,6 +16,7 @@ interface PromotionServiceDeps {
15
16
  catalogRepository: CatalogRepository;
16
17
  ordersRepository: OrdersRepository;
17
18
  hooks: HookRegistry;
19
+ config: CommerceConfig;
18
20
  services: Record<string, unknown>;
19
21
  database: DatabaseAdapter;
20
22
  }
@@ -69,6 +71,7 @@ export declare class PromotionService {
69
71
  private readonly catalogRepo;
70
72
  private readonly ordersRepo;
71
73
  constructor(deps: PromotionServiceDeps);
74
+ private resolveEvaluationOrgId;
72
75
  create(input: CreatePromotionInput, actor?: Actor | null, ctx?: TxContext): Promise<Result<Promotion>>;
73
76
  deactivate(orgId: string, id: string, ctx?: TxContext): Promise<Result<Promotion>>;
74
77
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/promotions/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/promotions/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAOrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EACV,oBAAoB,EACpB,SAAS,EACT,cAAc,EAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,oFAAoF;AACpF,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAEpF,UAAU,oBAAoB;IAC5B,UAAU,EAAE,oBAAoB,CAAC;IACjC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAoBD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAqDD,qBAAa,gBAAgB;IAKf,OAAO,CAAC,IAAI;IAJxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;gBAE1B,IAAI,EAAE,oBAAoB;IAM9C,OAAO,CAAC,sBAAsB;IAUxB,MAAM,CACV,KAAK,EAAE,oBAAoB,EAC3B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAmEvB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAqBxF;;;OAGG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,oBAAoB,EAC3B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAqEvB,IAAI,CACR,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,qBAAqB,CAAA;KAAE,EAC3C,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAyBzB,UAAU,CACd,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,SAAS,OAAa,EACtB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAQzB,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,0BAA0B,EACnC,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAsBvB,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,0BAA0B,EACnC,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAiBxC,eAAe,CACnB,OAAO,EAAE,0BAA0B,EACnC,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAiExC,WAAW,CACf,KAAK,EAAE;QACL,UAAU,EAAE,gBAAgB,EAAE,CAAC;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,EACD,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;YAiBtB,2BAA2B;YA0F3B,kBAAkB;YAuBlB,iBAAiB;YA2EjB,uBAAuB;CAmCtC"}
@@ -3,11 +3,11 @@ import { runAfterHooks } from "../../kernel/hooks/executor.js";
3
3
  import { createHookContext } from "../../kernel/hooks/create-context.js";
4
4
  import { Err, Ok } from "../../kernel/result.js";
5
5
  import { createLogger } from "../../utils/logger.js";
6
- import { resolveOrgId } from "../../auth/org.js";
6
+ import { resolveOrgId, resolveOrgIdForCommerce } from "../../auth/org.js";
7
7
  // PromotionType is derived from the zod enum (single source of truth) in
8
8
  // ./schemas.js; re-export it here for backwards-compatible imports.
9
9
  import { promotionTypeEnum } from "./schemas.js";
10
- function hookContext(actor, services, database, tx) {
10
+ function hookContext(actor, services, database, config, tx) {
11
11
  return createHookContext({
12
12
  actor,
13
13
  tx,
@@ -15,6 +15,7 @@ function hookContext(actor, services, database, tx) {
15
15
  services,
16
16
  context: { moduleName: "promotions" },
17
17
  database: { db: database.db },
18
+ commerceConfig: config,
18
19
  });
19
20
  }
20
21
  function matchesWindow(promotion, timestamp) {
@@ -70,6 +71,12 @@ export class PromotionService {
70
71
  this.catalogRepo = deps.catalogRepository;
71
72
  this.ordersRepo = deps.ordersRepository;
72
73
  }
74
+ resolveEvaluationOrgId(ctx, explicitOrgId) {
75
+ if (explicitOrgId) {
76
+ return resolveOrgId(ctx?.actor ?? null, explicitOrgId);
77
+ }
78
+ return resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
79
+ }
73
80
  async create(input, actor, ctx) {
74
81
  if (!input.name) {
75
82
  return Err(new CommerceValidationError("Promotion name is required."));
@@ -82,7 +89,7 @@ export class PromotionService {
82
89
  if (!validTypes.includes(input.type)) {
83
90
  return Err(new CommerceValidationError(`Invalid promotion type "${input.type}". Must be one of: ${validTypes.join(", ")}`));
84
91
  }
85
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
92
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
86
93
  if (input.code) {
87
94
  const normalized = input.code.trim().toUpperCase();
88
95
  const existing = await this.repo.findByCode(orgId, normalized, ctx);
@@ -109,7 +116,7 @@ export class PromotionService {
109
116
  validUntil: input.validUntil ?? null,
110
117
  }, ctx);
111
118
  const afterHooks = this.deps.hooks.resolve("promotions.afterCreate");
112
- const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
119
+ const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
113
120
  await runAfterHooks(afterHooks, null, promotion, "create", hctx);
114
121
  return Ok(promotion);
115
122
  }
@@ -123,7 +130,8 @@ export class PromotionService {
123
130
  return Err(new CommerceNotFoundError("Promotion not found."));
124
131
  }
125
132
  const afterHooks = this.deps.hooks.resolve("promotions.afterUpdate");
126
- const hctx = hookContext(null, this.deps.services, this.deps.database, ctx?.tx ?? null);
133
+ // Actor-less by design; resolves to the deployment's declared organization.
134
+ const hctx = hookContext(null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
127
135
  await runAfterHooks(afterHooks, promotion, updated, "update", hctx);
128
136
  return Ok(updated);
129
137
  }
@@ -192,12 +200,12 @@ export class PromotionService {
192
200
  return Err(new CommerceNotFoundError("Promotion not found."));
193
201
  }
194
202
  const afterHooks = this.deps.hooks.resolve("promotions.afterUpdate");
195
- const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
203
+ const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
196
204
  await runAfterHooks(afterHooks, existing, updated, "update", hctx);
197
205
  return Ok(updated);
198
206
  }
199
207
  async list(filter, actor, ctx) {
200
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
208
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
201
209
  const all = await this.repo.findAll(orgId, ctx);
202
210
  const now = new Date();
203
211
  if (!filter?.status)
@@ -218,7 +226,7 @@ export class PromotionService {
218
226
  return Ok(sortByPriority(filtered));
219
227
  }
220
228
  async listActive(actor, timestamp = new Date(), ctx) {
221
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
229
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
222
230
  const active = await this.repo.findActive(orgId, ctx);
223
231
  // Further filter by timestamp in case repo returns slightly stale results
224
232
  const filtered = active.filter((p) => matchesWindow(p, timestamp));
@@ -226,7 +234,7 @@ export class PromotionService {
226
234
  }
227
235
  async validate(code, context, ctx) {
228
236
  const normalized = code.trim().toUpperCase();
229
- const evalOrgId = resolveOrgId(ctx?.actor ?? null, context.orgId);
237
+ const evalOrgId = this.resolveEvaluationOrgId(ctx, context.orgId);
230
238
  const promotion = await this.repo.findByCode(evalOrgId, normalized, ctx);
231
239
  if (!promotion) {
232
240
  return Err(new CommerceNotFoundError(`Promotion code ${normalized} not found.`));
@@ -251,7 +259,7 @@ export class PromotionService {
251
259
  }
252
260
  async applyPromotions(context, ctx) {
253
261
  const timestamp = context.timestamp ?? new Date();
254
- const applyOrgId = resolveOrgId(ctx?.actor ?? null, context.orgId);
262
+ const applyOrgId = this.resolveEvaluationOrgId(ctx, context.orgId);
255
263
  const result = {
256
264
  totalDiscount: 0,
257
265
  freeShipping: false,
@@ -341,7 +349,7 @@ export class PromotionService {
341
349
  if (!context.customerId) {
342
350
  return "First-order promotion requires authenticated customer.";
343
351
  }
344
- const orders = await this.ordersRepo.findByCustomerId(resolveOrgId(ctx?.actor ?? null, context.orgId), context.customerId, ctx);
352
+ const orders = await this.ordersRepo.findByCustomerId(this.resolveEvaluationOrgId(ctx, context.orgId), context.customerId, ctx);
345
353
  if (orders.length > 0) {
346
354
  return "Promotion is valid for first order only.";
347
355
  }
@@ -1,21 +1,27 @@
1
1
  import type { Result } from "../../kernel/result.js";
2
2
  export interface SearchDocument {
3
3
  id: string;
4
+ organizationId?: string;
4
5
  type: string;
5
6
  slug: string;
6
7
  title: string;
7
8
  description?: string;
8
9
  status?: string;
10
+ isVisible?: boolean;
9
11
  categories: string[];
10
12
  brands: string[];
11
13
  text: string;
14
+ attributes?: Record<string, string | string[]>;
12
15
  payload?: Record<string, unknown>;
13
16
  }
14
17
  export interface SearchFilters {
18
+ /** Server-supplied tenant constraint; REST callers cannot choose this value. */
19
+ organizationId?: string;
15
20
  type?: string;
16
21
  category?: string;
17
22
  brand?: string;
18
23
  status?: string;
24
+ attributes?: Record<string, string | string[]>;
19
25
  }
20
26
  export interface SearchQueryParams {
21
27
  query: string;
@@ -28,6 +34,8 @@ export interface SearchSuggestParams {
28
34
  prefix: string;
29
35
  type?: string;
30
36
  limit?: number;
37
+ /** Server-supplied tenant constraint; REST callers cannot choose this value. */
38
+ organizationId?: string;
31
39
  }
32
40
  export interface SearchHit {
33
41
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/modules/search/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CACjE"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/modules/search/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CACjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/search/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,YAAY,2GAgBxB,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/search/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,YAAY,2GAmBxB,CAAC"}
@@ -8,6 +8,9 @@ export const searchModule = defineModule({
8
8
  const config = deps.config;
9
9
  return new SearchService({
10
10
  catalogRepository: deps.services.catalog.repository,
11
+ resolveEntityFieldDefinitions: deps.services.catalog.resolveEntityFieldDefinitions.bind(deps.services.catalog),
12
+ config,
13
+ ...(config.entities ? { entities: config.entities } : {}),
11
14
  ...(config.search?.adapter ? { adapter: config.search.adapter } : {}),
12
15
  ...(config.search?.defaultFacets
13
16
  ? { defaultFacets: config.search.defaultFacets }
@@ -1,9 +1,14 @@
1
1
  import { type Result } from "../../kernel/result.js";
2
2
  import type { TxContext } from "../../kernel/database/tx-context.js";
3
+ import type { CommerceConfig } from "../../config/types.js";
3
4
  import type { CatalogRepository } from "../catalog/repository/index.js";
4
5
  import type { SearchAdapter, SearchQueryParams, SearchQueryResult, SearchSuggestParams } from "./adapter.js";
6
+ import type { EntityFieldDefinitionResolver } from "../catalog/service.js";
5
7
  interface SearchServiceDeps {
6
8
  catalogRepository: CatalogRepository;
9
+ config: CommerceConfig;
10
+ entities?: CommerceConfig["entities"];
11
+ resolveEntityFieldDefinitions?: EntityFieldDefinitionResolver;
7
12
  adapter?: SearchAdapter;
8
13
  defaultFacets?: string[];
9
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/search/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAkB,MAAM,gCAAgC,CAAC;AACxF,OAAO,KAAK,EACV,aAAa,EAGb,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAEtB,UAAU,iBAAiB;IACzB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAuCD,qBAAa,aAAa;IACZ,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;YAE7B,gBAAgB;YAwBhB,YAAY;YAwBZ,aAAa;YAyCb,YAAY;IAY1B,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;IAgDf,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAcpE,KAAK,CACT,MAAM,EAAE,iBAAiB,EACzB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IA+D/B,OAAO,CACX,MAAM,EAAE,mBAAmB,EAC3B,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;CAoC7B"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/search/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,aAAa,EAGb,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAG3E,UAAU,iBAAiB;IACzB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,6BAA6B,CAAC,EAAE,6BAA6B,CAAC;IAC9D,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAoDD,qBAAa,aAAa;IACZ,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;YAE7B,gBAAgB;YAwBhB,YAAY;YAwBZ,aAAa;YAuEb,YAAY;IAoB1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,aAAa;IAoEf,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAcpE,KAAK,CACT,MAAM,EAAE,iBAAiB,EACzB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IA8F/B,OAAO,CACX,MAAM,EAAE,mBAAmB,EAC3B,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;CA+C7B"}
@@ -1,5 +1,7 @@
1
- import { Ok } from "../../kernel/result.js";
2
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { Err, Ok } from "../../kernel/result.js";
2
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
3
+ import { OrgResolutionError } from "../../kernel/errors.js";
4
+ import { canReadUnpublishedCatalog } from "../catalog/read-policy.js";
3
5
  function unique(values) {
4
6
  return [...new Set(values)];
5
7
  }
@@ -19,6 +21,22 @@ function includesAllTokens(haystack, tokens) {
19
21
  const lower = haystack.toLowerCase();
20
22
  return tokens.every((token) => lower.includes(token));
21
23
  }
24
+ function customFieldValue(field) {
25
+ if (field.textValue != null)
26
+ return field.textValue;
27
+ if (field.numberValue != null)
28
+ return String(field.numberValue);
29
+ if (field.booleanValue != null)
30
+ return String(field.booleanValue);
31
+ if (field.dateValue != null)
32
+ return field.dateValue.toISOString();
33
+ return undefined;
34
+ }
35
+ function attributeValues(value) {
36
+ if (value == null)
37
+ return [];
38
+ return Array.isArray(value) ? value : [value];
39
+ }
22
40
  function scoreText(document, tokens) {
23
41
  if (tokens.length === 0)
24
42
  return 1;
@@ -55,44 +73,80 @@ export class SearchService {
55
73
  return unique(slugs);
56
74
  }
57
75
  async buildDocument(entity, ctx) {
58
- const attributes = await this.deps.catalogRepository.findAttributesByEntityId(entity.id, ctx);
59
- const primary = attributes[0];
76
+ const localizedAttributes = await this.deps.catalogRepository.findAttributesByEntityId(entity.id, ctx);
77
+ const primary = localizedAttributes[0];
60
78
  const title = primary?.title ?? entity.slug;
61
79
  const description = primary?.description;
62
80
  const categories = await this.entityCategories(entity.id, ctx);
63
81
  const brands = await this.entityBrands(entity.id, ctx);
82
+ const definitions = this.deps.resolveEntityFieldDefinitions
83
+ ? await this.deps.resolveEntityFieldDefinitions(entity.type, entity.organizationId, ctx)
84
+ : (this.deps.entities?.[entity.type]?.fields ?? []);
85
+ const filterableFields = new Set(definitions
86
+ .filter((field) => field.filterable === true)
87
+ .map((field) => field.name));
88
+ const customFields = await this.deps.catalogRepository.findCustomFieldsByEntityId(entity.id, ctx);
89
+ const attributeValuesByName = new Map();
90
+ for (const field of customFields) {
91
+ if (field.locale !== "en" || !filterableFields.has(field.fieldName))
92
+ continue;
93
+ const value = customFieldValue(field);
94
+ if (value == null)
95
+ continue;
96
+ const values = attributeValuesByName.get(field.fieldName) ?? [];
97
+ if (!values.includes(value))
98
+ values.push(value);
99
+ attributeValuesByName.set(field.fieldName, values);
100
+ }
101
+ const attributes = Object.fromEntries([...attributeValuesByName.entries()].map(([name, values]) => [
102
+ name,
103
+ values.length === 1 ? values[0] : values,
104
+ ]));
64
105
  const textParts = [
65
106
  entity.slug,
66
107
  title,
67
108
  description ?? "",
68
109
  ...categories,
69
110
  ...brands,
70
- ...attributes.map((attr) => attr.title),
71
- ...attributes.map((attr) => attr.description ?? ""),
111
+ ...localizedAttributes.map((attr) => attr.title),
112
+ ...localizedAttributes.map((attr) => attr.description ?? ""),
72
113
  ];
73
114
  return {
74
115
  id: entity.id,
116
+ organizationId: entity.organizationId,
75
117
  type: entity.type,
76
118
  slug: entity.slug,
77
119
  title,
78
120
  ...(description ? { description } : {}),
79
121
  status: entity.status,
122
+ isVisible: entity.isVisible,
80
123
  categories,
81
124
  brands,
82
125
  text: textParts.join(" ").trim(),
126
+ ...(Object.keys(attributes).length > 0 ? { attributes } : {}),
83
127
  payload: {
84
128
  metadata: entity.metadata ?? undefined,
85
129
  },
86
130
  };
87
131
  }
88
132
  async allDocuments(ctx) {
89
- const orgId = resolveOrgId(ctx?.actor ?? null);
90
- const entities = await this.deps.catalogRepository.findEntities(orgId, undefined, ctx);
133
+ const actor = ctx?.actor;
134
+ if (!actor) {
135
+ // Deliberate exception: this needs an authenticated actor, not merely a
136
+ // resolvable organization, because visibility scoping is decided from the
137
+ // actor's permissions. A declared deployment default would satisfy the
138
+ // organization but not that.
139
+ throw new OrgResolutionError("Organization could not be resolved for a search read.");
140
+ }
141
+ const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
142
+ const entities = await this.deps.catalogRepository.findEntities(orgId, canReadUnpublishedCatalog(actor) ? undefined : { status: "active", isVisible: true }, ctx);
91
143
  return Promise.all(entities.map((entity) => this.buildDocument(entity, ctx)));
92
144
  }
93
145
  matchesFilters(document, filters) {
94
146
  if (!filters)
95
147
  return true;
148
+ if (filters.organizationId && document.organizationId !== filters.organizationId)
149
+ return false;
96
150
  if (filters.type && document.type !== filters.type)
97
151
  return false;
98
152
  if (filters.status && document.status !== filters.status)
@@ -101,6 +155,12 @@ export class SearchService {
101
155
  return false;
102
156
  if (filters.brand && !document.brands.includes(filters.brand))
103
157
  return false;
158
+ for (const [name, requested] of Object.entries(filters.attributes ?? {})) {
159
+ const actual = attributeValues(document.attributes?.[name]);
160
+ const expected = attributeValues(requested);
161
+ if (!expected.some((value) => actual.includes(value)))
162
+ return false;
163
+ }
104
164
  return true;
105
165
  }
106
166
  computeFacets(documents, requested) {
@@ -138,6 +198,24 @@ export class SearchService {
138
198
  }
139
199
  }
140
200
  }
201
+ const attributeName = facet.startsWith("attributes.")
202
+ ? facet.slice("attributes.".length)
203
+ : facet;
204
+ if (attributeName !== "type" &&
205
+ attributeName !== "status" &&
206
+ attributeName !== "category" &&
207
+ attributeName !== "categories" &&
208
+ attributeName !== "brand" &&
209
+ attributeName !== "brands") {
210
+ const values = {};
211
+ for (const document of documents) {
212
+ for (const value of new Set(attributeValues(document.attributes?.[attributeName]))) {
213
+ values[value] = (values[value] ?? 0) + 1;
214
+ }
215
+ }
216
+ if (Object.keys(values).length > 0)
217
+ output[attributeName] = values;
218
+ }
141
219
  }
142
220
  return output;
143
221
  }
@@ -156,17 +234,46 @@ export class SearchService {
156
234
  // Cap query length to prevent abuse / excessive processing
157
235
  const safeQuery = (params.query ?? "").slice(0, 500);
158
236
  if (this.deps.adapter) {
159
- return this.deps.adapter.search({
237
+ const actor = ctx?.actor ?? null;
238
+ // Deliberate exception: this needs an authenticated actor, not merely a
239
+ // resolvable organization, because visibility scoping is decided from the
240
+ // actor's permissions. A declared deployment default would satisfy the
241
+ // organization but not that.
242
+ if (!actor)
243
+ return Err(new OrgResolutionError("Organization could not be resolved for a search read."));
244
+ const organizationId = resolveOrgIdForCommerce(actor, this.deps.config);
245
+ const result = await this.deps.adapter.search({
160
246
  ...params,
161
247
  query: safeQuery,
162
248
  page,
163
249
  limit,
250
+ filters: {
251
+ ...params.filters,
252
+ organizationId,
253
+ ...(!canReadUnpublishedCatalog(actor) ? { status: "active" } : {}),
254
+ },
255
+ });
256
+ if (!result.ok)
257
+ return result;
258
+ const hits = result.value.hits.filter((hit) => hit.document.organizationId === organizationId &&
259
+ (canReadUnpublishedCatalog(actor) ||
260
+ (hit.document.status === "active" && hit.document.isVisible !== false)));
261
+ return Ok({
262
+ ...result.value,
263
+ hits,
264
+ total: hits.length,
265
+ facets: this.computeFacets(hits.map((hit) => hit.document), params.facets),
164
266
  });
165
267
  }
166
268
  // In-memory fallback: require a non-empty query to avoid loading all entities
167
269
  // (allDocuments triggers N+1 DB queries per entity — unsafe at scale)
168
270
  const tokens = tokenize(safeQuery);
169
- if (tokens.length === 0 && !params.filters?.type && !params.filters?.category && !params.filters?.brand && !params.filters?.status) {
271
+ if (tokens.length === 0 &&
272
+ !params.filters?.type &&
273
+ !params.filters?.category &&
274
+ !params.filters?.brand &&
275
+ !params.filters?.status &&
276
+ Object.keys(params.filters?.attributes ?? {}).length === 0) {
170
277
  return Ok({ hits: [], total: 0, page, limit, facets: {} });
171
278
  }
172
279
  try {
@@ -215,11 +322,24 @@ export class SearchService {
215
322
  if (prefix.length === 0)
216
323
  return Ok([]);
217
324
  if (this.deps.adapter) {
218
- return this.deps.adapter.suggest({
325
+ const actor = ctx?.actor ?? null;
326
+ // Deliberate exception: this needs an authenticated actor, not merely a
327
+ // resolvable organization, because visibility scoping is decided from the
328
+ // actor's permissions. A declared deployment default would satisfy the
329
+ // organization but not that.
330
+ if (!actor)
331
+ return Err(new OrgResolutionError("Organization could not be resolved for a search read."));
332
+ const organizationId = resolveOrgIdForCommerce(actor, this.deps.config);
333
+ const result = await this.deps.adapter.suggest({
219
334
  ...params,
220
335
  prefix,
221
336
  limit,
337
+ organizationId,
222
338
  });
339
+ if (!result.ok)
340
+ return result;
341
+ const visibleTitles = new Set((await this.allDocuments(ctx)).map((document) => document.title));
342
+ return Ok(result.value.filter((title) => visibleTitles.has(title)));
223
343
  }
224
344
  // In-memory fallback: require prefix >= 2 chars to avoid loading all entities
225
345
  // (allDocuments triggers N+1 DB queries per entity — unsafe at scale)
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/module.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,eAAO,MAAM,cAAc;mBACR,OAAO,aAAa;0CAUrC,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,eAAO,MAAM,cAAc;mBACR,OAAO,aAAa;0CAWrC,CAAC"}
@@ -7,5 +7,6 @@ export const settingsModule = defineModule({
7
7
  schema: () => ({ storeSettings }),
8
8
  service: (deps) => new SettingsService({
9
9
  repository: new SettingsRepository(deps.db.db),
10
+ config: deps.config,
10
11
  }),
11
12
  });
@@ -1,9 +1,11 @@
1
1
  import type { Actor } from "../../auth/types.js";
2
+ import type { CommerceConfig } from "../../config/types.js";
2
3
  import type { TxContext } from "../../kernel/database/tx-context.js";
3
4
  import { type Result } from "../../kernel/result.js";
4
5
  import type { SettingsRepository } from "./repository/index.js";
5
6
  interface SettingsServiceDeps {
6
7
  repository: SettingsRepository;
8
+ config: CommerceConfig;
7
9
  }
8
10
  /**
9
11
  * Org-scoped runtime settings (issue #49).
@@ -14,6 +16,7 @@ interface SettingsServiceDeps {
14
16
  */
15
17
  export declare class SettingsService {
16
18
  private repository;
19
+ private config;
17
20
  constructor(deps: SettingsServiceDeps);
18
21
  /** Runtime read for plugins/hooks. Unset groups read as `{}`. */
19
22
  read(orgId: string, group: string, ctx?: TxContext): Promise<Record<string, unknown>>;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,UAAU,mBAAmB;IAC3B,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAqB;gBAE3B,IAAI,EAAE,mBAAmB;IAIrC,iEAAiE;IAC3D,IAAI,CACR,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAK7B,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAKrC,MAAM,CACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAQ3D,wEAAwE;IAClE,WAAW,CACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAkB5C"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,UAAU,mBAAmB;IAC3B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAiB;gBAEnB,IAAI,EAAE,mBAAmB;IAKrC,iEAAiE;IAC3D,IAAI,CACR,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAK7B,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAKrC,MAAM,CACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAQ3D,wEAAwE;IAClE,WAAW,CACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAkB5C"}