@porulle/core 0.7.0 → 0.9.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 (325) hide show
  1. package/dist/auth/middleware.d.ts.map +1 -1
  2. package/dist/auth/middleware.js +26 -7
  3. package/dist/auth/setup.d.ts.map +1 -1
  4. package/dist/auth/setup.js +8 -5
  5. package/dist/config/defaults.d.ts.map +1 -1
  6. package/dist/config/defaults.js +7 -0
  7. package/dist/config/types.d.ts +26 -1
  8. package/dist/config/types.d.ts.map +1 -1
  9. package/dist/generated/plugin-manifest.d.ts +3 -0
  10. package/dist/generated/plugin-manifest.d.ts.map +1 -1
  11. package/dist/generated/plugin-manifest.js +1 -0
  12. package/dist/hooks/checkout-completion.d.ts.map +1 -1
  13. package/dist/hooks/checkout-completion.js +2 -2
  14. package/dist/hooks/checkout.d.ts.map +1 -1
  15. package/dist/hooks/checkout.js +17 -2
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -0
  19. package/dist/interfaces/rest/index.d.ts.map +1 -1
  20. package/dist/interfaces/rest/index.js +12 -0
  21. package/dist/interfaces/rest/routes/admin/staff.d.ts +12 -0
  22. package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -0
  23. package/dist/interfaces/rest/routes/admin/staff.js +206 -0
  24. package/dist/interfaces/rest/routes/analytics.d.ts +5 -0
  25. package/dist/interfaces/rest/routes/analytics.d.ts.map +1 -0
  26. package/dist/interfaces/rest/routes/analytics.js +24 -0
  27. package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
  28. package/dist/interfaces/rest/routes/carts.js +39 -2
  29. package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
  30. package/dist/interfaces/rest/routes/catalog.js +17 -1
  31. package/dist/interfaces/rest/routes/checkout.d.ts +9 -0
  32. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  33. package/dist/interfaces/rest/routes/checkout.js +97 -21
  34. package/dist/interfaces/rest/routes/documents.d.ts +10 -0
  35. package/dist/interfaces/rest/routes/documents.d.ts.map +1 -0
  36. package/dist/interfaces/rest/routes/documents.js +40 -0
  37. package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
  38. package/dist/interfaces/rest/routes/inventory.js +13 -0
  39. package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
  40. package/dist/interfaces/rest/routes/orders.js +111 -1
  41. package/dist/interfaces/rest/routes/pricing.d.ts.map +1 -1
  42. package/dist/interfaces/rest/routes/pricing.js +36 -1
  43. package/dist/interfaces/rest/routes/settings.d.ts +5 -0
  44. package/dist/interfaces/rest/routes/settings.d.ts.map +1 -0
  45. package/dist/interfaces/rest/routes/settings.js +50 -0
  46. package/dist/interfaces/rest/routes/shipping.d.ts +5 -0
  47. package/dist/interfaces/rest/routes/shipping.d.ts.map +1 -0
  48. package/dist/interfaces/rest/routes/shipping.js +68 -0
  49. package/dist/interfaces/rest/routes/tax.d.ts +5 -0
  50. package/dist/interfaces/rest/routes/tax.d.ts.map +1 -0
  51. package/dist/interfaces/rest/routes/tax.js +68 -0
  52. package/dist/interfaces/rest/schemas/admin-staff.d.ts +899 -0
  53. package/dist/interfaces/rest/schemas/admin-staff.d.ts.map +1 -0
  54. package/dist/interfaces/rest/schemas/admin-staff.js +98 -0
  55. package/dist/interfaces/rest/schemas/analytics.d.ts +252 -0
  56. package/dist/interfaces/rest/schemas/analytics.d.ts.map +1 -0
  57. package/dist/interfaces/rest/schemas/analytics.js +33 -0
  58. package/dist/interfaces/rest/schemas/carts.d.ts +656 -0
  59. package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
  60. package/dist/interfaces/rest/schemas/carts.js +38 -0
  61. package/dist/interfaces/rest/schemas/catalog.d.ts +1218 -1
  62. package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
  63. package/dist/interfaces/rest/schemas/catalog.js +48 -0
  64. package/dist/interfaces/rest/schemas/checkout.d.ts +2 -0
  65. package/dist/interfaces/rest/schemas/checkout.d.ts.map +1 -1
  66. package/dist/interfaces/rest/schemas/checkout.js +4 -0
  67. package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
  68. package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
  69. package/dist/interfaces/rest/schemas/documents.d.ts +509 -0
  70. package/dist/interfaces/rest/schemas/documents.d.ts.map +1 -0
  71. package/dist/interfaces/rest/schemas/documents.js +65 -0
  72. package/dist/interfaces/rest/schemas/orders.d.ts +3110 -43
  73. package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
  74. package/dist/interfaces/rest/schemas/orders.js +234 -1
  75. package/dist/interfaces/rest/schemas/pricing.d.ts +405 -0
  76. package/dist/interfaces/rest/schemas/pricing.d.ts.map +1 -1
  77. package/dist/interfaces/rest/schemas/pricing.js +70 -0
  78. package/dist/interfaces/rest/schemas/responses.d.ts +190 -0
  79. package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
  80. package/dist/interfaces/rest/schemas/search.d.ts +17 -0
  81. package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
  82. package/dist/interfaces/rest/schemas/settings.d.ts +397 -0
  83. package/dist/interfaces/rest/schemas/settings.d.ts.map +1 -0
  84. package/dist/interfaces/rest/schemas/settings.js +79 -0
  85. package/dist/interfaces/rest/schemas/shipping.d.ts +1093 -0
  86. package/dist/interfaces/rest/schemas/shipping.d.ts.map +1 -0
  87. package/dist/interfaces/rest/schemas/shipping.js +146 -0
  88. package/dist/interfaces/rest/schemas/tax.d.ts +1074 -0
  89. package/dist/interfaces/rest/schemas/tax.d.ts.map +1 -0
  90. package/dist/interfaces/rest/schemas/tax.js +132 -0
  91. package/dist/kernel/database/schema.d.ts +4 -0
  92. package/dist/kernel/database/schema.d.ts.map +1 -1
  93. package/dist/kernel/database/schema.js +8 -0
  94. package/dist/kernel/database/scoped-db.d.ts +2 -1
  95. package/dist/kernel/database/scoped-db.d.ts.map +1 -1
  96. package/dist/kernel/database/scoped-db.js +62 -1
  97. package/dist/kernel/hooks/types.d.ts +1 -1
  98. package/dist/kernel/hooks/types.d.ts.map +1 -1
  99. package/dist/kernel/plugin/manifest.d.ts +26 -0
  100. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  101. package/dist/kernel/plugin/manifest.js +17 -2
  102. package/dist/modules/analytics/drizzle-adapter.d.ts.map +1 -1
  103. package/dist/modules/analytics/drizzle-adapter.js +16 -3
  104. package/dist/modules/analytics/module.d.ts.map +1 -1
  105. package/dist/modules/analytics/module.js +6 -0
  106. package/dist/modules/analytics/reports.d.ts +58 -0
  107. package/dist/modules/analytics/reports.d.ts.map +1 -0
  108. package/dist/modules/analytics/reports.js +249 -0
  109. package/dist/modules/analytics/service.d.ts +10 -0
  110. package/dist/modules/analytics/service.d.ts.map +1 -1
  111. package/dist/modules/analytics/service.js +14 -0
  112. package/dist/modules/cart/repository/index.d.ts +7 -0
  113. package/dist/modules/cart/repository/index.d.ts.map +1 -1
  114. package/dist/modules/cart/repository/index.js +25 -1
  115. package/dist/modules/cart/schema.d.ts +17 -0
  116. package/dist/modules/cart/schema.d.ts.map +1 -1
  117. package/dist/modules/cart/schema.js +2 -0
  118. package/dist/modules/cart/schemas.d.ts +1 -0
  119. package/dist/modules/cart/schemas.d.ts.map +1 -1
  120. package/dist/modules/cart/schemas.js +1 -0
  121. package/dist/modules/cart/service.d.ts +32 -0
  122. package/dist/modules/cart/service.d.ts.map +1 -1
  123. package/dist/modules/cart/service.js +61 -2
  124. package/dist/modules/catalog/entity-service.d.ts +21 -0
  125. package/dist/modules/catalog/entity-service.d.ts.map +1 -1
  126. package/dist/modules/catalog/entity-service.js +166 -5
  127. package/dist/modules/catalog/schema.d.ts +34 -0
  128. package/dist/modules/catalog/schema.d.ts.map +1 -1
  129. package/dist/modules/catalog/schema.js +5 -0
  130. package/dist/modules/catalog/schemas.d.ts +3 -0
  131. package/dist/modules/catalog/schemas.d.ts.map +1 -1
  132. package/dist/modules/catalog/schemas.js +3 -0
  133. package/dist/modules/catalog/service.d.ts +36 -0
  134. package/dist/modules/catalog/service.d.ts.map +1 -1
  135. package/dist/modules/catalog/service.js +6 -0
  136. package/dist/modules/customers/service.d.ts.map +1 -1
  137. package/dist/modules/customers/service.js +6 -0
  138. package/dist/modules/documents/module.d.ts +7 -0
  139. package/dist/modules/documents/module.d.ts.map +1 -0
  140. package/dist/modules/documents/module.js +12 -0
  141. package/dist/modules/documents/pdf.d.ts +25 -0
  142. package/dist/modules/documents/pdf.d.ts.map +1 -0
  143. package/dist/modules/documents/pdf.js +80 -0
  144. package/dist/modules/documents/render.d.ts +32 -0
  145. package/dist/modules/documents/render.d.ts.map +1 -0
  146. package/dist/modules/documents/render.js +190 -0
  147. package/dist/modules/documents/repository/index.d.ts +25 -0
  148. package/dist/modules/documents/repository/index.d.ts.map +1 -0
  149. package/dist/modules/documents/repository/index.js +47 -0
  150. package/dist/modules/documents/schema.d.ts +214 -0
  151. package/dist/modules/documents/schema.d.ts.map +1 -0
  152. package/dist/modules/documents/schema.js +42 -0
  153. package/dist/modules/documents/service.d.ts +51 -0
  154. package/dist/modules/documents/service.d.ts.map +1 -0
  155. package/dist/modules/documents/service.js +119 -0
  156. package/dist/modules/fulfillment/service.d.ts +18 -0
  157. package/dist/modules/fulfillment/service.d.ts.map +1 -1
  158. package/dist/modules/fulfillment/service.js +85 -1
  159. package/dist/modules/orders/repository/index.d.ts +18 -1
  160. package/dist/modules/orders/repository/index.d.ts.map +1 -1
  161. package/dist/modules/orders/repository/index.js +86 -1
  162. package/dist/modules/orders/schema.d.ts +391 -0
  163. package/dist/modules/orders/schema.d.ts.map +1 -1
  164. package/dist/modules/orders/schema.js +56 -1
  165. package/dist/modules/orders/service.d.ts +102 -3
  166. package/dist/modules/orders/service.d.ts.map +1 -1
  167. package/dist/modules/orders/service.js +653 -29
  168. package/dist/modules/orders/stale-order-cleanup.d.ts.map +1 -1
  169. package/dist/modules/orders/stale-order-cleanup.js +13 -1
  170. package/dist/modules/pricing/repository/index.d.ts +5 -0
  171. package/dist/modules/pricing/repository/index.d.ts.map +1 -1
  172. package/dist/modules/pricing/repository/index.js +19 -0
  173. package/dist/modules/pricing/service.d.ts +18 -0
  174. package/dist/modules/pricing/service.d.ts.map +1 -1
  175. package/dist/modules/pricing/service.js +43 -5
  176. package/dist/modules/settings/module.d.ts +6 -0
  177. package/dist/modules/settings/module.d.ts.map +1 -0
  178. package/dist/modules/settings/module.js +11 -0
  179. package/dist/modules/settings/repository/index.d.ts +16 -0
  180. package/dist/modules/settings/repository/index.d.ts.map +1 -0
  181. package/dist/modules/settings/repository/index.js +41 -0
  182. package/dist/modules/settings/schema.d.ts +121 -0
  183. package/dist/modules/settings/schema.d.ts.map +1 -0
  184. package/dist/modules/settings/schema.js +24 -0
  185. package/dist/modules/settings/service.d.ts +26 -0
  186. package/dist/modules/settings/service.d.ts.map +1 -0
  187. package/dist/modules/settings/service.js +51 -0
  188. package/dist/modules/shipping/calculator.d.ts +5 -0
  189. package/dist/modules/shipping/calculator.d.ts.map +1 -1
  190. package/dist/modules/shipping/calculator.js +10 -0
  191. package/dist/modules/shipping/module.d.ts +5 -1
  192. package/dist/modules/shipping/module.d.ts.map +1 -1
  193. package/dist/modules/shipping/module.js +4 -1
  194. package/dist/modules/shipping/repository/index.d.ts +27 -2
  195. package/dist/modules/shipping/repository/index.d.ts.map +1 -1
  196. package/dist/modules/shipping/repository/index.js +105 -1
  197. package/dist/modules/shipping/schema.d.ts +419 -0
  198. package/dist/modules/shipping/schema.d.ts.map +1 -0
  199. package/dist/modules/shipping/schema.js +56 -0
  200. package/dist/modules/shipping/service.d.ts +54 -0
  201. package/dist/modules/shipping/service.d.ts.map +1 -1
  202. package/dist/modules/shipping/service.js +161 -2
  203. package/dist/modules/tax/adapter.d.ts +13 -0
  204. package/dist/modules/tax/adapter.d.ts.map +1 -1
  205. package/dist/modules/tax/module.d.ts +5 -1
  206. package/dist/modules/tax/module.d.ts.map +1 -1
  207. package/dist/modules/tax/module.js +4 -1
  208. package/dist/modules/tax/repository/index.d.ts +38 -2
  209. package/dist/modules/tax/repository/index.d.ts.map +1 -1
  210. package/dist/modules/tax/repository/index.js +138 -1
  211. package/dist/modules/tax/schema.d.ts +355 -0
  212. package/dist/modules/tax/schema.d.ts.map +1 -0
  213. package/dist/modules/tax/schema.js +55 -0
  214. package/dist/modules/tax/service.d.ts +60 -1
  215. package/dist/modules/tax/service.d.ts.map +1 -1
  216. package/dist/modules/tax/service.js +227 -2
  217. package/dist/runtime/kernel-modules.d.ts +15 -2
  218. package/dist/runtime/kernel-modules.d.ts.map +1 -1
  219. package/dist/runtime/kernel-modules.js +4 -0
  220. package/dist/runtime/kernel-types.d.ts +5 -1
  221. package/dist/runtime/kernel-types.d.ts.map +1 -1
  222. package/dist/runtime/kernel-types.js +2 -0
  223. package/dist/runtime/server.js +1 -1
  224. package/dist/test-utils/create-plugin-test-app.d.ts +3 -0
  225. package/dist/test-utils/create-plugin-test-app.d.ts.map +1 -1
  226. package/dist/test-utils/create-plugin-test-app.js +15 -3
  227. package/dist/test-utils/create-test-config.d.ts.map +1 -1
  228. package/dist/test-utils/create-test-config.js +2 -0
  229. package/dist/test-utils/order-test-helpers.d.ts +12 -0
  230. package/dist/test-utils/order-test-helpers.d.ts.map +1 -0
  231. package/dist/test-utils/order-test-helpers.js +18 -0
  232. package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
  233. package/dist/test-utils/rest-api-test-utils.js +7 -0
  234. package/dist/test-utils/test-actors.js +1 -1
  235. package/dist/testing.d.ts +1 -0
  236. package/dist/testing.d.ts.map +1 -1
  237. package/dist/testing.js +1 -0
  238. package/package.json +3 -3
  239. package/src/auth/middleware.ts +26 -7
  240. package/src/auth/setup.ts +11 -4
  241. package/src/config/defaults.ts +7 -0
  242. package/src/config/types.ts +26 -1
  243. package/src/generated/plugin-capabilities.d.ts +1 -0
  244. package/src/generated/plugin-manifest.ts +1 -0
  245. package/src/generated/plugin-repositories.d.ts +1 -0
  246. package/src/hooks/checkout-completion.ts +22 -16
  247. package/src/hooks/checkout.ts +36 -11
  248. package/src/index.ts +1 -0
  249. package/src/interfaces/rest/index.ts +12 -0
  250. package/src/interfaces/rest/routes/admin/staff.ts +260 -0
  251. package/src/interfaces/rest/routes/analytics.ts +33 -0
  252. package/src/interfaces/rest/routes/carts.ts +52 -2
  253. package/src/interfaces/rest/routes/catalog.ts +34 -0
  254. package/src/interfaces/rest/routes/checkout.ts +114 -27
  255. package/src/interfaces/rest/routes/documents.ts +61 -0
  256. package/src/interfaces/rest/routes/inventory.ts +14 -0
  257. package/src/interfaces/rest/routes/orders.ts +148 -1
  258. package/src/interfaces/rest/routes/pricing.ts +44 -1
  259. package/src/interfaces/rest/routes/settings.ts +61 -0
  260. package/src/interfaces/rest/routes/shipping.ts +92 -0
  261. package/src/interfaces/rest/routes/tax.ts +90 -0
  262. package/src/interfaces/rest/schemas/admin-staff.ts +110 -0
  263. package/src/interfaces/rest/schemas/analytics.ts +39 -0
  264. package/src/interfaces/rest/schemas/carts.ts +40 -0
  265. package/src/interfaces/rest/schemas/catalog.ts +53 -0
  266. package/src/interfaces/rest/schemas/checkout.ts +4 -0
  267. package/src/interfaces/rest/schemas/documents.ts +72 -0
  268. package/src/interfaces/rest/schemas/orders.ts +258 -1
  269. package/src/interfaces/rest/schemas/pricing.ts +75 -0
  270. package/src/interfaces/rest/schemas/settings.ts +93 -0
  271. package/src/interfaces/rest/schemas/shipping.ts +164 -0
  272. package/src/interfaces/rest/schemas/tax.ts +148 -0
  273. package/src/kernel/database/schema.ts +12 -0
  274. package/src/kernel/database/scoped-db.ts +70 -1
  275. package/src/kernel/hooks/types.ts +1 -0
  276. package/src/kernel/plugin/manifest.ts +41 -2
  277. package/src/modules/analytics/drizzle-adapter.ts +19 -3
  278. package/src/modules/analytics/module.ts +10 -0
  279. package/src/modules/analytics/reports.ts +311 -0
  280. package/src/modules/analytics/service.ts +23 -0
  281. package/src/modules/cart/repository/index.ts +30 -1
  282. package/src/modules/cart/schema.ts +2 -0
  283. package/src/modules/cart/schemas.ts +1 -0
  284. package/src/modules/cart/service.ts +104 -2
  285. package/src/modules/catalog/entity-service.ts +196 -4
  286. package/src/modules/catalog/schema.ts +5 -0
  287. package/src/modules/catalog/schemas.ts +3 -0
  288. package/src/modules/catalog/service.ts +30 -0
  289. package/src/modules/customers/service.ts +6 -0
  290. package/src/modules/documents/module.ts +19 -0
  291. package/src/modules/documents/pdf.ts +101 -0
  292. package/src/modules/documents/render.ts +231 -0
  293. package/src/modules/documents/repository/index.ts +68 -0
  294. package/src/modules/documents/schema.ts +44 -0
  295. package/src/modules/documents/service.ts +176 -0
  296. package/src/modules/fulfillment/service.ts +139 -1
  297. package/src/modules/orders/repository/index.ts +127 -1
  298. package/src/modules/orders/schema.ts +58 -1
  299. package/src/modules/orders/service.ts +1041 -65
  300. package/src/modules/orders/stale-order-cleanup.ts +18 -4
  301. package/src/modules/pricing/repository/index.ts +34 -0
  302. package/src/modules/pricing/service.ts +76 -6
  303. package/src/modules/settings/module.ts +18 -0
  304. package/src/modules/settings/repository/index.ts +59 -0
  305. package/src/modules/settings/schema.ts +25 -0
  306. package/src/modules/settings/service.ts +82 -0
  307. package/src/modules/shipping/calculator.ts +27 -0
  308. package/src/modules/shipping/module.ts +6 -2
  309. package/src/modules/shipping/repository/index.ts +136 -2
  310. package/src/modules/shipping/schema.ts +58 -0
  311. package/src/modules/shipping/service.ts +260 -1
  312. package/src/modules/tax/adapter.ts +9 -0
  313. package/src/modules/tax/module.ts +6 -2
  314. package/src/modules/tax/repository/index.ts +169 -2
  315. package/src/modules/tax/schema.ts +57 -0
  316. package/src/modules/tax/service.ts +313 -2
  317. package/src/runtime/kernel-modules.ts +4 -0
  318. package/src/runtime/kernel-types.ts +6 -0
  319. package/src/runtime/server.ts +1 -1
  320. package/src/test-utils/create-plugin-test-app.ts +17 -4
  321. package/src/test-utils/create-test-config.ts +2 -0
  322. package/src/test-utils/order-test-helpers.ts +26 -0
  323. package/src/test-utils/rest-api-test-utils.ts +7 -0
  324. package/src/test-utils/test-actors.ts +1 -1
  325. package/src/testing.ts +1 -0
