@unifiedcommerce/core 0.4.3 → 0.4.4

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 (561) hide show
  1. package/dist/interfaces/rest/index.d.ts.map +1 -1
  2. package/dist/interfaces/rest/index.js +4 -17
  3. package/dist/runtime/server.d.ts.map +1 -1
  4. package/dist/runtime/server.js +33 -0
  5. package/package.json +1 -1
  6. package/dist/adapters/console-email.d.ts +0 -23
  7. package/dist/adapters/console-email.d.ts.map +0 -1
  8. package/dist/adapters/console-email.js +0 -38
  9. package/dist/auth/access.d.ts +0 -101
  10. package/dist/auth/access.d.ts.map +0 -1
  11. package/dist/auth/access.js +0 -128
  12. package/dist/auth/auth-schema.d.ts +0 -1475
  13. package/dist/auth/auth-schema.d.ts.map +0 -1
  14. package/dist/auth/auth-schema.js +0 -124
  15. package/dist/auth/middleware.d.ts +0 -5
  16. package/dist/auth/middleware.d.ts.map +0 -1
  17. package/dist/auth/middleware.js +0 -141
  18. package/dist/auth/org.d.ts +0 -22
  19. package/dist/auth/org.d.ts.map +0 -1
  20. package/dist/auth/org.js +0 -36
  21. package/dist/auth/permissions.d.ts +0 -4
  22. package/dist/auth/permissions.d.ts.map +0 -1
  23. package/dist/auth/permissions.js +0 -24
  24. package/dist/auth/setup.d.ts +0 -29
  25. package/dist/auth/setup.d.ts.map +0 -1
  26. package/dist/auth/setup.js +0 -117
  27. package/dist/auth/system-actor.d.ts +0 -7
  28. package/dist/auth/system-actor.d.ts.map +0 -1
  29. package/dist/auth/system-actor.js +0 -17
  30. package/dist/auth/types.d.ts +0 -11
  31. package/dist/auth/types.d.ts.map +0 -1
  32. package/dist/auth/types.js +0 -1
  33. package/dist/config/defaults.d.ts +0 -3
  34. package/dist/config/defaults.d.ts.map +0 -1
  35. package/dist/config/defaults.js +0 -80
  36. package/dist/config/define-config.d.ts +0 -9
  37. package/dist/config/define-config.d.ts.map +0 -1
  38. package/dist/config/define-config.js +0 -44
  39. package/dist/config/types.d.ts +0 -327
  40. package/dist/config/types.d.ts.map +0 -1
  41. package/dist/config/types.js +0 -1
  42. package/dist/generated/plugin-manifest.d.ts +0 -48
  43. package/dist/generated/plugin-manifest.d.ts.map +0 -1
  44. package/dist/generated/plugin-manifest.js +0 -20
  45. package/dist/hooks/checkout-completion.d.ts +0 -58
  46. package/dist/hooks/checkout-completion.d.ts.map +0 -1
  47. package/dist/hooks/checkout-completion.js +0 -137
  48. package/dist/hooks/checkout.d.ts +0 -99
  49. package/dist/hooks/checkout.d.ts.map +0 -1
  50. package/dist/hooks/checkout.js +0 -317
  51. package/dist/hooks/order-emails.d.ts +0 -16
  52. package/dist/hooks/order-emails.d.ts.map +0 -1
  53. package/dist/hooks/order-emails.js +0 -44
  54. package/dist/index.d.ts +0 -77
  55. package/dist/index.d.ts.map +0 -1
  56. package/dist/index.js +0 -45
  57. package/dist/interfaces/mcp/agent-prompt.d.ts +0 -16
  58. package/dist/interfaces/mcp/agent-prompt.d.ts.map +0 -1
  59. package/dist/interfaces/mcp/agent-prompt.js +0 -172
  60. package/dist/interfaces/mcp/context-enrichment.d.ts +0 -39
  61. package/dist/interfaces/mcp/context-enrichment.d.ts.map +0 -1
  62. package/dist/interfaces/mcp/context-enrichment.js +0 -119
  63. package/dist/interfaces/mcp/server.d.ts +0 -5
  64. package/dist/interfaces/mcp/server.d.ts.map +0 -1
  65. package/dist/interfaces/mcp/server.js +0 -30
  66. package/dist/interfaces/mcp/tool-builder.d.ts +0 -120
  67. package/dist/interfaces/mcp/tool-builder.d.ts.map +0 -1
  68. package/dist/interfaces/mcp/tool-builder.js +0 -224
  69. package/dist/interfaces/mcp/tools/analytics.d.ts +0 -42
  70. package/dist/interfaces/mcp/tools/analytics.d.ts.map +0 -1
  71. package/dist/interfaces/mcp/tools/analytics.js +0 -70
  72. package/dist/interfaces/mcp/tools/cart.d.ts +0 -14
  73. package/dist/interfaces/mcp/tools/cart.d.ts.map +0 -1
  74. package/dist/interfaces/mcp/tools/cart.js +0 -47
  75. package/dist/interfaces/mcp/tools/catalog.d.ts +0 -53
  76. package/dist/interfaces/mcp/tools/catalog.d.ts.map +0 -1
  77. package/dist/interfaces/mcp/tools/catalog.js +0 -284
  78. package/dist/interfaces/mcp/tools/index.d.ts +0 -3
  79. package/dist/interfaces/mcp/tools/index.d.ts.map +0 -1
  80. package/dist/interfaces/mcp/tools/index.js +0 -20
  81. package/dist/interfaces/mcp/tools/inventory.d.ts +0 -27
  82. package/dist/interfaces/mcp/tools/inventory.d.ts.map +0 -1
  83. package/dist/interfaces/mcp/tools/inventory.js +0 -143
  84. package/dist/interfaces/mcp/tools/orders.d.ts +0 -18
  85. package/dist/interfaces/mcp/tools/orders.d.ts.map +0 -1
  86. package/dist/interfaces/mcp/tools/orders.js +0 -82
  87. package/dist/interfaces/mcp/tools/pricing.d.ts +0 -29
  88. package/dist/interfaces/mcp/tools/pricing.d.ts.map +0 -1
  89. package/dist/interfaces/mcp/tools/pricing.js +0 -90
  90. package/dist/interfaces/mcp/tools/promotions.d.ts +0 -44
  91. package/dist/interfaces/mcp/tools/promotions.d.ts.map +0 -1
  92. package/dist/interfaces/mcp/tools/promotions.js +0 -109
  93. package/dist/interfaces/mcp/tools/registry.d.ts +0 -32
  94. package/dist/interfaces/mcp/tools/registry.d.ts.map +0 -1
  95. package/dist/interfaces/mcp/tools/registry.js +0 -55
  96. package/dist/interfaces/mcp/tools/search.d.ts +0 -14
  97. package/dist/interfaces/mcp/tools/search.d.ts.map +0 -1
  98. package/dist/interfaces/mcp/tools/search.js +0 -39
  99. package/dist/interfaces/mcp/tools/webhooks.d.ts +0 -15
  100. package/dist/interfaces/mcp/tools/webhooks.d.ts.map +0 -1
  101. package/dist/interfaces/mcp/tools/webhooks.js +0 -48
  102. package/dist/interfaces/mcp/transport.d.ts +0 -20
  103. package/dist/interfaces/mcp/transport.d.ts.map +0 -1
  104. package/dist/interfaces/mcp/transport.js +0 -99
  105. package/dist/interfaces/rest/customer-portal.d.ts +0 -5
  106. package/dist/interfaces/rest/customer-portal.d.ts.map +0 -1
  107. package/dist/interfaces/rest/customer-portal.js +0 -206
  108. package/dist/interfaces/rest/router.d.ts +0 -164
  109. package/dist/interfaces/rest/router.d.ts.map +0 -1
  110. package/dist/interfaces/rest/router.js +0 -259
  111. package/dist/interfaces/rest/routes/admin-jobs.d.ts +0 -5
  112. package/dist/interfaces/rest/routes/admin-jobs.d.ts.map +0 -1
  113. package/dist/interfaces/rest/routes/admin-jobs.js +0 -48
  114. package/dist/interfaces/rest/routes/audit.d.ts +0 -5
  115. package/dist/interfaces/rest/routes/audit.d.ts.map +0 -1
  116. package/dist/interfaces/rest/routes/audit.js +0 -43
  117. package/dist/interfaces/rest/routes/carts.d.ts +0 -5
  118. package/dist/interfaces/rest/routes/carts.d.ts.map +0 -1
  119. package/dist/interfaces/rest/routes/carts.js +0 -55
  120. package/dist/interfaces/rest/routes/catalog.d.ts +0 -5
  121. package/dist/interfaces/rest/routes/catalog.d.ts.map +0 -1
  122. package/dist/interfaces/rest/routes/catalog.js +0 -256
  123. package/dist/interfaces/rest/routes/checkout.d.ts +0 -5
  124. package/dist/interfaces/rest/routes/checkout.d.ts.map +0 -1
  125. package/dist/interfaces/rest/routes/checkout.js +0 -216
  126. package/dist/interfaces/rest/routes/customers.d.ts +0 -5
  127. package/dist/interfaces/rest/routes/customers.d.ts.map +0 -1
  128. package/dist/interfaces/rest/routes/customers.js +0 -74
  129. package/dist/interfaces/rest/routes/entity-aliases.d.ts +0 -18
  130. package/dist/interfaces/rest/routes/entity-aliases.d.ts.map +0 -1
  131. package/dist/interfaces/rest/routes/entity-aliases.js +0 -39
  132. package/dist/interfaces/rest/routes/inventory.d.ts +0 -5
  133. package/dist/interfaces/rest/routes/inventory.d.ts.map +0 -1
  134. package/dist/interfaces/rest/routes/inventory.js +0 -72
  135. package/dist/interfaces/rest/routes/media.d.ts +0 -5
  136. package/dist/interfaces/rest/routes/media.d.ts.map +0 -1
  137. package/dist/interfaces/rest/routes/media.js +0 -65
  138. package/dist/interfaces/rest/routes/orders.d.ts +0 -5
  139. package/dist/interfaces/rest/routes/orders.d.ts.map +0 -1
  140. package/dist/interfaces/rest/routes/orders.js +0 -64
  141. package/dist/interfaces/rest/routes/payments.d.ts +0 -5
  142. package/dist/interfaces/rest/routes/payments.d.ts.map +0 -1
  143. package/dist/interfaces/rest/routes/payments.js +0 -45
  144. package/dist/interfaces/rest/routes/pricing.d.ts +0 -5
  145. package/dist/interfaces/rest/routes/pricing.d.ts.map +0 -1
  146. package/dist/interfaces/rest/routes/pricing.js +0 -48
  147. package/dist/interfaces/rest/routes/promotions.d.ts +0 -5
  148. package/dist/interfaces/rest/routes/promotions.d.ts.map +0 -1
  149. package/dist/interfaces/rest/routes/promotions.js +0 -76
  150. package/dist/interfaces/rest/routes/search.d.ts +0 -5
  151. package/dist/interfaces/rest/routes/search.d.ts.map +0 -1
  152. package/dist/interfaces/rest/routes/search.js +0 -60
  153. package/dist/interfaces/rest/routes/webhooks.d.ts +0 -5
  154. package/dist/interfaces/rest/routes/webhooks.d.ts.map +0 -1
  155. package/dist/interfaces/rest/routes/webhooks.js +0 -39
  156. package/dist/interfaces/rest/schemas/admin-jobs.d.ts +0 -327
  157. package/dist/interfaces/rest/schemas/admin-jobs.d.ts.map +0 -1
  158. package/dist/interfaces/rest/schemas/admin-jobs.js +0 -37
  159. package/dist/interfaces/rest/schemas/audit.d.ts +0 -59
  160. package/dist/interfaces/rest/schemas/audit.d.ts.map +0 -1
  161. package/dist/interfaces/rest/schemas/audit.js +0 -43
  162. package/dist/interfaces/rest/schemas/carts.d.ts +0 -1456
  163. package/dist/interfaces/rest/schemas/carts.d.ts.map +0 -1
  164. package/dist/interfaces/rest/schemas/carts.js +0 -109
  165. package/dist/interfaces/rest/schemas/catalog.d.ts +0 -5452
  166. package/dist/interfaces/rest/schemas/catalog.d.ts.map +0 -1
  167. package/dist/interfaces/rest/schemas/catalog.js +0 -397
  168. package/dist/interfaces/rest/schemas/checkout.d.ts +0 -160
  169. package/dist/interfaces/rest/schemas/checkout.d.ts.map +0 -1
  170. package/dist/interfaces/rest/schemas/checkout.js +0 -60
  171. package/dist/interfaces/rest/schemas/customer-portal.d.ts +0 -2203
  172. package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +0 -1
  173. package/dist/interfaces/rest/schemas/customer-portal.js +0 -177
  174. package/dist/interfaces/rest/schemas/customers.d.ts +0 -422
  175. package/dist/interfaces/rest/schemas/customers.d.ts.map +0 -1
  176. package/dist/interfaces/rest/schemas/customers.js +0 -150
  177. package/dist/interfaces/rest/schemas/inventory.d.ts +0 -561
  178. package/dist/interfaces/rest/schemas/inventory.d.ts.map +0 -1
  179. package/dist/interfaces/rest/schemas/inventory.js +0 -148
  180. package/dist/interfaces/rest/schemas/media.d.ts +0 -303
  181. package/dist/interfaces/rest/schemas/media.d.ts.map +0 -1
  182. package/dist/interfaces/rest/schemas/media.js +0 -69
  183. package/dist/interfaces/rest/schemas/orders.d.ts +0 -1792
  184. package/dist/interfaces/rest/schemas/orders.d.ts.map +0 -1
  185. package/dist/interfaces/rest/schemas/orders.js +0 -93
  186. package/dist/interfaces/rest/schemas/pricing.d.ts +0 -256
  187. package/dist/interfaces/rest/schemas/pricing.d.ts.map +0 -1
  188. package/dist/interfaces/rest/schemas/pricing.js +0 -72
  189. package/dist/interfaces/rest/schemas/promotions.d.ts +0 -363
  190. package/dist/interfaces/rest/schemas/promotions.d.ts.map +0 -1
  191. package/dist/interfaces/rest/schemas/promotions.js +0 -98
  192. package/dist/interfaces/rest/schemas/responses.d.ts +0 -4086
  193. package/dist/interfaces/rest/schemas/responses.d.ts.map +0 -1
  194. package/dist/interfaces/rest/schemas/responses.js +0 -74
  195. package/dist/interfaces/rest/schemas/search.d.ts +0 -247
  196. package/dist/interfaces/rest/schemas/search.d.ts.map +0 -1
  197. package/dist/interfaces/rest/schemas/search.js +0 -55
  198. package/dist/interfaces/rest/schemas/shared.d.ts +0 -95
  199. package/dist/interfaces/rest/schemas/shared.d.ts.map +0 -1
  200. package/dist/interfaces/rest/schemas/shared.js +0 -51
  201. package/dist/interfaces/rest/schemas/webhooks.d.ts +0 -221
  202. package/dist/interfaces/rest/schemas/webhooks.d.ts.map +0 -1
  203. package/dist/interfaces/rest/schemas/webhooks.js +0 -62
  204. package/dist/interfaces/rest/utils.d.ts +0 -45
  205. package/dist/interfaces/rest/utils.d.ts.map +0 -1
  206. package/dist/interfaces/rest/utils.js +0 -71
  207. package/dist/interfaces/rest/webhook-router.d.ts +0 -41
  208. package/dist/interfaces/rest/webhook-router.d.ts.map +0 -1
  209. package/dist/interfaces/rest/webhook-router.js +0 -36
  210. package/dist/kernel/compensation/executor.d.ts +0 -21
  211. package/dist/kernel/compensation/executor.d.ts.map +0 -1
  212. package/dist/kernel/compensation/executor.js +0 -36
  213. package/dist/kernel/compensation/types.d.ts +0 -25
  214. package/dist/kernel/compensation/types.d.ts.map +0 -1
  215. package/dist/kernel/compensation/types.js +0 -1
  216. package/dist/kernel/database/adapter.d.ts +0 -18
  217. package/dist/kernel/database/adapter.d.ts.map +0 -1
  218. package/dist/kernel/database/adapter.js +0 -3
  219. package/dist/kernel/database/drizzle-db.d.ts +0 -49
  220. package/dist/kernel/database/drizzle-db.d.ts.map +0 -1
  221. package/dist/kernel/database/drizzle-db.js +0 -20
  222. package/dist/kernel/database/migrate.d.ts +0 -38
  223. package/dist/kernel/database/migrate.d.ts.map +0 -1
  224. package/dist/kernel/database/migrate.js +0 -61
  225. package/dist/kernel/database/plugin-types.d.ts +0 -32
  226. package/dist/kernel/database/plugin-types.d.ts.map +0 -1
  227. package/dist/kernel/database/plugin-types.js +0 -10
  228. package/dist/kernel/database/schema.d.ts +0 -24
  229. package/dist/kernel/database/schema.d.ts.map +0 -1
  230. package/dist/kernel/database/schema.js +0 -36
  231. package/dist/kernel/database/scoped-db.d.ts +0 -20
  232. package/dist/kernel/database/scoped-db.d.ts.map +0 -1
  233. package/dist/kernel/database/scoped-db.js +0 -62
  234. package/dist/kernel/database/tx-context.d.ts +0 -15
  235. package/dist/kernel/database/tx-context.d.ts.map +0 -1
  236. package/dist/kernel/database/tx-context.js +0 -19
  237. package/dist/kernel/error-mapper.d.ts +0 -3
  238. package/dist/kernel/error-mapper.d.ts.map +0 -1
  239. package/dist/kernel/error-mapper.js +0 -12
  240. package/dist/kernel/errors.d.ts +0 -38
  241. package/dist/kernel/errors.d.ts.map +0 -1
  242. package/dist/kernel/errors.js +0 -69
  243. package/dist/kernel/factory/repository-factory.d.ts +0 -71
  244. package/dist/kernel/factory/repository-factory.d.ts.map +0 -1
  245. package/dist/kernel/factory/repository-factory.js +0 -138
  246. package/dist/kernel/hooks/create-context.d.ts +0 -25
  247. package/dist/kernel/hooks/create-context.d.ts.map +0 -1
  248. package/dist/kernel/hooks/create-context.js +0 -22
  249. package/dist/kernel/hooks/executor.d.ts +0 -12
  250. package/dist/kernel/hooks/executor.d.ts.map +0 -1
  251. package/dist/kernel/hooks/executor.js +0 -50
  252. package/dist/kernel/hooks/registry.d.ts +0 -28
  253. package/dist/kernel/hooks/registry.d.ts.map +0 -1
  254. package/dist/kernel/hooks/registry.js +0 -58
  255. package/dist/kernel/hooks/types.d.ts +0 -37
  256. package/dist/kernel/hooks/types.d.ts.map +0 -1
  257. package/dist/kernel/hooks/types.js +0 -1
  258. package/dist/kernel/http-error.d.ts +0 -30
  259. package/dist/kernel/http-error.d.ts.map +0 -1
  260. package/dist/kernel/http-error.js +0 -35
  261. package/dist/kernel/jobs/adapter.d.ts +0 -25
  262. package/dist/kernel/jobs/adapter.d.ts.map +0 -1
  263. package/dist/kernel/jobs/adapter.js +0 -9
  264. package/dist/kernel/jobs/drizzle-adapter.d.ts +0 -15
  265. package/dist/kernel/jobs/drizzle-adapter.d.ts.map +0 -1
  266. package/dist/kernel/jobs/drizzle-adapter.js +0 -42
  267. package/dist/kernel/jobs/runner.d.ts +0 -24
  268. package/dist/kernel/jobs/runner.d.ts.map +0 -1
  269. package/dist/kernel/jobs/runner.js +0 -114
  270. package/dist/kernel/jobs/schema.d.ts +0 -280
  271. package/dist/kernel/jobs/schema.d.ts.map +0 -1
  272. package/dist/kernel/jobs/schema.js +0 -37
  273. package/dist/kernel/jobs/types.d.ts +0 -30
  274. package/dist/kernel/jobs/types.d.ts.map +0 -1
  275. package/dist/kernel/jobs/types.js +0 -1
  276. package/dist/kernel/local-api.d.ts +0 -103
  277. package/dist/kernel/local-api.d.ts.map +0 -1
  278. package/dist/kernel/local-api.js +0 -89
  279. package/dist/kernel/plugin/manifest.d.ts +0 -90
  280. package/dist/kernel/plugin/manifest.d.ts.map +0 -1
  281. package/dist/kernel/plugin/manifest.js +0 -169
  282. package/dist/kernel/query/executor.d.ts +0 -21
  283. package/dist/kernel/query/executor.d.ts.map +0 -1
  284. package/dist/kernel/query/executor.js +0 -128
  285. package/dist/kernel/query/registry.d.ts +0 -33
  286. package/dist/kernel/query/registry.d.ts.map +0 -1
  287. package/dist/kernel/query/registry.js +0 -20
  288. package/dist/kernel/result.d.ts +0 -36
  289. package/dist/kernel/result.d.ts.map +0 -1
  290. package/dist/kernel/result.js +0 -16
  291. package/dist/kernel/schema/extra-columns.d.ts +0 -23
  292. package/dist/kernel/schema/extra-columns.d.ts.map +0 -1
  293. package/dist/kernel/schema/extra-columns.js +0 -10
  294. package/dist/kernel/service-registry.d.ts +0 -109
  295. package/dist/kernel/service-registry.d.ts.map +0 -1
  296. package/dist/kernel/service-registry.js +0 -26
  297. package/dist/kernel/service-timing.d.ts +0 -25
  298. package/dist/kernel/service-timing.d.ts.map +0 -1
  299. package/dist/kernel/service-timing.js +0 -62
  300. package/dist/kernel/state-machine/machine.d.ts +0 -24
  301. package/dist/kernel/state-machine/machine.d.ts.map +0 -1
  302. package/dist/kernel/state-machine/machine.js +0 -70
  303. package/dist/modules/analytics/drizzle-adapter.d.ts +0 -13
  304. package/dist/modules/analytics/drizzle-adapter.d.ts.map +0 -1
  305. package/dist/modules/analytics/drizzle-adapter.js +0 -358
  306. package/dist/modules/analytics/hooks.d.ts +0 -13
  307. package/dist/modules/analytics/hooks.d.ts.map +0 -1
  308. package/dist/modules/analytics/hooks.js +0 -12
  309. package/dist/modules/analytics/models.d.ts +0 -14
  310. package/dist/modules/analytics/models.d.ts.map +0 -1
  311. package/dist/modules/analytics/models.js +0 -118
  312. package/dist/modules/analytics/repository/index.d.ts +0 -5
  313. package/dist/modules/analytics/repository/index.d.ts.map +0 -1
  314. package/dist/modules/analytics/repository/index.js +0 -1
  315. package/dist/modules/analytics/service.d.ts +0 -45
  316. package/dist/modules/analytics/service.d.ts.map +0 -1
  317. package/dist/modules/analytics/service.js +0 -196
  318. package/dist/modules/analytics/types.d.ts +0 -119
  319. package/dist/modules/analytics/types.d.ts.map +0 -1
  320. package/dist/modules/analytics/types.js +0 -25
  321. package/dist/modules/audit/hooks.d.ts +0 -7
  322. package/dist/modules/audit/hooks.d.ts.map +0 -1
  323. package/dist/modules/audit/hooks.js +0 -67
  324. package/dist/modules/audit/schema.d.ts +0 -178
  325. package/dist/modules/audit/schema.d.ts.map +0 -1
  326. package/dist/modules/audit/schema.js +0 -21
  327. package/dist/modules/audit/service.d.ts +0 -38
  328. package/dist/modules/audit/service.d.ts.map +0 -1
  329. package/dist/modules/audit/service.js +0 -109
  330. package/dist/modules/cart/access.d.ts +0 -11
  331. package/dist/modules/cart/access.d.ts.map +0 -1
  332. package/dist/modules/cart/access.js +0 -18
  333. package/dist/modules/cart/matcher.d.ts +0 -20
  334. package/dist/modules/cart/matcher.d.ts.map +0 -1
  335. package/dist/modules/cart/matcher.js +0 -2
  336. package/dist/modules/cart/repository/index.d.ts +0 -45
  337. package/dist/modules/cart/repository/index.d.ts.map +0 -1
  338. package/dist/modules/cart/repository/index.js +0 -158
  339. package/dist/modules/cart/schema.d.ts +0 -359
  340. package/dist/modules/cart/schema.d.ts.map +0 -1
  341. package/dist/modules/cart/schema.js +0 -40
  342. package/dist/modules/cart/schemas.d.ts +0 -29
  343. package/dist/modules/cart/schemas.d.ts.map +0 -1
  344. package/dist/modules/cart/schemas.js +0 -14
  345. package/dist/modules/cart/service.d.ts +0 -63
  346. package/dist/modules/cart/service.d.ts.map +0 -1
  347. package/dist/modules/cart/service.js +0 -339
  348. package/dist/modules/catalog/repository/index.d.ts +0 -106
  349. package/dist/modules/catalog/repository/index.d.ts.map +0 -1
  350. package/dist/modules/catalog/repository/index.js +0 -455
  351. package/dist/modules/catalog/schema.d.ts +0 -1193
  352. package/dist/modules/catalog/schema.d.ts.map +0 -1
  353. package/dist/modules/catalog/schema.js +0 -149
  354. package/dist/modules/catalog/schemas.d.ts +0 -81
  355. package/dist/modules/catalog/schemas.d.ts.map +0 -1
  356. package/dist/modules/catalog/schemas.js +0 -62
  357. package/dist/modules/catalog/service.d.ts +0 -160
  358. package/dist/modules/catalog/service.d.ts.map +0 -1
  359. package/dist/modules/catalog/service.js +0 -759
  360. package/dist/modules/customers/repository/index.d.ts +0 -47
  361. package/dist/modules/customers/repository/index.d.ts.map +0 -1
  362. package/dist/modules/customers/repository/index.js +0 -206
  363. package/dist/modules/customers/schema.d.ts +0 -560
  364. package/dist/modules/customers/schema.d.ts.map +0 -1
  365. package/dist/modules/customers/schema.js +0 -60
  366. package/dist/modules/customers/service.d.ts +0 -27
  367. package/dist/modules/customers/service.d.ts.map +0 -1
  368. package/dist/modules/customers/service.js +0 -106
  369. package/dist/modules/fulfillment/repository/index.d.ts +0 -63
  370. package/dist/modules/fulfillment/repository/index.d.ts.map +0 -1
  371. package/dist/modules/fulfillment/repository/index.js +0 -268
  372. package/dist/modules/fulfillment/schema.d.ts +0 -655
  373. package/dist/modules/fulfillment/schema.d.ts.map +0 -1
  374. package/dist/modules/fulfillment/schema.js +0 -83
  375. package/dist/modules/fulfillment/service.d.ts +0 -58
  376. package/dist/modules/fulfillment/service.d.ts.map +0 -1
  377. package/dist/modules/fulfillment/service.js +0 -338
  378. package/dist/modules/fulfillment/types.d.ts +0 -44
  379. package/dist/modules/fulfillment/types.d.ts.map +0 -1
  380. package/dist/modules/fulfillment/types.js +0 -1
  381. package/dist/modules/inventory/repository/index.d.ts +0 -81
  382. package/dist/modules/inventory/repository/index.d.ts.map +0 -1
  383. package/dist/modules/inventory/repository/index.js +0 -310
  384. package/dist/modules/inventory/schema.d.ts +0 -570
  385. package/dist/modules/inventory/schema.d.ts.map +0 -1
  386. package/dist/modules/inventory/schema.js +0 -69
  387. package/dist/modules/inventory/schemas.d.ts +0 -31
  388. package/dist/modules/inventory/schemas.d.ts.map +0 -1
  389. package/dist/modules/inventory/schemas.js +0 -28
  390. package/dist/modules/inventory/service.d.ts +0 -69
  391. package/dist/modules/inventory/service.d.ts.map +0 -1
  392. package/dist/modules/inventory/service.js +0 -283
  393. package/dist/modules/media/adapter.d.ts +0 -16
  394. package/dist/modules/media/adapter.d.ts.map +0 -1
  395. package/dist/modules/media/adapter.js +0 -1
  396. package/dist/modules/media/repository/index.d.ts +0 -35
  397. package/dist/modules/media/repository/index.d.ts.map +0 -1
  398. package/dist/modules/media/repository/index.js +0 -176
  399. package/dist/modules/media/schema.d.ts +0 -289
  400. package/dist/modules/media/schema.d.ts.map +0 -1
  401. package/dist/modules/media/schema.js +0 -35
  402. package/dist/modules/media/service.d.ts +0 -42
  403. package/dist/modules/media/service.d.ts.map +0 -1
  404. package/dist/modules/media/service.js +0 -89
  405. package/dist/modules/orders/repository/index.d.ts +0 -48
  406. package/dist/modules/orders/repository/index.d.ts.map +0 -1
  407. package/dist/modules/orders/repository/index.js +0 -199
  408. package/dist/modules/orders/schema.d.ts +0 -672
  409. package/dist/modules/orders/schema.d.ts.map +0 -1
  410. package/dist/modules/orders/schema.js +0 -63
  411. package/dist/modules/orders/service.d.ts +0 -85
  412. package/dist/modules/orders/service.d.ts.map +0 -1
  413. package/dist/modules/orders/service.js +0 -313
  414. package/dist/modules/orders/stale-order-cleanup.d.ts +0 -27
  415. package/dist/modules/orders/stale-order-cleanup.d.ts.map +0 -1
  416. package/dist/modules/orders/stale-order-cleanup.js +0 -55
  417. package/dist/modules/organization/service.d.ts +0 -53
  418. package/dist/modules/organization/service.d.ts.map +0 -1
  419. package/dist/modules/organization/service.js +0 -151
  420. package/dist/modules/payments/adapter.d.ts +0 -42
  421. package/dist/modules/payments/adapter.d.ts.map +0 -1
  422. package/dist/modules/payments/adapter.js +0 -1
  423. package/dist/modules/payments/repository/index.d.ts +0 -5
  424. package/dist/modules/payments/repository/index.d.ts.map +0 -1
  425. package/dist/modules/payments/repository/index.js +0 -1
  426. package/dist/modules/payments/service.d.ts +0 -23
  427. package/dist/modules/payments/service.d.ts.map +0 -1
  428. package/dist/modules/payments/service.js +0 -72
  429. package/dist/modules/pricing/repository/index.d.ts +0 -34
  430. package/dist/modules/pricing/repository/index.d.ts.map +0 -1
  431. package/dist/modules/pricing/repository/index.js +0 -176
  432. package/dist/modules/pricing/schema.d.ts +0 -565
  433. package/dist/modules/pricing/schema.d.ts.map +0 -1
  434. package/dist/modules/pricing/schema.js +0 -57
  435. package/dist/modules/pricing/schemas.d.ts +0 -37
  436. package/dist/modules/pricing/schemas.d.ts.map +0 -1
  437. package/dist/modules/pricing/schemas.js +0 -30
  438. package/dist/modules/pricing/service.d.ts +0 -62
  439. package/dist/modules/pricing/service.d.ts.map +0 -1
  440. package/dist/modules/pricing/service.js +0 -308
  441. package/dist/modules/promotions/repository/index.d.ts +0 -41
  442. package/dist/modules/promotions/repository/index.d.ts.map +0 -1
  443. package/dist/modules/promotions/repository/index.js +0 -204
  444. package/dist/modules/promotions/schema.d.ts +0 -427
  445. package/dist/modules/promotions/schema.d.ts.map +0 -1
  446. package/dist/modules/promotions/schema.js +0 -52
  447. package/dist/modules/promotions/schemas.d.ts +0 -33
  448. package/dist/modules/promotions/schemas.d.ts.map +0 -1
  449. package/dist/modules/promotions/schemas.js +0 -32
  450. package/dist/modules/promotions/service.d.ts +0 -80
  451. package/dist/modules/promotions/service.d.ts.map +0 -1
  452. package/dist/modules/promotions/service.js +0 -347
  453. package/dist/modules/search/adapter.d.ts +0 -51
  454. package/dist/modules/search/adapter.d.ts.map +0 -1
  455. package/dist/modules/search/adapter.js +0 -1
  456. package/dist/modules/search/hooks.d.ts +0 -8
  457. package/dist/modules/search/hooks.d.ts.map +0 -1
  458. package/dist/modules/search/hooks.js +0 -6
  459. package/dist/modules/search/repository/index.d.ts +0 -5
  460. package/dist/modules/search/repository/index.d.ts.map +0 -1
  461. package/dist/modules/search/repository/index.js +0 -1
  462. package/dist/modules/search/service.d.ts +0 -24
  463. package/dist/modules/search/service.d.ts.map +0 -1
  464. package/dist/modules/search/service.js +0 -217
  465. package/dist/modules/shipping/calculator.d.ts +0 -42
  466. package/dist/modules/shipping/calculator.d.ts.map +0 -1
  467. package/dist/modules/shipping/calculator.js +0 -91
  468. package/dist/modules/shipping/repository/index.d.ts +0 -5
  469. package/dist/modules/shipping/repository/index.d.ts.map +0 -1
  470. package/dist/modules/shipping/repository/index.js +0 -1
  471. package/dist/modules/shipping/service.d.ts +0 -28
  472. package/dist/modules/shipping/service.d.ts.map +0 -1
  473. package/dist/modules/shipping/service.js +0 -20
  474. package/dist/modules/tax/adapter.d.ts +0 -58
  475. package/dist/modules/tax/adapter.d.ts.map +0 -1
  476. package/dist/modules/tax/adapter.js +0 -1
  477. package/dist/modules/tax/repository/index.d.ts +0 -5
  478. package/dist/modules/tax/repository/index.d.ts.map +0 -1
  479. package/dist/modules/tax/repository/index.js +0 -1
  480. package/dist/modules/tax/service.d.ts +0 -19
  481. package/dist/modules/tax/service.d.ts.map +0 -1
  482. package/dist/modules/tax/service.js +0 -34
  483. package/dist/modules/webhooks/hook.d.ts +0 -13
  484. package/dist/modules/webhooks/hook.d.ts.map +0 -1
  485. package/dist/modules/webhooks/hook.js +0 -29
  486. package/dist/modules/webhooks/repository/index.d.ts +0 -40
  487. package/dist/modules/webhooks/repository/index.d.ts.map +0 -1
  488. package/dist/modules/webhooks/repository/index.js +0 -175
  489. package/dist/modules/webhooks/schema.d.ts +0 -404
  490. package/dist/modules/webhooks/schema.d.ts.map +0 -1
  491. package/dist/modules/webhooks/schema.js +0 -40
  492. package/dist/modules/webhooks/service.d.ts +0 -23
  493. package/dist/modules/webhooks/service.d.ts.map +0 -1
  494. package/dist/modules/webhooks/service.js +0 -92
  495. package/dist/modules/webhooks/signing.d.ts +0 -2
  496. package/dist/modules/webhooks/signing.d.ts.map +0 -1
  497. package/dist/modules/webhooks/signing.js +0 -5
  498. package/dist/modules/webhooks/ssrf-guard.d.ts +0 -19
  499. package/dist/modules/webhooks/ssrf-guard.d.ts.map +0 -1
  500. package/dist/modules/webhooks/ssrf-guard.js +0 -79
  501. package/dist/modules/webhooks/tasks.d.ts +0 -16
  502. package/dist/modules/webhooks/tasks.d.ts.map +0 -1
  503. package/dist/modules/webhooks/tasks.js +0 -35
  504. package/dist/modules/webhooks/worker.d.ts +0 -21
  505. package/dist/modules/webhooks/worker.d.ts.map +0 -1
  506. package/dist/modules/webhooks/worker.js +0 -113
  507. package/dist/runtime/commerce.d.ts +0 -110
  508. package/dist/runtime/commerce.d.ts.map +0 -1
  509. package/dist/runtime/commerce.js +0 -37
  510. package/dist/runtime/kernel.d.ts +0 -71
  511. package/dist/runtime/kernel.d.ts.map +0 -1
  512. package/dist/runtime/kernel.js +0 -306
  513. package/dist/runtime/logger.d.ts +0 -11
  514. package/dist/runtime/logger.d.ts.map +0 -1
  515. package/dist/runtime/logger.js +0 -32
  516. package/dist/runtime/shutdown.d.ts +0 -15
  517. package/dist/runtime/shutdown.d.ts.map +0 -1
  518. package/dist/runtime/shutdown.js +0 -34
  519. package/dist/test-utils/create-pglite-adapter.d.ts +0 -32
  520. package/dist/test-utils/create-pglite-adapter.d.ts.map +0 -1
  521. package/dist/test-utils/create-pglite-adapter.js +0 -107
  522. package/dist/test-utils/create-plugin-test-app.d.ts +0 -50
  523. package/dist/test-utils/create-plugin-test-app.d.ts.map +0 -1
  524. package/dist/test-utils/create-plugin-test-app.js +0 -74
  525. package/dist/test-utils/create-repository-test-harness.d.ts +0 -8
  526. package/dist/test-utils/create-repository-test-harness.d.ts.map +0 -1
  527. package/dist/test-utils/create-repository-test-harness.js +0 -7
  528. package/dist/test-utils/create-test-config.d.ts +0 -18
  529. package/dist/test-utils/create-test-config.d.ts.map +0 -1
  530. package/dist/test-utils/create-test-config.js +0 -172
  531. package/dist/test-utils/create-test-kernel.d.ts +0 -3
  532. package/dist/test-utils/create-test-kernel.d.ts.map +0 -1
  533. package/dist/test-utils/create-test-kernel.js +0 -5
  534. package/dist/test-utils/create-test-plugin-context.d.ts +0 -42
  535. package/dist/test-utils/create-test-plugin-context.d.ts.map +0 -1
  536. package/dist/test-utils/create-test-plugin-context.js +0 -46
  537. package/dist/test-utils/rest-api-test-utils.d.ts +0 -64
  538. package/dist/test-utils/rest-api-test-utils.d.ts.map +0 -1
  539. package/dist/test-utils/rest-api-test-utils.js +0 -207
  540. package/dist/test-utils/test-actors.d.ts +0 -15
  541. package/dist/test-utils/test-actors.d.ts.map +0 -1
  542. package/dist/test-utils/test-actors.js +0 -57
  543. package/dist/test-utils/typed-hooks.d.ts +0 -43
  544. package/dist/test-utils/typed-hooks.d.ts.map +0 -1
  545. package/dist/test-utils/typed-hooks.js +0 -35
  546. package/dist/testing.d.ts +0 -14
  547. package/dist/testing.d.ts.map +0 -1
  548. package/dist/testing.js +0 -13
  549. package/dist/tsconfig.tsbuildinfo +0 -1
  550. package/dist/types/commerce-types.d.ts +0 -34
  551. package/dist/types/commerce-types.d.ts.map +0 -1
  552. package/dist/types/commerce-types.js +0 -1
  553. package/dist/utils/id.d.ts +0 -2
  554. package/dist/utils/id.d.ts.map +0 -1
  555. package/dist/utils/id.js +0 -3
  556. package/dist/utils/logger.d.ts +0 -3
  557. package/dist/utils/logger.d.ts.map +0 -1
  558. package/dist/utils/logger.js +0 -16
  559. package/dist/utils/pagination.d.ts +0 -11
  560. package/dist/utils/pagination.d.ts.map +0 -1
  561. package/dist/utils/pagination.js +0 -15