@@ -0,0 +1,148 @@
1
+ import { z, createRoute } from "@hono/zod-openapi";
2
+ import { errorResponses } from "./shared.js";
3
+
4
+ export const CreateTaxRateBodySchema = z.object({
5
+ name: z.string().min(1).openapi({ example: "NY sales tax" }),
6
+ country: z.string().min(1).openapi({ example: "US", description: "ISO 3166-1 alpha-2; \"*\" matches any country" }),
7
+ state: z.string().min(1).optional().openapi({ example: "NY" }),
8
+ rateBps: z.number().int().nonnegative().openapi({ example: 500, description: "Basis points: 500 = 5%" }),
9
+ appliesToShipping: z.boolean().optional(),
10
+ priority: z.number().int().optional(),
11
+ isActive: z.boolean().optional(),
12
+ }).openapi("CreateTaxRateRequest");
13
+
14
+ export const UpdateTaxRateBodySchema = z.object({
15
+ name: z.string().min(1).optional(),
16
+ country: z.string().min(1).optional(),
17
+ state: z.string().min(1).nullable().optional(),
18
+ rateBps: z.number().int().nonnegative().optional(),
19
+ appliesToShipping: z.boolean().optional(),
20
+ priority: z.number().int().optional(),
21
+ isActive: z.boolean().optional(),
22
+ }).openapi("UpdateTaxRateRequest");
23
+
24
+ const IdParam = z.object({
25
+ id: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
26
+ });
27
+
28
+ const DataResponse = z.object({ data: z.any() }).openapi("TaxConfigResponse");
29
+
30
+ export const createTaxRateRoute = createRoute({
31
+ method: "post",
32
+ path: "/rates",
33
+ tags: ["Tax"],
34
+ summary: "Create a tax rate",
35
+ request: {
36
+ body: { content: { "application/json": { schema: CreateTaxRateBodySchema } }, required: true },
37
+ },
38
+ responses: {
39
+ 201: { content: { "application/json": { schema: DataResponse } }, description: "Tax rate created." },
40
+ ...errorResponses,
41
+ },
42
+ });
43
+
44
+ export const listTaxRatesRoute = createRoute({
45
+ method: "get",
46
+ path: "/rates",
47
+ tags: ["Tax"],
48
+ summary: "List tax rates",
49
+ responses: {
50
+ 200: { content: { "application/json": { schema: DataResponse } }, description: "Tax rates" },
51
+ ...errorResponses,
52
+ },
53
+ });
54
+
55
+ export const updateTaxRateRoute = createRoute({
56
+ method: "patch",
57
+ path: "/rates/{id}",
58
+ tags: ["Tax"],
59
+ summary: "Update a tax rate",
60
+ request: {
61
+ params: IdParam,
62
+ body: { content: { "application/json": { schema: UpdateTaxRateBodySchema } }, required: true },
63
+ },
64
+ responses: {
65
+ 200: { content: { "application/json": { schema: DataResponse } }, description: "Tax rate updated." },
66
+ ...errorResponses,
67
+ },
68
+ });
69
+
70
+ export const deleteTaxRateRoute = createRoute({
71
+ method: "delete",
72
+ path: "/rates/{id}",
73
+ tags: ["Tax"],
74
+ summary: "Delete a tax rate",
75
+ request: { params: IdParam },
76
+ responses: {
77
+ 200: { content: { "application/json": { schema: DataResponse } }, description: "Tax rate deleted." },
78
+ ...errorResponses,
79
+ },
80
+ });
81
+
82
+ // ── Product tax classes (issue #57) ─────────────────────────────────────────
83
+
84
+ export const CreateTaxClassBodySchema = z.object({
85
+ name: z.string().min(1).regex(/^[a-z][a-z0-9_-]*$/, "lowercase slug (e.g. standard, zero)"),
86
+ rateBps: z.number().int().nonnegative().openapi({ example: 1800, description: "Basis points: 1800 = 18%" }),
87
+ isDefault: z.boolean().optional().openapi({ description: "Lines with no taxClass use the default class." }),
88
+ isActive: z.boolean().optional(),
89
+ }).openapi("CreateTaxClassRequest");
90
+
91
+ export const UpdateTaxClassBodySchema = z.object({
92
+ name: z.string().min(1).regex(/^[a-z][a-z0-9_-]*$/).optional(),
93
+ rateBps: z.number().int().nonnegative().optional(),
94
+ isDefault: z.boolean().optional(),
95
+ isActive: z.boolean().optional(),
96
+ }).openapi("UpdateTaxClassRequest");
97
+
98
+ const ClassIdParam = z.object({ id: z.uuid() });
99
+
100
+ export const createTaxClassRoute = createRoute({
101
+ method: "post",
102
+ path: "/classes",
103
+ tags: ["Tax"],
104
+ summary: "Create a product tax class",
105
+ request: { body: { content: { "application/json": { schema: CreateTaxClassBodySchema } }, required: true } },
106
+ responses: {
107
+ 201: { content: { "application/json": { schema: DataResponse } }, description: "Tax class created." },
108
+ ...errorResponses,
109
+ },
110
+ });
111
+
112
+ export const listTaxClassesRoute = createRoute({
113
+ method: "get",
114
+ path: "/classes",
115
+ tags: ["Tax"],
116
+ summary: "List product tax classes",
117
+ responses: {
118
+ 200: { content: { "application/json": { schema: DataResponse } }, description: "Tax classes." },
119
+ ...errorResponses,
120
+ },
121
+ });
122
+
123
+ export const updateTaxClassRoute = createRoute({
124
+ method: "patch",
125
+ path: "/classes/{id}",
126
+ tags: ["Tax"],
127
+ summary: "Update a product tax class",
128
+ request: {
129
+ params: ClassIdParam,
130
+ body: { content: { "application/json": { schema: UpdateTaxClassBodySchema } }, required: true },
131
+ },
132
+ responses: {
133
+ 200: { content: { "application/json": { schema: DataResponse } }, description: "Tax class updated." },
134
+ ...errorResponses,
135
+ },
136
+ });
137
+
138
+ export const deleteTaxClassRoute = createRoute({
139
+ method: "delete",
140
+ path: "/classes/{id}",
141
+ tags: ["Tax"],
142
+ summary: "Delete a product tax class",
143
+ request: { params: ClassIdParam },
144
+ responses: {
145
+ 200: { content: { "application/json": { schema: DataResponse } }, description: "Tax class deleted." },
146
+ ...errorResponses,
147
+ },
148
+ });
@@ -43,6 +43,18 @@ export * from "../../modules/webhooks/schema.js";
43
43
  // Fulfillment module
44
44
  export * from "../../modules/fulfillment/schema.js";
45
45
 
46
+ // Shipping module (runtime zones & rates)
47
+ export * from "../../modules/shipping/schema.js";
48
+
49
+ // Tax module (runtime tax rates)
50
+ export * from "../../modules/tax/schema.js";
51
+
52
+ // Settings module (org-scoped runtime settings)
53
+ export * from "../../modules/settings/schema.js";
54
+
55
+ // Documents module (fiscal sequences + issued documents)
56
+ export * from "../../modules/documents/schema.js";
57
+
46
58
  // Jobs (kernel)
47
59
  export * from "../jobs/schema.js";
48
60
 
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Wraps a Drizzle PgDatabase instance so that INSERT operations on
5
5
  * org-scoped tables automatically include the actor's organizationId,
6
- * and SELECT ... FROM org-scoped tables constrain rows to that organization.
6
+ * and SELECT / UPDATE / DELETE against org-scoped tables constrain rows to
7
+ * that organization — including when the caller supplies no WHERE clause.
7
8
  *
8
9
  * Plugin route handlers receive this scoped db via PluginContext.database.db
9
10
  * (organization resolved per operation from AsyncLocalStorage when used from
@@ -30,6 +31,33 @@ function tableHasOrganizationId(table: unknown): boolean {
30
31
  }
31
32
  }