@@ -1,30 +0,0 @@
1
- import { z } from "@hono/zod-openapi";
2
- // ─── Zod Body Schemas (single source of truth) ─────────────────────────────
3
- export const SetBasePriceBodySchema = z.object({
4
- entityId: z.string().openapi({ example: "product-uuid" }),
5
- variantId: z.string().optional().openapi({ example: "variant-uuid" }),
6
- currency: z.string().length(3).openapi({ example: "USD" }),
7
- amount: z.number().openapi({ example: 29.99 }),
8
- customerGroupId: z.string().optional(),
9
- minQuantity: z.number().int().optional(),
10
- maxQuantity: z.number().int().optional(),
11
- validFrom: z.coerce.date().optional(),
12
- validUntil: z.coerce.date().optional(),
13
- metadata: z.record(z.string(), z.unknown()).optional(),
14
- }).openapi("SetBasePriceRequest");
15
- export const CreateModifierBodySchema = z.object({
16
- name: z.string().openapi({ example: "Summer Sale" }),
17
- type: z.enum(["percentage_discount", "fixed_discount", "markup", "override"]).openapi({ example: "percentage_discount" }),
18
- value: z.number().openapi({ example: 10 }),
19
- priority: z.number().int().optional(),
20
- entityId: z.string().optional(),
21
- variantId: z.string().optional(),
22
- customerGroupId: z.string().optional(),
23
- currency: z.string().length(3).optional().openapi({ example: "USD" }),
24
- minQuantity: z.number().int().optional(),
25
- maxQuantity: z.number().int().optional(),
26
- conditions: z.record(z.string(), z.unknown()).optional(),
27
- validFrom: z.coerce.date().optional(),
28
- validUntil: z.coerce.date().optional(),
29
- metadata: z.record(z.string(), z.unknown()).optional(),
30
- }).openapi("CreateModifierRequest");
@@ -1,62 +0,0 @@
1
- import type { Actor } from "../../auth/types.js";
2
- import { type Result } from "../../kernel/result.js";
3
- import type { TxContext } from "../../kernel/database/tx-context.js";
4
- import type { PricingRepository, Price, PriceModifier } from "./repository/index.js";
5
- import type { CatalogRepository } from "../catalog/repository/index.js";
6
- export type PriceModifierType = "percentage_discount" | "fixed_discount" | "markup" | "override";
7
- interface PricingServiceDeps {
8
- repository: PricingRepository;
9
- catalogRepository: CatalogRepository;
10
- }
11
- export interface PriceResolutionContext {
12
- entityId: string;
13
- variantId?: string;
14
- currency: string;
15
- quantity: number;
16
- customerId?: string;
17
- customerGroupIds?: string[];
18
- timestamp?: Date;
19
- }
20
- export interface PriceBreakdownStep {
21
- label: string;
22
- amountBefore: number;
23
- delta: number;
24
- amountAfter: number;
25
- metadata?: Record<string, unknown>;
26
- }
27
- export interface ResolvedPrice {
28
- baseAmount: number;
29
- finalAmount: number;
30
- currency: string;
31
- appliedModifiers: Array<{
32
- id: string;
33
- name: string;
34
- type: PriceModifierType;
35
- delta: number;
36
- value: number;
37
- priority: number;
38
- }>;
39
- breakdown: PriceBreakdownStep[];
40
- basePriceId: string;
41
- }
42
- export type { SetBasePriceInput, CreatePriceModifierInput } from "./schemas.js";
43
- import type { SetBasePriceInput, CreatePriceModifierInput } from "./schemas.js";
44
- export declare class PricingService {
45
- private deps;
46
- private readonly repo;
47
- private readonly catalogRepo;
48
- constructor(deps: PricingServiceDeps);
49
- setBasePrice(input: SetBasePriceInput, actor?: Actor | null, ctx?: TxContext): Promise<Result<Price>>;
50
- createModifier(input: CreatePriceModifierInput, actor?: Actor | null, ctx?: TxContext): Promise<Result<PriceModifier>>;
51
- listPrices(filter?: {
52
- entityId?: string;
53
- variantId?: string;
54
- currency?: string;
55
- customerGroupId?: string;
56
- }, ctx?: TxContext): Promise<Result<{
57
- prices: Price[];
58
- modifiers: PriceModifier[];
59
- }>>;
60
- resolve(input: PriceResolutionContext, ctx?: TxContext): Promise<Result<ResolvedPrice>>;
61
- }
62
- //# sourceMappingURL=service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/pricing/service.ts"],"names":[],"mappings":"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"}
@@ -1,308 +0,0 @@
1
- import { resolveOrgId } from "../../auth/org.js";
2
- import { CommerceNotFoundError, CommerceValidationError, } from "../../kernel/errors.js";
3
- import { Err, Ok } from "../../kernel/result.js";
4
- function matchesQuantity(min, max, quantity) {
5
- if (min != null && quantity < min)
6
- return false;
7
- if (max != null && quantity > max)
8
- return false;
9
- return true;
10
- }
11
- function matchesWindow(validFrom, validUntil, timestamp) {
12
- if (validFrom && timestamp < validFrom)
13
- return false;
14
- if (validUntil && timestamp > validUntil)
15
- return false;
16
- return true;
17
- }
18
- function durationScore(validFrom, validUntil) {
19
- if (validFrom && validUntil)
20
- return validUntil.getTime() - validFrom.getTime();
21
- if (validFrom || validUntil)
22
- return Number.MAX_SAFE_INTEGER - 1;
23
- return Number.MAX_SAFE_INTEGER;
24
- }
25
- function quantityRangeWidth(min, max) {
26
- if (min != null && max != null)
27
- return Math.max(0, max - min);
28
- if (min != null || max != null)
29
- return Number.MAX_SAFE_INTEGER - 1;
30
- return Number.MAX_SAFE_INTEGER;
31
- }
32
- function compareBasePriceSpecificity(a, b, context) {
33
- const aVariant = context.variantId !== undefined && a.variantId === context.variantId
34
- ? 1
35
- : 0;
36
- const bVariant = context.variantId !== undefined && b.variantId === context.variantId
37
- ? 1
38
- : 0;
39
- if (aVariant !== bVariant)
40
- return bVariant - aVariant;
41
- const hasGroupA = a.customerGroupId ? 1 : 0;
42
- const hasGroupB = b.customerGroupId ? 1 : 0;
43
- if (hasGroupA !== hasGroupB)
44
- return hasGroupB - hasGroupA;
45
- const aRange = quantityRangeWidth(a.minQuantity, a.maxQuantity);
46
- const bRange = quantityRangeWidth(b.minQuantity, b.maxQuantity);
47
- if (aRange !== bRange)
48
- return aRange - bRange;
49
- const aDuration = durationScore(a.validFrom, a.validUntil);
50
- const bDuration = durationScore(b.validFrom, b.validUntil);
51
- if (aDuration !== bDuration)
52
- return aDuration - bDuration;
53
- return b.createdAt.getTime() - a.createdAt.getTime();
54
- }
55
- function resolveModifierDelta(type, value, amountBefore) {
56
- switch (type) {
57
- case "percentage_discount":
58
- return -Math.round((amountBefore * value) / 100);
59
- case "fixed_discount":
60
- return -value;
61
- case "markup":
62
- return value;
63
- case "override":
64
- return value - amountBefore;
65
- default:
66
- return 0;
67
- }
68
- }
69
- function toGroupSet(context) {
70
- return new Set(context.customerGroupIds ?? []);
71
- }
72
- function normalizeCurrency(currency) {
73
- return currency.trim().toUpperCase();
74
- }
75
- export class PricingService {
76
- deps;
77
- repo;
78
- catalogRepo;
79
- constructor(deps) {
80
- this.deps = deps;
81
- this.repo = deps.repository;
82
- this.catalogRepo = deps.catalogRepository;
83
- }
84
- async setBasePrice(input, actor, ctx) {
85
- if (input.amount < 0) {
86
- return Err(new CommerceValidationError("Base price amount cannot be negative."));
87
- }
88
- const entity = await this.catalogRepo.findEntityById(input.entityId, ctx);
89
- if (!entity) {
90
- return Err(new CommerceNotFoundError("Entity not found for price assignment."));
91
- }
92
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
93
- const priceData = {
94
- organizationId: orgId,
95
- entityId: input.entityId,
96
- currency: normalizeCurrency(input.currency),
97
- amount: input.amount,
98
- metadata: input.metadata ?? {},
99
- variantId: input.variantId ?? null,
100
- customerGroupId: input.customerGroupId ?? null,
101
- minQuantity: input.minQuantity ?? null,
102
- maxQuantity: input.maxQuantity ?? null,
103
- validFrom: input.validFrom ?? null,
104
- validUntil: input.validUntil ?? null,
105
- };
106
- const record = await this.repo.createPrice(priceData, ctx);
107
- return Ok(record);
108
- }
109
- async createModifier(input, actor, ctx) {
110
- if (!input.name) {
111
- return Err(new CommerceValidationError("Modifier name is required."));
112
- }
113
- // Validate modifier type
114
- const validTypes = [
115
- "percentage_discount",
116
- "fixed_discount",
117
- "markup",
118
- "override",
119
- ];
120
- if (!validTypes.includes(input.type)) {
121
- return Err(new CommerceValidationError(`Invalid modifier type "${input.type}". Must be one of: ${validTypes.join(", ")}`));
122
- }
123
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
124
- const modifierData = {
125
- organizationId: orgId,
126
- name: input.name,
127
- type: input.type,
128
- value: input.value,
129
- priority: input.priority ?? 100,
130
- conditions: input.conditions ?? {},
131
- metadata: input.metadata ?? {},
132
- entityId: input.entityId ?? null,
133
- variantId: input.variantId ?? null,
134
- customerGroupId: input.customerGroupId ?? null,
135
- currency: input.currency ? normalizeCurrency(input.currency) : null,
136
- minQuantity: input.minQuantity ?? null,
137
- maxQuantity: input.maxQuantity ?? null,
138
- validFrom: input.validFrom ?? null,
139
- validUntil: input.validUntil ?? null,
140
- };
141
- const modifier = await this.repo.createModifier(modifierData, ctx);
142
- return Ok(modifier);
143
- }
144
- async listPrices(filter, ctx) {
145
- // Get all prices for the entity if specified, or filter after retrieval
146
- let prices = [];
147
- if (filter?.entityId) {
148
- prices = await this.repo.findPricesByEntityId(filter.entityId, ctx);
149
- }
150
- // Note: For full list without entityId, we'd need a findAll method
151
- // For now, entityId is typically required for practical use
152
- // Apply additional filters
153
- if (filter?.variantId !== undefined) {
154
- prices = prices.filter((p) => p.variantId === filter.variantId);
155
- }
156
- if (filter?.currency !== undefined) {
157
- const normalizedCurrency = normalizeCurrency(filter.currency);
158
- prices = prices.filter((p) => p.currency === normalizedCurrency);
159
- }
160
- if (filter?.customerGroupId !== undefined) {
161
- prices = prices.filter((p) => p.customerGroupId === filter.customerGroupId);
162
- }
163
- // Get modifiers for the entity
164
- let modifiers = [];
165
- if (filter?.entityId) {
166
- modifiers = await this.repo.findModifiersByEntityId(filter.entityId, ctx);
167
- }
168
- // Apply additional filters
169
- if (filter?.variantId !== undefined) {
170
- modifiers = modifiers.filter((m) => m.variantId === filter.variantId);
171
- }
172
- if (filter?.currency !== undefined) {
173
- const normalizedCurrency = normalizeCurrency(filter.currency);
174
- modifiers = modifiers.filter((m) => m.currency === null || m.currency === normalizedCurrency);
175
- }
176
- if (filter?.customerGroupId !== undefined) {
177
- modifiers = modifiers.filter((m) => m.customerGroupId === null ||
178
- m.customerGroupId === filter.customerGroupId);
179
- }
180
- return Ok({ prices, modifiers });
181
- }
182
- async resolve(input, ctx) {
183
- const entity = await this.catalogRepo.findEntityById(input.entityId, ctx);
184
- if (!entity) {
185
- return Err(new CommerceNotFoundError(`Entity ${input.entityId} not found.`));
186
- }
187
- if (input.quantity <= 0) {
188
- return Err(new CommerceValidationError("Quantity must be greater than zero for price resolution."));
189
- }
190
- const timestamp = input.timestamp ?? new Date();
191
- const currency = normalizeCurrency(input.currency);
192
- const groupSet = toGroupSet(input);
193
- // Get matching prices from repository
194
- const allPrices = await this.repo.findPricesByEntityId(input.entityId, ctx);
195
- const matchingPrices = allPrices.filter((price) => {
196
- if (input.variantId !== undefined) {
197
- if (price.variantId !== null && price.variantId !== input.variantId)
198
- return false;
199
- }
200
- else if (price.variantId !== null) {
201
- return false;
202
- }
203
- if (price.currency !== currency)
204
- return false;
205
- if (!matchesQuantity(price.minQuantity, price.maxQuantity, input.quantity))
206
- return false;
207
- if (!matchesWindow(price.validFrom, price.validUntil, timestamp))
208
- return false;
209
- if (price.customerGroupId !== null &&
210
- !groupSet.has(price.customerGroupId))
211
- return false;
212
- return true;
213
- });
214
- if (matchingPrices.length === 0) {
215
- const metadataPrice = typeof entity.metadata?.basePrice === "number"
216
- ? Math.round(entity.metadata.basePrice)
217
- : undefined;
218
- if (metadataPrice === undefined) {
219
- return Err(new CommerceNotFoundError(`No base price configured for ${entity.slug} (${currency}).`));
220
- }
221
- const fallback = {
222
- baseAmount: metadataPrice,
223
- finalAmount: metadataPrice,
224
- currency,
225
- basePriceId: "metadata:basePrice",
226
- appliedModifiers: [],
227
- breakdown: [
228
- {
229
- label: "Base price (entity metadata)",
230
- amountBefore: metadataPrice,
231
- delta: 0,
232
- amountAfter: metadataPrice,
233
- },
234
- ],
235
- };
236
- return Ok(fallback);
237
- }
238
- const selectedBase = [...matchingPrices].sort((a, b) => compareBasePriceSpecificity(a, b, input))[0];
239
- if (!selectedBase) {
240
- return Err(new CommerceNotFoundError("No matching base price could be selected."));
241
- }
242
- let runningAmount = selectedBase.amount;
243
- const breakdown = [
244
- {
245
- label: "Base price",
246
- amountBefore: selectedBase.amount,
247
- delta: 0,
248
- amountAfter: selectedBase.amount,
249
- metadata: {
250
- priceId: selectedBase.id,
251
- customerGroupId: selectedBase.customerGroupId,
252
- minQuantity: selectedBase.minQuantity,
253
- maxQuantity: selectedBase.maxQuantity,
254
- },
255
- },
256
- ];
257
- const appliedModifiers = [];
258
- // Get matching modifiers (includes both entity-specific and global)
259
- const firstGroupId = groupSet.size > 0 ? [...groupSet][0] : undefined;
260
- const activeModifiers = await this.repo.findActiveModifiers(input.entityId, input.variantId, firstGroupId, currency, input.quantity, ctx);
261
- // Additional filtering for multiple customer groups and conditions
262
- const modifiers = activeModifiers
263
- .filter((modifier) => {
264
- // Re-check customer group for multi-group support
265
- if (modifier.customerGroupId !== null &&
266
- !groupSet.has(modifier.customerGroupId))
267
- return false;
268
- const conditions = modifier.conditions;
269
- const minSubtotal = conditions?.minSubtotal;
270
- if (typeof minSubtotal === "number" && runningAmount < minSubtotal)
271
- return false;
272
- return true;
273
- })
274
- .sort((a, b) => a.priority - b.priority);
275
- for (const modifier of modifiers) {
276
- const amountBefore = runningAmount;
277
- const rawDelta = resolveModifierDelta(modifier.type, modifier.value, amountBefore);
278
- const delta = Math.max(-amountBefore, rawDelta);
279
- runningAmount = Math.max(0, amountBefore + delta);
280
- appliedModifiers.push({
281
- id: modifier.id,
282
- name: modifier.name,
283
- type: modifier.type,
284
- delta,
285
- value: modifier.value,
286
- priority: modifier.priority,
287
- });
288
- breakdown.push({
289
- label: `Modifier: ${modifier.name}`,
290
- amountBefore,
291
- delta,
292
- amountAfter: runningAmount,
293
- metadata: {
294
- type: modifier.type,
295
- priority: modifier.priority,
296
- },
297
- });
298
- }
299
- return Ok({
300
- baseAmount: selectedBase.amount,
301
- finalAmount: runningAmount,
302
- currency,
303
- basePriceId: selectedBase.id,
304
- appliedModifiers,
305
- breakdown,
306
- });
307
- }
308
- }
@@ -1,41 +0,0 @@
1
- import type { TxContext } from "../../../kernel/database/tx-context.js";
2
- import type { DrizzleDatabase } from "../../../kernel/database/drizzle-db.js";
3
- import { promotions, promotionUsages } from "../schema.js";
4
- export type Promotion = typeof promotions.$inferSelect;
5
- export type PromotionInsert = typeof promotions.$inferInsert;
6
- export type PromotionUsage = typeof promotionUsages.$inferSelect;
7
- export type PromotionUsageInsert = typeof promotionUsages.$inferInsert;
8
- /**
9
- * PromotionsRepository provides type-safe database operations for promotions.
10
- *
11
- * This repository manages promotions and their usage tracking.
12
- * All methods support an optional TxContext parameter for transaction participation.
13
- */
14
- export declare class PromotionsRepository {
15
- private readonly db;
16
- constructor(db: DrizzleDatabase);
17
- private getDb;
18
- findById(orgId: string, id: string, ctx?: TxContext): Promise<Promotion | undefined>;
19
- findByCode(orgId: string, code: string, ctx?: TxContext): Promise<Promotion | undefined>;
20
- findAll(orgId: string, ctx?: TxContext): Promise<Promotion[]>;
21
- findActive(orgId: string, ctx?: TxContext): Promise<Promotion[]>;
22
- findAutomatic(orgId: string, ctx?: TxContext): Promise<Promotion[]>;
23
- create(data: PromotionInsert, ctx?: TxContext): Promise<Promotion>;
24
- update(id: string, data: Partial<Omit<PromotionInsert, "id">>, ctx?: TxContext): Promise<Promotion | undefined>;
25
- delete(id: string, ctx?: TxContext): Promise<boolean>;
26
- activate(id: string, ctx?: TxContext): Promise<Promotion | undefined>;
27
- deactivate(id: string, ctx?: TxContext): Promise<Promotion | undefined>;
28
- findUsageById(id: string, ctx?: TxContext): Promise<PromotionUsage | undefined>;
29
- findUsagesByPromotionId(promotionId: string, ctx?: TxContext): Promise<PromotionUsage[]>;
30
- findUsagesByCustomerId(customerId: string, ctx?: TxContext): Promise<PromotionUsage[]>;
31
- createUsage(data: PromotionUsageInsert, ctx?: TxContext): Promise<PromotionUsage>;
32
- countUsages(promotionId: string, ctx?: TxContext): Promise<number>;
33
- countUsagesByCustomer(promotionId: string, customerId: string, ctx?: TxContext): Promise<number>;
34
- isUsageLimitReached(orgId: string, promotionId: string, ctx?: TxContext): Promise<boolean>;
35
- isCustomerUsageLimitReached(orgId: string, promotionId: string, customerId: string, ctx?: TxContext): Promise<boolean>;
36
- isPromotionValid(orgId: string, promotionId: string, customerId?: string, ctx?: TxContext): Promise<{
37
- valid: boolean;
38
- reason?: string;
39
- }>;
40
- }
41
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/promotions/repository/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG3D,MAAM,MAAM,SAAS,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AACvD,MAAM,MAAM,eAAe,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AAC7D,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AACjE,MAAM,MAAM,oBAAoB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEvE;;;;;GAKG;AACH,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,eAAe;IAEhD,OAAO,CAAC,KAAK;IAQP,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IASpF,UAAU,CACd,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAc3B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAS7D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAkBhE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAmBnE,MAAM,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAMlE,MAAM,CACV,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,EAC1C,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAU3B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IASrD,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAIrE,UAAU,CACd,EAAE,EAAE,MAAM,EACV,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAQ3B,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAShC,uBAAuB,CAC3B,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,EAAE,CAAC;IAQtB,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,EAAE,CAAC;IAQtB,WAAW,CACf,IAAI,EAAE,oBAAoB,EAC1B,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,CAAC;IAuCpB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IASlE,qBAAqB,CACzB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;IAkBZ,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,OAAO,CAAC;IASb,2BAA2B,CAC/B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,OAAO,CAAC;IAab,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAiChD"}
@@ -1,204 +0,0 @@
1
- import { eq, and, lte, gte, or, isNull, desc, sql } from "drizzle-orm";
2
- import { promotions, promotionUsages } from "../schema.js";
3
- /**
4
- * PromotionsRepository provides type-safe database operations for promotions.
5
- *
6
- * This repository manages promotions and their usage tracking.
7
- * All methods support an optional TxContext parameter for transaction participation.
8
- */
9
- export class PromotionsRepository {
10
- db;
11
- constructor(db) {
12
- this.db = db;
13
- }
14
- getDb(ctx) {
15
- return ctx?.tx ?? this.db;
16
- }
17
- // ─────────────────────────────────────────────────────────────────────────────
18
- // Promotions
19
- // ─────────────────────────────────────────────────────────────────────────────
20
- async findById(orgId, id, ctx) {
21
- const db = this.getDb(ctx);
22
- const rows = await db
23
- .select()
24
- .from(promotions)
25
- .where(and(eq(promotions.organizationId, orgId), eq(promotions.id, id)));
26
- return rows[0];
27
- }
28
- async findByCode(orgId, code, ctx) {
29
- const db = this.getDb(ctx);
30
- const rows = await db
31
- .select()
32
- .from(promotions)
33
- .where(and(eq(promotions.organizationId, orgId), eq(promotions.code, code)));
34
- return rows[0];
35
- }
36
- async findAll(orgId, ctx) {
37
- const db = this.getDb(ctx);
38
- return db
39
- .select()
40
- .from(promotions)
41
- .where(eq(promotions.organizationId, orgId))
42
- .orderBy(desc(promotions.priority));
43
- }
44
- async findActive(orgId, ctx) {
45
- const db = this.getDb(ctx);
46
- const now = new Date();
47
- return db
48
- .select()
49
- .from(promotions)
50
- .where(and(eq(promotions.organizationId, orgId), eq(promotions.isActive, true), or(isNull(promotions.validFrom), lte(promotions.validFrom, now)), or(isNull(promotions.validUntil), gte(promotions.validUntil, now))))
51
- .orderBy(desc(promotions.priority));
52
- }
53
- async findAutomatic(orgId, ctx) {
54
- const db = this.getDb(ctx);
55
- const now = new Date();
56
- return db
57
- .select()
58
- .from(promotions)
59
- .where(and(eq(promotions.organizationId, orgId), eq(promotions.isActive, true), eq(promotions.isAutomatic, true), or(isNull(promotions.validFrom), lte(promotions.validFrom, now)), or(isNull(promotions.validUntil), gte(promotions.validUntil, now))))
60
- .orderBy(desc(promotions.priority));
61
- }
62
- async create(data, ctx) {
63
- const db = this.getDb(ctx);
64
- const rows = await db.insert(promotions).values(data).returning();
65
- return rows[0];
66
- }
67
- async update(id, data, ctx) {
68
- const db = this.getDb(ctx);
69
- const rows = await db
70
- .update(promotions)
71
- .set({ ...data, updatedAt: new Date() })
72
- .where(eq(promotions.id, id))
73
- .returning();
74
- return rows[0];
75
- }
76
- async delete(id, ctx) {
77
- const db = this.getDb(ctx);
78
- const result = await db
79
- .delete(promotions)
80
- .where(eq(promotions.id, id))
81
- .returning();
82
- return result.length > 0;
83
- }
84
- async activate(id, ctx) {
85
- return this.update(id, { isActive: true }, ctx);
86
- }
87
- async deactivate(id, ctx) {
88
- return this.update(id, { isActive: false }, ctx);
89
- }
90
- // ─────────────────────────────────────────────────────────────────────────────
91
- // Promotion Usages
92
- // ─────────────────────────────────────────────────────────────────────────────
93
- async findUsageById(id, ctx) {
94
- const db = this.getDb(ctx);
95
- const rows = await db
96
- .select()
97
- .from(promotionUsages)
98
- .where(eq(promotionUsages.id, id));
99
- return rows[0];
100
- }
101
- async findUsagesByPromotionId(promotionId, ctx) {
102
- const db = this.getDb(ctx);
103
- return db
104
- .select()
105
- .from(promotionUsages)
106
- .where(eq(promotionUsages.promotionId, promotionId));
107
- }
108
- async findUsagesByCustomerId(customerId, ctx) {
109
- const db = this.getDb(ctx);
110
- return db
111
- .select()
112
- .from(promotionUsages)
113
- .where(eq(promotionUsages.customerId, customerId));
114
- }
115
- async createUsage(data, ctx) {
116
- const db = this.getDb(ctx);
117
- // Atomic guard: use INSERT ... SELECT WHERE count < limit to prevent
118
- // race conditions between concurrent checkouts using the same coupon.
119
- // A plain count-then-insert has a TOCTOU gap; this single statement
120
- // ensures the insert only succeeds if the limit has not been reached.
121
- const promo = await db
122
- .select({ usageLimitTotal: promotions.usageLimitTotal })
123
- .from(promotions)
124
- .where(eq(promotions.id, data.promotionId));
125
- const limit = promo[0]?.usageLimitTotal;
126
- if (limit != null) {
127
- // Atomic guard: lock the promotion row and check usage count in the
128
- // same statement sequence. This prevents two concurrent checkouts
129
- // from both passing the count check (TOCTOU race).
130
- //
131
- // SELECT ... FOR UPDATE acquires a row-level lock that serializes
132
- // concurrent callers. If the caller is already inside a transaction
133
- // (ctx.tx), the lock is held until that transaction commits.
134
- await db.execute(sql `SELECT id FROM promotions WHERE id = ${data.promotionId} FOR UPDATE`);
135
- const currentCount = await this.countUsages(data.promotionId, ctx);
136
- if (currentCount >= limit) {
137
- throw new Error(`Promotion usage limit reached (${currentCount}/${limit})`);
138
- }
139
- const rows = await db.insert(promotionUsages).values(data).returning();
140
- return rows[0];
141
- }
142
- const rows = await db.insert(promotionUsages).values(data).returning();
143
- return rows[0];
144
- }
145
- async countUsages(promotionId, ctx) {
146
- const db = this.getDb(ctx);
147
- const result = await db
148
- .select({ count: sql `count(*)::int` })
149
- .from(promotionUsages)
150
- .where(eq(promotionUsages.promotionId, promotionId));
151
- return result[0]?.count ?? 0;
152
- }
153
- async countUsagesByCustomer(promotionId, customerId, ctx) {
154
- const db = this.getDb(ctx);
155
- const result = await db
156
- .select({ count: sql `count(*)::int` })
157
- .from(promotionUsages)
158
- .where(and(eq(promotionUsages.promotionId, promotionId), eq(promotionUsages.customerId, customerId)));
159
- return result[0]?.count ?? 0;
160
- }
161
- // ─────────────────────────────────────────────────────────────────────────────
162
- // Validation Helpers
163
- // ─────────────────────────────────────────────────────────────────────────────
164
- async isUsageLimitReached(orgId, promotionId, ctx) {
165
- const promotion = await this.findById(orgId, promotionId, ctx);
166
- if (!promotion || promotion.usageLimitTotal === null) {
167
- return false;
168
- }
169
- const count = await this.countUsages(promotionId, ctx);
170
- return count >= promotion.usageLimitTotal;
171
- }
172
- async isCustomerUsageLimitReached(orgId, promotionId, customerId, ctx) {
173
- const promotion = await this.findById(orgId, promotionId, ctx);
174
- if (!promotion || promotion.usageLimitPerCustomer === null) {
175
- return false;
176
- }
177
- const count = await this.countUsagesByCustomer(promotionId, customerId, ctx);
178
- return count >= promotion.usageLimitPerCustomer;
179
- }
180
- async isPromotionValid(orgId, promotionId, customerId, ctx) {
181
- const promotion = await this.findById(orgId, promotionId, ctx);
182
- if (!promotion) {
183
- return { valid: false, reason: "Promotion not found" };
184
- }
185
- if (!promotion.isActive) {
186
- return { valid: false, reason: "Promotion is not active" };
187
- }
188
- const now = new Date();
189
- if (promotion.validFrom && promotion.validFrom > now) {
190
- return { valid: false, reason: "Promotion has not started yet" };
191
- }
192
- if (promotion.validUntil && promotion.validUntil < now) {
193
- return { valid: false, reason: "Promotion has expired" };
194
- }
195
- if (await this.isUsageLimitReached(orgId, promotionId, ctx)) {
196
- return { valid: false, reason: "Promotion usage limit reached" };
197
- }
198
- if (customerId &&
199
- (await this.isCustomerUsageLimitReached(orgId, promotionId, customerId, ctx))) {
200
- return { valid: false, reason: "Customer usage limit reached" };
201
- }
202
- return { valid: true };
203
- }
204
- }