32
33
 
34
+ /**
35
+ * Pre-apply the org predicate to a WHERE-able builder (UPDATE/DELETE) and wrap
36
+ * its `.where()` so a caller-supplied condition is AND-ed with the org filter
37
+ * rather than replacing it. Pre-applying `orgEq` immediately means a builder
38
+ * executed with NO caller `.where()` (e.g. `update(t).set(...)`) is still
39
+ * constrained to the org — it can never touch another tenant's rows.
40
+ */
41
+ function scopeWhereBuilder(
42
+ builder: { where: (c: SQL | undefined) => unknown },
43
+ orgEq: SQL,
44
+ ): unknown {
45
+ const scoped = builder.where(orgEq);
46
+ return new Proxy(scoped as Record<string, unknown>, {
47
+ get(st, sp, sr) {
48
+ const sv = Reflect.get(st, sp, sr);
49
+ if (sp === "where" && typeof sv === "function") {
50
+ return (condition?: unknown, ...wRest: unknown[]) => {
51
+ const c = condition as SQL | undefined;
52
+ const merged = c ? and(orgEq, c) : orgEq;
53
+ return (sv as (...a: unknown[]) => unknown).call(st, merged, ...wRest);
54
+ };
55
+ }
56
+ return typeof sv === "function" ? sv.bind(st) : sv;
57
+ },
58
+ });
59
+ }
60
+
33
61
  export function createScopedDb<TDb>(rawDb: TDb, orgSource: ScopedOrganizationId): TDb {
34
62
  if (!rawDb || typeof rawDb !== "object") return rawDb;
35
63
 
@@ -106,6 +134,47 @@ export function createScopedDb<TDb>(rawDb: TDb, orgSource: ScopedOrganizationId)
106
134
  };
107
135
  }
108
136
 
137
+ if (prop === "update" && typeof value === "function") {
138
+ return (table: PgTable) => {
139
+ const builder = value.call(target, table);
140
+ if (!tableHasOrganizationId(table)) return builder;
141
+ const orgCol = getTableColumns(table).organizationId;
142
+ if (!orgCol) return builder;
143
+ const orgEq = eq(orgCol, resolveOrganizationId(orgSource));
144
+ // The org filter lives after `.set()`, so wrap `.set()` and scope the
145
+ // resulting WHERE-able builder.
146
+ return new Proxy(builder as Record<string, unknown>, {
147
+ get(t, p, r) {
148
+ const v = Reflect.get(t, p, r);
149
+ if (p === "set" && typeof v === "function") {
150
+ return (data: unknown) => {
151
+ const setBuilder = (v as (...a: unknown[]) => unknown).call(t, data);
152
+ return scopeWhereBuilder(
153
+ setBuilder as { where: (c: SQL | undefined) => unknown },
154
+ orgEq,
155
+ );
156
+ };
157
+ }
158
+ return typeof v === "function" ? v.bind(t) : v;
159
+ },
160
+ });
161
+ };
162
+ }
163
+
164
+ if (prop === "delete" && typeof value === "function") {
165
+ return (table: PgTable) => {
166
+ const builder = value.call(target, table);
167
+ if (!tableHasOrganizationId(table)) return builder;
168
+ const orgCol = getTableColumns(table).organizationId;
169
+ if (!orgCol) return builder;
170
+ const orgEq = eq(orgCol, resolveOrganizationId(orgSource));
171
+ return scopeWhereBuilder(
172
+ builder as { where: (c: SQL | undefined) => unknown },
173
+ orgEq,
174
+ );
175
+ };
176
+ }
177
+
109
178
  return typeof value === "function" ? value.bind(target) : value;
110
179
  },
111
180
  }) as TDb;
@@ -11,6 +11,7 @@ export type HookOperation =
11
11
  | "statusChange"
12
12
  | "addItem"
13
13
  | "removeItem"
14
+ | "recover"
14
15
  | "custom";
15
16
 
16
17
  export interface Logger {
@@ -59,6 +59,14 @@ export interface PluginContext {
59
59
  transaction<T>(fn: (tx: PluginDb) => Promise<T>): Promise<T>;
60
60
  };
61
61
  logger: PluginLogger;
62
+ /**
63
+ * The Better Auth instance (issue #51) — lets plugins mint/revoke
64
+ * credentials (e.g. per-shift API keys from a POS PIN login). Present when
65
+ * routes are mounted by createServer; may be absent in bare-kernel setups,
66
+ * so plugins must degrade gracefully. Typed loosely to avoid coupling every
67
+ * plugin to Better Auth's generics — cast to the narrow surface you use.
68
+ */
69
+ auth?: unknown;
62
70
  }
63
71
 
64
72
  const UNSCOPED_WARN_COOLDOWN_MS = 60_000;
@@ -139,6 +147,21 @@ export interface CommercePluginManifest {
139
147
  hooks?: () => PluginHookRegistration[];
140
148
  routes?: (ctx: PluginContext) => PluginRouteRegistration[];
141
149
  analyticsModels?: () => unknown[];
150
+ /**
151
+ * Named API-key scopes this plugin mints credentials under (issue #51),
152
+ * merged into `config.auth.apiKeyScopes`. User-defined scopes with the
153
+ * same name win.
154
+ */
155
+ apiKeyScopes?: () => Record<string, {
156
+ prefix?: string;
157
+ description?: string;
158
+ permissions?: Record<string, string[]>;
159
+ /** Expiry bounds in DAYS (fractions allowed — 1/24 = one hour). */
160
+ keyExpiration?: { minExpiresIn?: number; maxExpiresIn?: number };
161
+ /** Better Auth ownership model for keys minted under this scope. */
162
+ references?: "user" | "organization";
163
+ enableMetadata?: boolean;
164
+ }>;
142
165
  }
143
166
 
144
167
  // ─── Plugin Dependency Tracking ──────────────────────────────────────
@@ -193,6 +216,21 @@ export function defineCommercePlugin(
193
216
  };
194
217
  }
195
218
 
219
+ // 0. API-key scopes — merge into auth.apiKeyScopes (user config wins)
220
+ if (manifest.apiKeyScopes) {
221
+ const scopes = manifest.apiKeyScopes();
222
+ result = {
223
+ ...result,
224
+ auth: {
225
+ ...(result.auth ?? {}),
226
+ apiKeyScopes: {
227
+ ...scopes,
228
+ ...(result.auth?.apiKeyScopes ?? {}),
229
+ },
230
+ },
231
+ } as CommerceConfig;
232
+ }
233
+
196
234
  // 1. Schema — push into customSchemas for kernel to register
197
235
  if (manifest.schema) {
198
236
  const schemas = manifest.schema();
@@ -220,8 +258,8 @@ export function defineCommercePlugin(
220
258
  const pluginRoutes = manifest.routes;
221
259
  result = {
222
260
  ...result,
223
- routes: (app: Hono, kernel: Kernel) => {
224
- existingRoutes?.(app, kernel);
261
+ routes: (app: Hono, kernel: Kernel, auth?: unknown) => {
262
+ existingRoutes?.(app, kernel, auth as never);
225
263
  const k = kernel as {
226
264
  config: CommerceConfig;
227
265
  services: Record<string, unknown>;
@@ -240,6 +278,7 @@ export function defineCommercePlugin(
240
278
  k.logger,
241
279
  ),
242
280
  logger: k.logger,
281
+ ...(auth !== undefined ? { auth } : {}),
243
282
  });
244
283
  for (const route of regs) {
245
284
  // ── Error boundary: wrap handler with plugin context ──
@@ -216,6 +216,17 @@ export class DrizzleAnalyticsAdapter implements AnalyticsAdapter {
216
216
  }
217
217
  }
218
218
 
219
+ // Validate that requested time dimensions exist in the cube
220
+ for (const td of params.timeDimensions ?? []) {
221
+ const shortName = td.dimension.split(".")[1];
222
+ if (shortName && !cube.dimensions[shortName]) {
223
+ const available = Object.keys(cube.dimensions).map((d) => `${cubeName}.${d}`).join(", ");
224
+ return Err(new CommerceValidationError(
225
+ `Unknown time dimension: "${td.dimension}". Available dimensions for ${cubeName}: ${available}`,
226
+ ));
227
+ }
228
+ }
229
+
219
230
  try {
220
231
  const rows = await this.executeQuery(cube, params, scope);
221
232
  return Ok({
@@ -330,14 +341,17 @@ export class DrizzleAnalyticsAdapter implements AnalyticsAdapter {
330
341
  const shortName = dim.split(".")[1]!;
331
342
  const dimDef = cube.dimensions[shortName];
332
343
  if (!dimDef) continue;
333
- selectParts.push(sql.raw(`${dimDef.sql} AS "${dim}"`));
344
+ const alias = `${cube.name}.${shortName}`;
345
+ selectParts.push(sql.raw(`${dimDef.sql} AS "${alias}"`));
334
346
  groupByParts.push(sql.raw(dimDef.sql));
335
347
  }
336
348
 
337
349
  // Time dimensions → SELECT + GROUP BY + WHERE (dateRange)
338
350
  for (const td of params.timeDimensions ?? []) {
351
+ const shortName = td.dimension.split(".")[1]!;
339
352
  const selectExpr = compileTimeDimensionSelect(cube, td);
340
- selectParts.push(sql`${selectExpr} AS ${sql.raw(`"${td.dimension}"`)}`);
353
+ const alias = `${cube.name}.${shortName}`;
354
+ selectParts.push(sql`${selectExpr} AS ${sql.raw(`"${alias}"`)}`);
341
355
  groupByParts.push(selectExpr);
342
356
 
343
357
  // Date range filter
@@ -357,7 +371,9 @@ export class DrizzleAnalyticsAdapter implements AnalyticsAdapter {
357
371
 
358
372
  // Measures → SELECT
359
373
  for (const measure of params.measures) {
360
- selectParts.push(sql`${compileMeasure(cube, measure)} AS ${sql.raw(`"${measure}"`)}`);
374
+ const shortName = measure.split(".")[1]!;
375
+ const alias = `${cube.name}.${shortName}`;
376
+ selectParts.push(sql`${compileMeasure(cube, measure)} AS ${sql.raw(`"${alias}"`)}`);
361
377
  }
362
378
 
363
379
  // If no select parts (shouldn't happen with validation), bail
@@ -1,8 +1,10 @@
1
1
  import type { CommerceConfig } from "../../config/types.js";
2
2
  import type { DrizzleDatabase } from "../../kernel/database/drizzle-db.js";
3
3
  import { defineModule } from "../../kernel/module/index.js";
4
+ import type { SettingsService } from "../settings/service.js";
4
5
  import { DrizzleAnalyticsAdapter } from "./drizzle-adapter.js";
5
6
  import { BUILTIN_ANALYTICS_MODELS } from "./models.js";
7
+ import { RetailReportsEngine } from "./reports.js";
6
8
  import { AnalyticsService } from "./service.js";
7
9
 
8
10
  export const analyticsModule = defineModule<
@@ -17,9 +19,17 @@ export const analyticsModule = defineModule<
17
19
  for (const model of BUILTIN_ANALYTICS_MODELS) {
18
20
  adapter.registerModel(model);
19
21
  }
22
+ // Settings is resolved lazily from the shared service container — the
23
+ // settings module may instantiate after analytics.
24
+ const services = deps.services as Record<string, unknown>;
25
+ const reports = new RetailReportsEngine(
26
+ deps.db.db as DrizzleDatabase,
27
+ (orgId, group) => (services.settings as SettingsService).read(orgId, group),
28
+ );
20
29
  return new AnalyticsService({
21
30
  adapter,
22
31
  config: deps.config as CommerceConfig,
32
+ reports,
23
33
  });
24
34
  },
25
35
  });