@stacksjs/defaults 0.70.57 → 0.70.59

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 (575) hide show
  1. package/app/Actions/AI/AskAction.ts +40 -0
  2. package/app/Actions/AI/SummaryAction.ts +40 -0
  3. package/app/Actions/Auth/AuthUserAction.ts +13 -0
  4. package/app/Actions/Auth/CreateTokenAction.ts +64 -0
  5. package/app/Actions/Auth/DisableTwoFactorAction.ts +37 -0
  6. package/app/Actions/Auth/EnableTwoFactorAction.ts +37 -0
  7. package/app/Actions/Auth/GenerateAuthenticationAction.ts +51 -0
  8. package/app/Actions/Auth/GenerateRegistrationAction.ts +53 -0
  9. package/app/Actions/Auth/GenerateTwoFactorSecretAction.ts +26 -0
  10. package/app/Actions/Auth/ListTokensAction.ts +30 -0
  11. package/app/Actions/Auth/LoginAction.ts +73 -0
  12. package/app/Actions/Auth/LogoutAction.ts +16 -0
  13. package/app/Actions/Auth/LogoutAllAction.ts +28 -0
  14. package/app/Actions/Auth/RefreshTokenAction.ts +39 -0
  15. package/app/Actions/Auth/RegisterAction.ts +57 -0
  16. package/app/Actions/Auth/ResendVerificationAction.ts +24 -0
  17. package/app/Actions/Auth/RevokeTokenAction.ts +43 -0
  18. package/app/Actions/Auth/TestAbilitiesAction.ts +61 -0
  19. package/app/Actions/Auth/VerifyAuthenticationAction.ts +94 -0
  20. package/app/Actions/Auth/VerifyEmailAction.ts +25 -0
  21. package/app/Actions/Auth/VerifyRegistrationAction.ts +59 -0
  22. package/app/Actions/Auth/VerifyTwoFactorLoginAction.ts +57 -0
  23. package/app/Actions/Billable/CheckoutAction.ts +25 -0
  24. package/app/Actions/Buddy/BuddyBrowseAction.ts +34 -0
  25. package/app/Actions/Buddy/BuddyCancelAction.ts +32 -0
  26. package/app/Actions/Buddy/BuddyCommitAction.ts +25 -0
  27. package/app/Actions/Buddy/BuddyGitHubConnectAction.ts +40 -0
  28. package/app/Actions/Buddy/BuddyGitHubDisconnectAction.ts +19 -0
  29. package/app/Actions/Buddy/BuddyProcessAction.ts +65 -0
  30. package/app/Actions/Buddy/BuddyProcessStreamAction.ts +128 -0
  31. package/app/Actions/Buddy/BuddyPushAction.ts +21 -0
  32. package/app/Actions/Buddy/BuddyRepoOpenAction.ts +44 -0
  33. package/app/Actions/Buddy/BuddyRepoValidateAction.ts +35 -0
  34. package/app/Actions/Buddy/BuddySettingsAction.ts +21 -0
  35. package/app/Actions/Buddy/BuddySettingsUpdateAction.ts +46 -0
  36. package/app/Actions/Buddy/BuddyStateAction.ts +28 -0
  37. package/app/Actions/Buddy/BuddyTitleAction.ts +49 -0
  38. package/app/Actions/Buddy/CommandsAction.ts +802 -0
  39. package/app/Actions/Buddy/JobCancelAction.ts +32 -0
  40. package/app/Actions/Buddy/JobRetryAction.ts +49 -0
  41. package/app/Actions/Buddy/JobsListAction.ts +141 -0
  42. package/app/Actions/Buddy/ScheduleListAction.ts +52 -0
  43. package/app/Actions/Buddy/VersionsAction.ts +12 -0
  44. package/app/Actions/Cms/AuthorDestroyAction.ts +21 -0
  45. package/app/Actions/Cms/AuthorIndexAction.ts +14 -0
  46. package/app/Actions/Cms/AuthorShowAction.ts +19 -0
  47. package/app/Actions/Cms/AuthorStoreAction.ts +20 -0
  48. package/app/Actions/Cms/AuthorUpdateAction.ts +24 -0
  49. package/app/Actions/Cms/CategorizableDestroyAction.ts +16 -0
  50. package/app/Actions/Cms/CategorizableIndexAction.ts +14 -0
  51. package/app/Actions/Cms/CategorizableShowAction.ts +16 -0
  52. package/app/Actions/Cms/CategorizableStoreAction.ts +42 -0
  53. package/app/Actions/Cms/CategorizableUpdateAction.ts +38 -0
  54. package/app/Actions/Cms/CommentDestroyAction.ts +16 -0
  55. package/app/Actions/Cms/CommentIndexAction.ts +17 -0
  56. package/app/Actions/Cms/CommentShowAction.ts +16 -0
  57. package/app/Actions/Cms/CommentStoreAction.ts +39 -0
  58. package/app/Actions/Cms/CommentUpdateAction.ts +37 -0
  59. package/app/Actions/Cms/PageDestroyAction.ts +16 -0
  60. package/app/Actions/Cms/PageIndexAction.ts +14 -0
  61. package/app/Actions/Cms/PageStoreAction.ts +31 -0
  62. package/app/Actions/Cms/PageUpdateAction.ts +27 -0
  63. package/app/Actions/Cms/PostDestroyAction.ts +17 -0
  64. package/app/Actions/Cms/PostIndexAction.ts +14 -0
  65. package/app/Actions/Cms/PostShowAction.ts +16 -0
  66. package/app/Actions/Cms/PostStoreAction.ts +37 -0
  67. package/app/Actions/Cms/PostUpdateAction.ts +32 -0
  68. package/app/Actions/Cms/PostViewsUpdateAction.ts +34 -0
  69. package/app/Actions/Cms/RssFeedAction.ts +59 -0
  70. package/app/Actions/Cms/SitemapAction.ts +60 -0
  71. package/app/Actions/Cms/TaggableDestroyAction.ts +16 -0
  72. package/app/Actions/Cms/TaggableIndexAction.ts +14 -0
  73. package/app/Actions/Cms/TaggableShowAction.ts +16 -0
  74. package/app/Actions/Cms/TaggableStoreAction.ts +36 -0
  75. package/app/Actions/Cms/TaggableUpdateAction.ts +37 -0
  76. package/app/Actions/Commerce/CouponDestroyAction.ts +18 -0
  77. package/app/Actions/Commerce/CouponIndexAction.ts +16 -0
  78. package/app/Actions/Commerce/CouponShowAction.ts +18 -0
  79. package/app/Actions/Commerce/CouponStoreAction.ts +21 -0
  80. package/app/Actions/Commerce/CouponUpdateAction.ts +31 -0
  81. package/app/Actions/Commerce/CustomerDestroyAction.ts +16 -0
  82. package/app/Actions/Commerce/CustomerIndexAction.ts +15 -0
  83. package/app/Actions/Commerce/CustomerShowAction.ts +18 -0
  84. package/app/Actions/Commerce/CustomerStoreAction.ts +29 -0
  85. package/app/Actions/Commerce/CustomerUpdateAction.ts +27 -0
  86. package/app/Actions/Commerce/DriverDestroyAction.ts +18 -0
  87. package/app/Actions/Commerce/GiftCardDestroyAction.ts +18 -0
  88. package/app/Actions/Commerce/GiftCardIndexAction.ts +16 -0
  89. package/app/Actions/Commerce/GiftCardShowAction.ts +18 -0
  90. package/app/Actions/Commerce/GiftCardStatsAction.ts +30 -0
  91. package/app/Actions/Commerce/GiftCardStoreAction.ts +35 -0
  92. package/app/Actions/Commerce/GiftCardUpdateAction.ts +26 -0
  93. package/app/Actions/Commerce/GiftCardUpdateBalanceAction.ts +36 -0
  94. package/app/Actions/Commerce/OrderDestroyAction.ts +18 -0
  95. package/app/Actions/Commerce/OrderExportAction.ts +15 -0
  96. package/app/Actions/Commerce/OrderIndexAction.ts +15 -0
  97. package/app/Actions/Commerce/OrderShowAction.ts +18 -0
  98. package/app/Actions/Commerce/OrderStoreAction.ts +32 -0
  99. package/app/Actions/Commerce/OrderUpdateAction.ts +34 -0
  100. package/app/Actions/Commerce/PaymentDestroyAction.ts +16 -0
  101. package/app/Actions/Commerce/PaymentFetchStatsAction.ts +31 -0
  102. package/app/Actions/Commerce/PaymentIndexAction.ts +15 -0
  103. package/app/Actions/Commerce/PaymentMonthlyTrendsAction.ts +21 -0
  104. package/app/Actions/Commerce/PaymentShowAction.ts +17 -0
  105. package/app/Actions/Commerce/PaymentStoreAction.ts +24 -0
  106. package/app/Actions/Commerce/PaymentUpdateAction.ts +35 -0
  107. package/app/Actions/Commerce/PrintDeviceDestroyAction.ts +18 -0
  108. package/app/Actions/Commerce/PrintDeviceIndexAction.ts +14 -0
  109. package/app/Actions/Commerce/PrintDeviceShowAction.ts +17 -0
  110. package/app/Actions/Commerce/PrintDeviceStoreAction.ts +27 -0
  111. package/app/Actions/Commerce/PrintDeviceUpdateAction.ts +27 -0
  112. package/app/Actions/Commerce/Product/ManufacturerDestroyAction.ts +20 -0
  113. package/app/Actions/Commerce/Product/ManufacturerIndexAction.ts +16 -0
  114. package/app/Actions/Commerce/Product/ManufacturerShowAction.ts +18 -0
  115. package/app/Actions/Commerce/Product/ManufacturerStoreAction.ts +14 -0
  116. package/app/Actions/Commerce/Product/ProductCategoryIndexAction.ts +16 -0
  117. package/app/Actions/Commerce/Product/ProductCategoryStoreAction.ts +16 -0
  118. package/app/Actions/Commerce/Product/ProductDestroyAction.ts +16 -0
  119. package/app/Actions/Commerce/Product/ProductIndexAction.ts +14 -0
  120. package/app/Actions/Commerce/Product/ProductManufacturerDestroyAction.ts +18 -0
  121. package/app/Actions/Commerce/Product/ProductManufacturerIndexAction.ts +14 -0
  122. package/app/Actions/Commerce/Product/ProductManufacturerShowAction.ts +16 -0
  123. package/app/Actions/Commerce/Product/ProductManufacturerStoreAction.ts +14 -0
  124. package/app/Actions/Commerce/Product/ProductManufacturerUpdateAction.ts +18 -0
  125. package/app/Actions/Commerce/Product/ProductShowAction.ts +18 -0
  126. package/app/Actions/Commerce/Product/ProductStoreAction.ts +17 -0
  127. package/app/Actions/Commerce/Product/ProductUnitDestroyAction.ts +18 -0
  128. package/app/Actions/Commerce/Product/ProductUnitIndexAction.ts +14 -0
  129. package/app/Actions/Commerce/Product/ProductUnitShowAction.ts +18 -0
  130. package/app/Actions/Commerce/Product/ProductUnitStoreAction.ts +15 -0
  131. package/app/Actions/Commerce/Product/ProductUpdateAction.ts +17 -0
  132. package/app/Actions/Commerce/Product/ProductVariantDestroyAction.ts +18 -0
  133. package/app/Actions/Commerce/Product/ProductVariantIndexAction.ts +14 -0
  134. package/app/Actions/Commerce/Product/ProductVariantShowAction.ts +17 -0
  135. package/app/Actions/Commerce/Product/ProductVariantStoreAction.ts +14 -0
  136. package/app/Actions/Commerce/Product/ProductVariantUpdateAction.ts +16 -0
  137. package/app/Actions/Commerce/ReceiptDestroyAction.ts +18 -0
  138. package/app/Actions/Commerce/ReceiptIndexAction.ts +14 -0
  139. package/app/Actions/Commerce/ReceiptShowAction.ts +18 -0
  140. package/app/Actions/Commerce/ReceiptStoreAction.ts +28 -0
  141. package/app/Actions/Commerce/ReceiptUpdateAction.ts +30 -0
  142. package/app/Actions/Commerce/ReviewIndexAction.ts +14 -0
  143. package/app/Actions/Commerce/ReviewShowAction.ts +16 -0
  144. package/app/Actions/Commerce/ReviewStoreAction.ts +26 -0
  145. package/app/Actions/Commerce/ReviewUpdateAction.ts +28 -0
  146. package/app/Actions/Commerce/Shipping/DeliveryRouteDestroyAction.ts +18 -0
  147. package/app/Actions/Commerce/Shipping/DeliveryRouteIndexAction.ts +16 -0
  148. package/app/Actions/Commerce/Shipping/DeliveryRouteShowAction.ts +18 -0
  149. package/app/Actions/Commerce/Shipping/DeliveryRouteStoreAction.ts +16 -0
  150. package/app/Actions/Commerce/Shipping/DeliveryRouteUpdateAction.ts +18 -0
  151. package/app/Actions/Commerce/Shipping/DigitalDeliveryDestroyAction.ts +18 -0
  152. package/app/Actions/Commerce/Shipping/DigitalDeliveryIndexAction.ts +16 -0
  153. package/app/Actions/Commerce/Shipping/DigitalDeliveryShowAction.ts +18 -0
  154. package/app/Actions/Commerce/Shipping/DigitalDeliveryStoreAction.ts +18 -0
  155. package/app/Actions/Commerce/Shipping/DigitalDeliveryUpdateAction.ts +18 -0
  156. package/app/Actions/Commerce/Shipping/DriverIndexAction.ts +16 -0
  157. package/app/Actions/Commerce/Shipping/DriverShowAction.ts +18 -0
  158. package/app/Actions/Commerce/Shipping/DriverStoreAction.ts +16 -0
  159. package/app/Actions/Commerce/Shipping/DriverUpdateAction.ts +18 -0
  160. package/app/Actions/Commerce/Shipping/LicenseKeyDestroyAction.ts +20 -0
  161. package/app/Actions/Commerce/Shipping/LicenseKeyIndexAction.ts +16 -0
  162. package/app/Actions/Commerce/Shipping/LicenseKeyShowAction.ts +18 -0
  163. package/app/Actions/Commerce/Shipping/LicenseKeyStoreAction.ts +18 -0
  164. package/app/Actions/Commerce/Shipping/LicenseKeyUpdateAction.ts +18 -0
  165. package/app/Actions/Commerce/Shipping/ShippingMethodDestroyAction.ts +16 -0
  166. package/app/Actions/Commerce/Shipping/ShippingMethodIndexAction.ts +14 -0
  167. package/app/Actions/Commerce/Shipping/ShippingMethodShowAction.ts +16 -0
  168. package/app/Actions/Commerce/Shipping/ShippingMethodStoreAction.ts +16 -0
  169. package/app/Actions/Commerce/Shipping/ShippingMethodUpdateAction.ts +15 -0
  170. package/app/Actions/Commerce/Shipping/ShippingRateDestroyAction.ts +16 -0
  171. package/app/Actions/Commerce/Shipping/ShippingRateIndexAction.ts +14 -0
  172. package/app/Actions/Commerce/Shipping/ShippingRateShowAction.ts +16 -0
  173. package/app/Actions/Commerce/Shipping/ShippingRateStoreAction.ts +16 -0
  174. package/app/Actions/Commerce/Shipping/ShippingRateUpdateAction.ts +17 -0
  175. package/app/Actions/Commerce/Shipping/ShippingZoneDestroyAction.ts +16 -0
  176. package/app/Actions/Commerce/Shipping/ShippingZoneIndexAction.ts +14 -0
  177. package/app/Actions/Commerce/Shipping/ShippingZoneShowAction.ts +16 -0
  178. package/app/Actions/Commerce/Shipping/ShippingZoneStoreAction.ts +16 -0
  179. package/app/Actions/Commerce/Shipping/ShippingZoneUpdateAction.ts +15 -0
  180. package/app/Actions/Commerce/TaxRateDestroyAction.ts +16 -0
  181. package/app/Actions/Commerce/TaxRateIndexAction.ts +14 -0
  182. package/app/Actions/Commerce/TaxRateShowAction.ts +17 -0
  183. package/app/Actions/Commerce/TaxRateStoreAction.ts +24 -0
  184. package/app/Actions/Commerce/TaxRateUpdateAction.ts +24 -0
  185. package/app/Actions/Commerce/WaitlistProductAnalyticsAction.ts +29 -0
  186. package/app/Actions/Commerce/WaitlistProductDestroyAction.ts +16 -0
  187. package/app/Actions/Commerce/WaitlistProductIndexAction.ts +14 -0
  188. package/app/Actions/Commerce/WaitlistProductQuantityDistributionAction.ts +32 -0
  189. package/app/Actions/Commerce/WaitlistProductShowAction.ts +16 -0
  190. package/app/Actions/Commerce/WaitlistProductStatusAction.ts +37 -0
  191. package/app/Actions/Commerce/WaitlistProductStoreAction.ts +27 -0
  192. package/app/Actions/Commerce/WaitlistProductTimeSeriesAction.ts +25 -0
  193. package/app/Actions/Commerce/WaitlistProductUpdateAction.ts +29 -0
  194. package/app/Actions/Commerce/WaitlistRestaurantDashboardAction.ts +29 -0
  195. package/app/Actions/Commerce/WaitlistRestaurantDestroyAction.ts +16 -0
  196. package/app/Actions/Commerce/WaitlistRestaurantIndexAction.ts +14 -0
  197. package/app/Actions/Commerce/WaitlistRestaurantShowAction.ts +16 -0
  198. package/app/Actions/Commerce/WaitlistRestaurantStoreAction.ts +31 -0
  199. package/app/Actions/Commerce/WaitlistRestaurantUpdateAction.ts +33 -0
  200. package/app/Actions/ContactAction.ts +72 -0
  201. package/app/Actions/Dashboard/Actions/CreateAction.ts +11 -0
  202. package/app/Actions/Dashboard/Actions/GetActionCount.ts +12 -0
  203. package/app/Actions/Dashboard/Actions/GetActions.ts +19 -0
  204. package/app/Actions/Dashboard/Analytics/BlogAnalyticsAction.ts +58 -0
  205. package/app/Actions/Dashboard/Analytics/BrowserAnalyticsAction.ts +42 -0
  206. package/app/Actions/Dashboard/Analytics/CommerceAnalyticsAction.ts +64 -0
  207. package/app/Actions/Dashboard/Analytics/CountryAnalyticsAction.ts +41 -0
  208. package/app/Actions/Dashboard/Analytics/DeviceAnalyticsAction.ts +58 -0
  209. package/app/Actions/Dashboard/Analytics/EventAnalyticsAction.ts +90 -0
  210. package/app/Actions/Dashboard/Analytics/MarketingAnalyticsAction.ts +76 -0
  211. package/app/Actions/Dashboard/Analytics/PageAnalyticsAction.ts +45 -0
  212. package/app/Actions/Dashboard/Analytics/ReferrerAnalyticsAction.ts +72 -0
  213. package/app/Actions/Dashboard/Analytics/SalesAnalyticsAction.ts +73 -0
  214. package/app/Actions/Dashboard/Analytics/WebAnalyticsAction.ts +114 -0
  215. package/app/Actions/Dashboard/Auth/MeAction.ts +84 -0
  216. package/app/Actions/Dashboard/BuddyDashboardAction.ts +34 -0
  217. package/app/Actions/Dashboard/Ci/RepoRunJobsAction.ts +60 -0
  218. package/app/Actions/Dashboard/Ci/RepoRunsAction.ts +67 -0
  219. package/app/Actions/Dashboard/Ci/RunnerHistoryAction.ts +58 -0
  220. package/app/Actions/Dashboard/Ci/StatusAction.ts +73 -0
  221. package/app/Actions/Dashboard/Ci/failure-notifier.ts +214 -0
  222. package/app/Actions/Dashboard/Ci/runner-pressure-monitor.ts +259 -0
  223. package/app/Actions/Dashboard/Cloud/CloudIndexAction.ts +61 -0
  224. package/app/Actions/Dashboard/Commands/CreateCommand.ts +11 -0
  225. package/app/Actions/Dashboard/Commands/GetAverageCommandTime.ts +12 -0
  226. package/app/Actions/Dashboard/Commands/GetCommandCount.ts +12 -0
  227. package/app/Actions/Dashboard/Commands/GetCommandSuccessRate.ts +12 -0
  228. package/app/Actions/Dashboard/Commands/GetCommands.ts +12 -0
  229. package/app/Actions/Dashboard/Commerce/CommerceCouponsAction.ts +48 -0
  230. package/app/Actions/Dashboard/Commerce/CommerceCustomersAction.ts +48 -0
  231. package/app/Actions/Dashboard/Commerce/CommerceDashboardAction.ts +98 -0
  232. package/app/Actions/Dashboard/Commerce/CommerceDeliveryAction.ts +65 -0
  233. package/app/Actions/Dashboard/Commerce/CommerceGiftCardsAction.ts +48 -0
  234. package/app/Actions/Dashboard/Commerce/CommerceOrdersAction.ts +51 -0
  235. package/app/Actions/Dashboard/Commerce/CommercePaymentsAction.ts +59 -0
  236. package/app/Actions/Dashboard/Commerce/CommerceProductsAction.ts +50 -0
  237. package/app/Actions/Dashboard/Commerce/CommerceTaxesAction.ts +46 -0
  238. package/app/Actions/Dashboard/Commerce/PosIndexAction.ts +57 -0
  239. package/app/Actions/Dashboard/Commerce/ReviewIndexAction.ts +51 -0
  240. package/app/Actions/Dashboard/Content/AuthorIndexAction.ts +51 -0
  241. package/app/Actions/Dashboard/Content/CategoryIndexAction.ts +27 -0
  242. package/app/Actions/Dashboard/Content/CommentIndexAction.ts +41 -0
  243. package/app/Actions/Dashboard/Content/ContentDashboardAction.ts +54 -0
  244. package/app/Actions/Dashboard/Content/FileIndexAction.ts +24 -0
  245. package/app/Actions/Dashboard/Content/PageIndexAction.ts +25 -0
  246. package/app/Actions/Dashboard/Content/PostIndexAction.ts +102 -0
  247. package/app/Actions/Dashboard/Content/SeoIndexAction.ts +17 -0
  248. package/app/Actions/Dashboard/Content/TagIndexAction.ts +23 -0
  249. package/app/Actions/Dashboard/CreateDnsRecords.ts +11 -0
  250. package/app/Actions/Dashboard/CreateMailbox.ts +11 -0
  251. package/app/Actions/Dashboard/DashboardActivityAction.ts +58 -0
  252. package/app/Actions/Dashboard/DashboardHealthAction.ts +52 -0
  253. package/app/Actions/Dashboard/DashboardHomeAction.ts +83 -0
  254. package/app/Actions/Dashboard/DashboardStatsAction.ts +48 -0
  255. package/app/Actions/Dashboard/Data/AccessTokenIndexAction.ts +65 -0
  256. package/app/Actions/Dashboard/Data/ActivityIndexAction.ts +28 -0
  257. package/app/Actions/Dashboard/Data/DataDashboardAction.ts +67 -0
  258. package/app/Actions/Dashboard/Data/SubscriberIndexAction.ts +48 -0
  259. package/app/Actions/Dashboard/Data/TeamIndexAction.ts +43 -0
  260. package/app/Actions/Dashboard/Data/UserIndexAction.ts +48 -0
  261. package/app/Actions/Dashboard/Deployments/CreateDeployment.ts +11 -0
  262. package/app/Actions/Dashboard/Deployments/GetAverageDeploymentTime.ts +15 -0
  263. package/app/Actions/Dashboard/Deployments/GetDeployScript.ts +12 -0
  264. package/app/Actions/Dashboard/Deployments/GetDeploymentCount.ts +12 -0
  265. package/app/Actions/Dashboard/Deployments/GetDeploymentLiveTerminalOutput.ts +12 -0
  266. package/app/Actions/Dashboard/Deployments/GetDeployments.ts +20 -0
  267. package/app/Actions/Dashboard/Deployments/GetRecentDeployments.ts +12 -0
  268. package/app/Actions/Dashboard/Deployments/UpdateDeployScript.ts +11 -0
  269. package/app/Actions/Dashboard/GetDnsRecords.ts +12 -0
  270. package/app/Actions/Dashboard/GetEmailInboxes.ts +12 -0
  271. package/app/Actions/Dashboard/GetProjects.ts +13 -0
  272. package/app/Actions/Dashboard/GetRecentCommits.ts +13 -0
  273. package/app/Actions/Dashboard/Inbox/InboxIndexAction.ts +144 -0
  274. package/app/Actions/Dashboard/Inbox/InboxShowAction.ts +89 -0
  275. package/app/Actions/Dashboard/Infrastructure/CommandIndexAction.ts +18 -0
  276. package/app/Actions/Dashboard/Infrastructure/DnsIndexAction.ts +101 -0
  277. package/app/Actions/Dashboard/Infrastructure/EnvironmentIndexAction.ts +67 -0
  278. package/app/Actions/Dashboard/Infrastructure/InsightsAction.ts +29 -0
  279. package/app/Actions/Dashboard/Infrastructure/LogIndexAction.ts +50 -0
  280. package/app/Actions/Dashboard/Infrastructure/MailboxIndexAction.ts +85 -0
  281. package/app/Actions/Dashboard/Infrastructure/PermissionIndexAction.ts +54 -0
  282. package/app/Actions/Dashboard/Infrastructure/RequestIndexAction.ts +44 -0
  283. package/app/Actions/Dashboard/Infrastructure/ServerIndexAction.ts +101 -0
  284. package/app/Actions/Dashboard/Jobs/CreateJob.ts +11 -0
  285. package/app/Actions/Dashboard/Jobs/GetAverageJobTime.ts +12 -0
  286. package/app/Actions/Dashboard/Jobs/GetJobHistory.ts +12 -0
  287. package/app/Actions/Dashboard/Jobs/GetJobs.ts +11 -0
  288. package/app/Actions/Dashboard/Jobs/GetJobsPerMinute.ts +12 -0
  289. package/app/Actions/Dashboard/Jobs/JobIndexAction.ts +136 -0
  290. package/app/Actions/Dashboard/Jobs/JobRetryAction.ts +23 -0
  291. package/app/Actions/Dashboard/Jobs/JobStatsAction.ts +49 -0
  292. package/app/Actions/Dashboard/Kanban/BoardDestroyAction.ts +84 -0
  293. package/app/Actions/Dashboard/Kanban/BoardShowAction.ts +215 -0
  294. package/app/Actions/Dashboard/Kanban/BoardStoreAction.ts +98 -0
  295. package/app/Actions/Dashboard/Kanban/BoardUpdateAction.ts +96 -0
  296. package/app/Actions/Dashboard/Kanban/BoardsIndexAction.ts +81 -0
  297. package/app/Actions/Dashboard/Kanban/BoardsReorderAction.ts +80 -0
  298. package/app/Actions/Dashboard/Kanban/CardAssigneesSyncAction.ts +103 -0
  299. package/app/Actions/Dashboard/Kanban/CardCommentDestroyAction.ts +33 -0
  300. package/app/Actions/Dashboard/Kanban/CardCommentStoreAction.ts +82 -0
  301. package/app/Actions/Dashboard/Kanban/CardDestroyAction.ts +48 -0
  302. package/app/Actions/Dashboard/Kanban/CardLabelsSyncAction.ts +103 -0
  303. package/app/Actions/Dashboard/Kanban/CardShowAction.ts +122 -0
  304. package/app/Actions/Dashboard/Kanban/CardStoreAction.ts +112 -0
  305. package/app/Actions/Dashboard/Kanban/CardUpdateAction.ts +91 -0
  306. package/app/Actions/Dashboard/Kanban/CardsReorderAction.ts +148 -0
  307. package/app/Actions/Dashboard/Kanban/ColumnDestroyAction.ts +59 -0
  308. package/app/Actions/Dashboard/Kanban/ColumnStoreAction.ts +94 -0
  309. package/app/Actions/Dashboard/Kanban/ColumnUpdateAction.ts +89 -0
  310. package/app/Actions/Dashboard/Kanban/ColumnsReorderAction.ts +85 -0
  311. package/app/Actions/Dashboard/Kanban/LabelDestroyAction.ts +41 -0
  312. package/app/Actions/Dashboard/Kanban/LabelStoreAction.ts +70 -0
  313. package/app/Actions/Dashboard/Kanban/LabelUpdateAction.ts +83 -0
  314. package/app/Actions/Dashboard/Kanban/UsersListAction.ts +36 -0
  315. package/app/Actions/Dashboard/Library/CreateComponent.ts +11 -0
  316. package/app/Actions/Dashboard/Library/CreateFunction.ts +11 -0
  317. package/app/Actions/Dashboard/Library/DependencyIndexAction.ts +92 -0
  318. package/app/Actions/Dashboard/Library/GetAverageReleaseTime.ts +12 -0
  319. package/app/Actions/Dashboard/Library/GetComponents.ts +24 -0
  320. package/app/Actions/Dashboard/Library/GetComponentsDownloadCount.ts +12 -0
  321. package/app/Actions/Dashboard/Library/GetDownloadCount.ts +12 -0
  322. package/app/Actions/Dashboard/Library/GetFunctions.ts +22 -0
  323. package/app/Actions/Dashboard/Library/GetFunctionsDownloadCount.ts +12 -0
  324. package/app/Actions/Dashboard/Library/GetReleaseCount.ts +12 -0
  325. package/app/Actions/Dashboard/Library/GetReleases.ts +28 -0
  326. package/app/Actions/Dashboard/Library/PackageIndexAction.ts +26 -0
  327. package/app/Actions/Dashboard/Marketing/CampaignIndexAction.ts +45 -0
  328. package/app/Actions/Dashboard/Marketing/ListIndexAction.ts +43 -0
  329. package/app/Actions/Dashboard/Marketing/SocialPostIndexAction.ts +47 -0
  330. package/app/Actions/Dashboard/Models/GetModels.ts +39 -0
  331. package/app/Actions/Dashboard/Models/GetSubscriberCount.ts +12 -0
  332. package/app/Actions/Dashboard/Models/GetUserCount.ts +12 -0
  333. package/app/Actions/Dashboard/Models/ModelShowAction.ts +131 -0
  334. package/app/Actions/Dashboard/Models/ModelsIndexAction.ts +169 -0
  335. package/app/Actions/Dashboard/Notifications/CreateNotification.ts +11 -0
  336. package/app/Actions/Dashboard/Notifications/GetAverageNotificationTime.ts +12 -0
  337. package/app/Actions/Dashboard/Notifications/GetNotificationCount.ts +12 -0
  338. package/app/Actions/Dashboard/Notifications/GetNotificationDeliveryRate.ts +12 -0
  339. package/app/Actions/Dashboard/Notifications/GetNotificationHistory.ts +12 -0
  340. package/app/Actions/Dashboard/Notifications/GetNotifications.ts +12 -0
  341. package/app/Actions/Dashboard/Notifications/NotificationDashboardAction.ts +43 -0
  342. package/app/Actions/Dashboard/Queries/QueryIndexAction.ts +22 -0
  343. package/app/Actions/Dashboard/Queue/QueueRetryFailedAction.ts +22 -0
  344. package/app/Actions/Dashboard/Queue/QueueStatsAction.ts +98 -0
  345. package/app/Actions/Dashboard/Queue/QueueWorkersAction.ts +46 -0
  346. package/app/Actions/Dashboard/Rbac/PermissionDestroyAction.ts +33 -0
  347. package/app/Actions/Dashboard/Rbac/PermissionStoreAction.ts +53 -0
  348. package/app/Actions/Dashboard/Rbac/PermissionsIndexAction.ts +34 -0
  349. package/app/Actions/Dashboard/Rbac/RoleDestroyAction.ts +35 -0
  350. package/app/Actions/Dashboard/Rbac/RolePermissionsShowAction.ts +45 -0
  351. package/app/Actions/Dashboard/Rbac/RolePermissionsSyncAction.ts +63 -0
  352. package/app/Actions/Dashboard/Rbac/RoleStoreAction.ts +58 -0
  353. package/app/Actions/Dashboard/Rbac/RolesIndexAction.ts +36 -0
  354. package/app/Actions/Dashboard/Rbac/UserRolesShowAction.ts +40 -0
  355. package/app/Actions/Dashboard/Rbac/UserRolesSyncAction.ts +65 -0
  356. package/app/Actions/Dashboard/Rbac/UsersListAction.ts +39 -0
  357. package/app/Actions/Dashboard/Realtime/RealtimeStatsAction.ts +50 -0
  358. package/app/Actions/Dashboard/Releases/ReleaseIndexAction.ts +21 -0
  359. package/app/Actions/Dashboard/Requests/GetAverageRequestTime.ts +12 -0
  360. package/app/Actions/Dashboard/Requests/GetRequestCount.ts +12 -0
  361. package/app/Actions/Dashboard/Requests/GetRequestSuccessRate.ts +12 -0
  362. package/app/Actions/Dashboard/Requests/GetRequests.ts +12 -0
  363. package/app/Actions/Dashboard/Search/GlobalSearchAction.ts +26 -0
  364. package/app/Actions/Dashboard/ServiceHealthAction.ts +243 -0
  365. package/app/Actions/Dashboard/Settings/MailSettingsGetAction.ts +20 -0
  366. package/app/Actions/Dashboard/Settings/MailSettingsUpdateAction.ts +10 -0
  367. package/app/Actions/Dashboard/Settings/SettingsIndexAction.ts +40 -0
  368. package/app/Actions/Dashboard/Settings/UpdateAiConfig.ts +27 -0
  369. package/app/Actions/Dashboard/Settings/UpdateAnalyticsConfig.ts +38 -0
  370. package/app/Actions/Dashboard/Settings/UpdateAppConfig.ts +38 -0
  371. package/app/Actions/Dashboard/Settings/UpdateCacheConfig.ts +11 -0
  372. package/app/Actions/Dashboard/Settings/UpdateCliConfig.ts +11 -0
  373. package/app/Actions/Dashboard/Settings/UpdateCloudConfig.ts +38 -0
  374. package/app/Actions/Dashboard/Settings/UpdateDatabaseConfig.ts +38 -0
  375. package/app/Actions/Dashboard/Settings/UpdateDnsConfig.ts +38 -0
  376. package/app/Actions/Dashboard/Settings/UpdateDocsConfig.ts +11 -0
  377. package/app/Actions/Dashboard/Settings/UpdateEmailConfig.ts +38 -0
  378. package/app/Actions/Dashboard/Settings/UpdateEnvConfig.ts +11 -0
  379. package/app/Actions/Dashboard/Settings/UpdateErrorsConfig.ts +11 -0
  380. package/app/Actions/Dashboard/Settings/UpdateFileSystemsConfig.ts +11 -0
  381. package/app/Actions/Dashboard/Settings/UpdateGitConfig.ts +11 -0
  382. package/app/Actions/Dashboard/Settings/UpdateHashingConfig.ts +11 -0
  383. package/app/Actions/Dashboard/Settings/UpdateLibraryConfig.ts +11 -0
  384. package/app/Actions/Dashboard/Settings/UpdateLoggerConfig.ts +11 -0
  385. package/app/Actions/Dashboard/Settings/UpdateNotificationConfig.ts +11 -0
  386. package/app/Actions/Dashboard/Settings/UpdatePaymentConfig.ts +11 -0
  387. package/app/Actions/Dashboard/Settings/UpdatePortsConfig.ts +38 -0
  388. package/app/Actions/Dashboard/Settings/UpdateQueueConfig.ts +11 -0
  389. package/app/Actions/Dashboard/Settings/UpdateSearchEngineConfig.ts +11 -0
  390. package/app/Actions/Dashboard/Settings/UpdateSecurityConfig.ts +38 -0
  391. package/app/Actions/Dashboard/Settings/UpdateServicesConfig.ts +38 -0
  392. package/app/Actions/Dashboard/Settings/UpdateStorageConfig.ts +11 -0
  393. package/app/Actions/Dashboard/Settings/UpdateTeamConfig.ts +11 -0
  394. package/app/Actions/Dashboard/Settings/UpdateUiConfig.ts +11 -0
  395. package/app/Actions/HealthAction.ts +112 -0
  396. package/app/Actions/InstallAction.ts +83 -0
  397. package/app/Actions/Locale/SetLocaleAction.ts +51 -0
  398. package/app/Actions/LogAction.ts +42 -0
  399. package/app/Actions/Logs/LogFetchStatsAction.ts +50 -0
  400. package/app/Actions/Logs/LogIndexOrmAction.ts +13 -0
  401. package/app/Actions/Logs/LogShowOrmAction.ts +17 -0
  402. package/app/Actions/Logs/LogStoreOrmAction.ts +16 -0
  403. package/app/Actions/Logs/LogUpdateOrmAction.ts +20 -0
  404. package/app/Actions/Monitoring/ErrorDestroyAction.ts +25 -0
  405. package/app/Actions/Monitoring/ErrorGroupAction.ts +21 -0
  406. package/app/Actions/Monitoring/ErrorIgnoreAction.ts +25 -0
  407. package/app/Actions/Monitoring/ErrorIndexAction.ts +14 -0
  408. package/app/Actions/Monitoring/ErrorResolveAction.ts +25 -0
  409. package/app/Actions/Monitoring/ErrorShowAction.ts +19 -0
  410. package/app/Actions/Monitoring/ErrorStatsAction.ts +14 -0
  411. package/app/Actions/Monitoring/ErrorTimelineAction.ts +14 -0
  412. package/app/Actions/Monitoring/ErrorUnresolveAction.ts +25 -0
  413. package/app/Actions/NotifyUser.ts +10 -0
  414. package/app/Actions/Password/PasswordResetAction.ts +54 -0
  415. package/app/Actions/Password/SendPasswordResetEmailAction.ts +66 -0
  416. package/app/Actions/Password/VerifyResetTokenAction.ts +27 -0
  417. package/app/Actions/Payment/CancelSubscriptionAction.ts +20 -0
  418. package/app/Actions/Payment/CreateCheckoutAction.ts +28 -0
  419. package/app/Actions/Payment/CreateInvoiceSubscription.ts +18 -0
  420. package/app/Actions/Payment/CreatePaymentIntentAction.ts +31 -0
  421. package/app/Actions/Payment/CreateSetupIntentAction.ts +20 -0
  422. package/app/Actions/Payment/CreateSubscriptionAction.ts +23 -0
  423. package/app/Actions/Payment/DeleteDefaultPaymentAction.ts +18 -0
  424. package/app/Actions/Payment/FetchActiveSubscriptionAction.ts +18 -0
  425. package/app/Actions/Payment/FetchDefaultPaymentMethodAction.ts +18 -0
  426. package/app/Actions/Payment/FetchPaymentCustomerAction.ts +18 -0
  427. package/app/Actions/Payment/FetchPaymentMethodsAction.ts +18 -0
  428. package/app/Actions/Payment/FetchProductAction.ts +15 -0
  429. package/app/Actions/Payment/FetchTransactionHistoryAction.ts +18 -0
  430. package/app/Actions/Payment/FetchUserSubscriptionsAction.ts +18 -0
  431. package/app/Actions/Payment/SetDefaultPaymentAction.ts +20 -0
  432. package/app/Actions/Payment/SetUserDefaultPaymentAction.ts +20 -0
  433. package/app/Actions/Payment/StorePaymentMethodAction.ts +20 -0
  434. package/app/Actions/Payment/StoreTransactionAction.ts +20 -0
  435. package/app/Actions/Payment/UpdateCustomerAction.ts +24 -0
  436. package/app/Actions/Payment/UpdateDefaultPaymentMethodAction.ts +18 -0
  437. package/app/Actions/Payment/UpdateSubscriptionAction.ts +22 -0
  438. package/app/Actions/Queue/FetchQueuesAction.ts +14 -0
  439. package/app/Actions/README.md +61 -0
  440. package/app/Actions/Realtime/FetchWebsocketsAction.ts +14 -0
  441. package/app/Actions/RobotsAction.ts +61 -0
  442. package/app/Actions/SendWelcomeEmail.ts +40 -0
  443. package/app/Actions/SitemapAction.ts +234 -0
  444. package/app/Actions/Storefront/AddToCartAction.ts +153 -0
  445. package/app/Actions/Storefront/CheckoutContactAction.ts +50 -0
  446. package/app/Actions/Storefront/CheckoutShippingAction.ts +61 -0
  447. package/app/Actions/Storefront/GetCartAction.ts +58 -0
  448. package/app/Actions/Storefront/PlaceOrderAction.ts +195 -0
  449. package/app/Actions/Storefront/SubmitReviewAction.ts +140 -0
  450. package/app/Actions/Storefront/UpdateCartItemAction.ts +83 -0
  451. package/app/Actions/Storefront/_shipping.ts +64 -0
  452. package/app/Actions/SubscriberEmailAction.ts +60 -0
  453. package/app/Actions/TestErrorAction.ts +163 -0
  454. package/app/Actions/UnsubscribeAction.ts +107 -0
  455. package/app/Actions/UploadTestAction.ts +57 -0
  456. package/app/Broadcasts/OrderShipped.ts +57 -0
  457. package/app/Commands/Inspire.ts +57 -0
  458. package/app/Commands/README.md +84 -0
  459. package/app/Commands.ts +38 -0
  460. package/app/Controllers/ComingSoonController.ts +9 -0
  461. package/app/Controllers/QueryController.ts +373 -0
  462. package/app/Events.ts +14 -0
  463. package/app/Gates.ts +107 -0
  464. package/app/Jobs/ExampleJob.ts +20 -0
  465. package/app/Jobs/ExampleTwoJob.ts +12 -0
  466. package/app/Jobs/PruneModelsJob.ts +61 -0
  467. package/app/Jobs/PruneQueryLogsJob.ts +51 -0
  468. package/app/Jobs/README.md +79 -0
  469. package/app/Jobs/SendCampaignJob.ts +201 -0
  470. package/app/Jobs/SendEmailJob.ts +52 -0
  471. package/app/Jobs/SendPasswordResetEmailJob.ts +44 -0
  472. package/app/Jobs/SyncSearchIndexJob.ts +64 -0
  473. package/app/Listener.ts +84 -0
  474. package/app/Listeners/Console.ts +22 -0
  475. package/app/Listeners/README.md +47 -0
  476. package/app/Mail/OrderConfirmation.ts +60 -0
  477. package/app/Mail/SubscriptionConfirmation.ts +41 -0
  478. package/app/Middleware/Abilities.ts +53 -0
  479. package/app/Middleware/Api.ts +26 -0
  480. package/app/Middleware/Auth.ts +59 -0
  481. package/app/Middleware/Can.ts +68 -0
  482. package/app/Middleware/Compress.ts +213 -0
  483. package/app/Middleware/Cors.ts +320 -0
  484. package/app/Middleware/Csrf.ts +224 -0
  485. package/app/Middleware/EnsureEmailIsVerified.ts +28 -0
  486. package/app/Middleware/Env.ts +24 -0
  487. package/app/Middleware/EnvDevelopment.ts +19 -0
  488. package/app/Middleware/EnvLocal.ts +19 -0
  489. package/app/Middleware/EnvNotDevelopment.ts +19 -0
  490. package/app/Middleware/EnvNotLocal.ts +19 -0
  491. package/app/Middleware/EnvNotProduction.ts +19 -0
  492. package/app/Middleware/EnvNotStaging.ts +19 -0
  493. package/app/Middleware/EnvProduction.ts +19 -0
  494. package/app/Middleware/EnvStaging.ts +19 -0
  495. package/app/Middleware/Guest.ts +25 -0
  496. package/app/Middleware/Logger.ts +20 -0
  497. package/app/Middleware/Maintenance.ts +36 -0
  498. package/app/Middleware/Permission.ts +42 -0
  499. package/app/Middleware/README.md +48 -0
  500. package/app/Middleware/Role.ts +42 -0
  501. package/app/Middleware/Signed.ts +31 -0
  502. package/app/Middleware/Team.ts +36 -0
  503. package/app/Middleware/Throttle.ts +96 -0
  504. package/app/Middleware.ts +35 -0
  505. package/app/Models/Activity.ts +94 -0
  506. package/app/Models/Board.ts +103 -0
  507. package/app/Models/BoardColumn.ts +87 -0
  508. package/app/Models/Campaign.ts +239 -0
  509. package/app/Models/CampaignSend.ts +107 -0
  510. package/app/Models/Card.ts +117 -0
  511. package/app/Models/CardComment.ts +68 -0
  512. package/app/Models/Comment.ts +108 -0
  513. package/app/Models/Content/Author.ts +104 -0
  514. package/app/Models/Content/Page.ts +99 -0
  515. package/app/Models/Content/Post.ts +144 -0
  516. package/app/Models/Deployment.ts +116 -0
  517. package/app/Models/EmailList.ts +126 -0
  518. package/app/Models/EmailListSubscriber.ts +91 -0
  519. package/app/Models/Error.ts +70 -0
  520. package/app/Models/FailedJob.ts +62 -0
  521. package/app/Models/Job.ts +63 -0
  522. package/app/Models/Label.ts +66 -0
  523. package/app/Models/Log.ts +110 -0
  524. package/app/Models/Notification.ts +118 -0
  525. package/app/Models/PaymentMethod.ts +98 -0
  526. package/app/Models/PaymentProduct.ts +91 -0
  527. package/app/Models/PaymentTransaction.ts +78 -0
  528. package/app/Models/README.md +31 -0
  529. package/app/Models/Release.ts +89 -0
  530. package/app/Models/Request.ts +114 -0
  531. package/app/Models/SocialPost.ts +136 -0
  532. package/app/Models/Subscriber.ts +89 -0
  533. package/app/Models/SubscriberEmail.ts +55 -0
  534. package/app/Models/Subscription.ts +153 -0
  535. package/app/Models/Tag.ts +82 -0
  536. package/app/Models/Team.ts +72 -0
  537. package/app/Models/User.ts +134 -0
  538. package/app/Models/commerce/Cart.ts +139 -0
  539. package/app/Models/commerce/CartItem.ts +137 -0
  540. package/app/Models/commerce/Category.ts +105 -0
  541. package/app/Models/commerce/Coupon.ts +181 -0
  542. package/app/Models/commerce/Customer.ts +132 -0
  543. package/app/Models/commerce/DeliveryRoute.ts +93 -0
  544. package/app/Models/commerce/DigitalDelivery.ts +105 -0
  545. package/app/Models/commerce/Driver.ts +97 -0
  546. package/app/Models/commerce/GiftCard.ts +191 -0
  547. package/app/Models/commerce/LicenseKey.ts +87 -0
  548. package/app/Models/commerce/LoyaltyPoint.ts +107 -0
  549. package/app/Models/commerce/LoyaltyReward.ts +124 -0
  550. package/app/Models/commerce/Manufacturer.ts +84 -0
  551. package/app/Models/commerce/Order.ts +142 -0
  552. package/app/Models/commerce/OrderItem.ts +51 -0
  553. package/app/Models/commerce/Payment.ts +163 -0
  554. package/app/Models/commerce/PrintDevice.ts +117 -0
  555. package/app/Models/commerce/Product.ts +148 -0
  556. package/app/Models/commerce/ProductUnit.ts +107 -0
  557. package/app/Models/commerce/ProductVariant.ts +106 -0
  558. package/app/Models/commerce/Receipt.ts +128 -0
  559. package/app/Models/commerce/Review.ts +140 -0
  560. package/app/Models/commerce/ShippingMethod.ts +97 -0
  561. package/app/Models/commerce/ShippingRate.ts +74 -0
  562. package/app/Models/commerce/ShippingZone.ts +111 -0
  563. package/app/Models/commerce/TaxRate.ts +114 -0
  564. package/app/Models/commerce/Transaction.ts +126 -0
  565. package/app/Models/commerce/WaitlistProduct.ts +149 -0
  566. package/app/Models/commerce/WaitlistRestaurant.ts +187 -0
  567. package/app/Models/realtime/Websocket.ts +77 -0
  568. package/app/Notifications/README.md +31 -0
  569. package/app/Notifications/Welcome.ts +32 -0
  570. package/app/Policies/PostPolicy.ts +131 -0
  571. package/app/README.md +23 -0
  572. package/app/Routes.ts +47 -0
  573. package/app/Scheduler.ts +28 -0
  574. package/app/Storefront/CartCookie.ts +109 -0
  575. package/package.json +3 -2
@@ -0,0 +1,153 @@
1
+ import { Action } from '@stacksjs/actions'
2
+ import { db } from '@stacksjs/database'
3
+ import { response } from '@stacksjs/router'
4
+ import { randomUUIDv7 } from 'bun'
5
+ import { readCartCookie, writeCartCookie } from '../../Storefront/CartCookie'
6
+
7
+ const CART_COOKIE = 'stacks_cart'
8
+ const COOKIE_OPTS = {
9
+ path: '/',
10
+ httpOnly: true,
11
+ sameSite: 'lax' as const,
12
+ maxAge: 60 * 60 * 24 * 30, // 30 days
13
+ }
14
+
15
+ /**
16
+ * Add a product to the shopper's cart.
17
+ *
18
+ * - Anonymous, cookie-keyed: a `stacks_cart` cookie holds a random
19
+ * `session_token` that points at a row in `carts`. We create the cart
20
+ * on first add so empty visitors don't litter the table.
21
+ * - Idempotent per product: if the same slug is already in the cart we
22
+ * bump the existing line's quantity instead of inserting a duplicate.
23
+ * - Form vs XHR: a normal HTML form post redirects to /cart so the
24
+ * back button works; XHR callers (the cart drawer) get JSON and
25
+ * stay on the current page.
26
+ */
27
+ export default new Action({
28
+ name: 'AddToCartAction',
29
+ description: 'Add a product to the anonymous cart, keyed by cookie session.',
30
+ method: 'POST',
31
+
32
+ async handle(request: any) {
33
+ const slug = String(request.get('slug') ?? '').trim()
34
+ const quantity = Math.max(1, Math.min(99, Number(request.get('quantity') ?? 1) || 1))
35
+
36
+ if (!slug)
37
+ return response.json({ error: 'A product slug is required.' }, { status: 422 })
38
+
39
+ const product = await (db as any)
40
+ .selectFrom('products')
41
+ .where('slug', '=', slug)
42
+ .where('is_available', '=', 1)
43
+ .selectAll()
44
+ .executeTakeFirst()
45
+
46
+ if (!product)
47
+ return response.json({ error: `Product "${slug}" not found` }, { status: 404 })
48
+
49
+ // readCartCookie verifies the HMAC; tampered cookies return null
50
+ // and the action falls through to the "create new cart" branch as
51
+ // if no cookie were present. Legacy unsigned tokens are accepted
52
+ // once and re-signed on the next write below.
53
+ let token = readCartCookie(request, CART_COOKIE)
54
+ let cart = token
55
+ ? await (db as any).selectFrom('carts').where('session_token', '=', token).selectAll().executeTakeFirst()
56
+ : null
57
+
58
+ if (!cart) {
59
+ token = randomUUIDv7()
60
+ await (db as any)
61
+ .insertInto('carts')
62
+ .values({
63
+ status: 'active',
64
+ total_items: 0,
65
+ subtotal: 0,
66
+ total: 0,
67
+ currency: 'USD',
68
+ session_token: token,
69
+ checkout_step: 'cart',
70
+ })
71
+ .execute()
72
+ // Re-read by session_token: bun-query-builder's `returningAll()`
73
+ // returns metadata (lastInsertRowid) on sqlite rather than the
74
+ // full row, so we look up by token to grab a real id we can use
75
+ // for the cart_items FK.
76
+ cart = await (db as any)
77
+ .selectFrom('carts')
78
+ .where('session_token', '=', token)
79
+ .selectAll()
80
+ .executeTakeFirst()
81
+ writeCartCookie(request, CART_COOKIE, token, COOKIE_OPTS)
82
+ }
83
+ else if (!(request.cookies?.get?.(CART_COOKIE) ?? '').includes('.')) {
84
+ // Re-sign legacy carts opportunistically so the next request
85
+ // round-trips with the HMAC variant. Cheap — one cookie set per
86
+ // legacy shopper, then never again.
87
+ writeCartCookie(request, CART_COOKIE, token!, COOKIE_OPTS)
88
+ }
89
+
90
+ // Look for an existing line for the same product to bump quantity.
91
+ const existingItem = await (db as any)
92
+ .selectFrom('cart_items')
93
+ .where('cart_id', '=', cart.id)
94
+ .where('product_sku', '=', product.slug)
95
+ .selectAll()
96
+ .executeTakeFirst()
97
+
98
+ if (existingItem) {
99
+ const newQty = Number(existingItem.quantity) + quantity
100
+ await (db as any)
101
+ .updateTable('cart_items')
102
+ .set({
103
+ quantity: newQty,
104
+ total_price: newQty * Number(existingItem.unit_price),
105
+ })
106
+ .where('id', '=', existingItem.id)
107
+ .execute()
108
+ }
109
+ else {
110
+ await (db as any)
111
+ .insertInto('cart_items')
112
+ .values({
113
+ cart_id: cart.id,
114
+ quantity,
115
+ unit_price: Number(product.price),
116
+ total_price: quantity * Number(product.price),
117
+ product_name: product.name,
118
+ product_sku: product.slug,
119
+ product_image: product.image_url,
120
+ })
121
+ .execute()
122
+ }
123
+
124
+ await recomputeCartTotals(cart.id)
125
+
126
+ // Browser form post → redirect; XHR (cart drawer) → JSON.
127
+ const wantsHtml = (request.headers?.get?.('accept') || '').includes('text/html')
128
+ const xhr = request.headers?.get?.('x-requested-with') === 'XMLHttpRequest'
129
+ const redirectTarget = String(request.get('redirect') ?? '/cart')
130
+
131
+ if (wantsHtml && !xhr)
132
+ return response.redirect(redirectTarget)
133
+
134
+ return response.json({ ok: true, cart_id: cart.id })
135
+ },
136
+ })
137
+
138
+ async function recomputeCartTotals(cartId: number): Promise<void> {
139
+ const items = await (db as any)
140
+ .selectFrom('cart_items')
141
+ .where('cart_id', '=', cartId)
142
+ .selectAll()
143
+ .execute()
144
+
145
+ const totalItems = items.reduce((s: number, i: any) => s + Number(i.quantity), 0)
146
+ const subtotal = items.reduce((s: number, i: any) => s + Number(i.total_price || 0), 0)
147
+
148
+ await (db as any)
149
+ .updateTable('carts')
150
+ .set({ total_items: totalItems, subtotal, total: subtotal })
151
+ .where('id', '=', cartId)
152
+ .execute()
153
+ }
@@ -0,0 +1,50 @@
1
+ import { Action } from '@stacksjs/actions'
2
+ import { db } from '@stacksjs/database'
3
+ import { response } from '@stacksjs/router'
4
+ import { readCartCookie } from '../../Storefront/CartCookie'
5
+
6
+ const CART_COOKIE = 'stacks_cart'
7
+
8
+ /**
9
+ * Step 1 of multi-step checkout. Persists the shopper's email on the
10
+ * cart row and bumps the cart's `checkout_step` so a refresh on the
11
+ * shipping page knows which step the shopper is actually on.
12
+ */
13
+ export default new Action({
14
+ name: 'CheckoutContactAction',
15
+ description: 'Save the shopper email on the active cart.',
16
+ method: 'POST',
17
+
18
+ async handle(request: any) {
19
+ const email = String(request.get('email') ?? '').trim().toLowerCase()
20
+ if (!email || !email.includes('@'))
21
+ return response.json({ error: 'A valid email is required.' }, { status: 422 })
22
+
23
+ const token = readCartCookie(request, CART_COOKIE)
24
+ if (!token)
25
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
26
+
27
+ const cart = await (db as any)
28
+ .selectFrom('carts')
29
+ .where('session_token', '=', token)
30
+ .where('status', '=', 'active')
31
+ .selectAll()
32
+ .executeTakeFirst()
33
+
34
+ if (!cart)
35
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
36
+
37
+ await (db as any)
38
+ .updateTable('carts')
39
+ .set({ email, checkout_step: 'shipping' })
40
+ .where('id', '=', cart.id)
41
+ .execute()
42
+
43
+ const wantsHtml = (request.headers?.get?.('accept') || '').includes('text/html')
44
+ const xhr = request.headers?.get?.('x-requested-with') === 'XMLHttpRequest'
45
+ if (wantsHtml && !xhr)
46
+ return response.redirect('/checkout/shipping')
47
+
48
+ return response.json({ ok: true, next: '/checkout/shipping' })
49
+ },
50
+ })
@@ -0,0 +1,61 @@
1
+ import { Action } from '@stacksjs/actions'
2
+ import { db } from '@stacksjs/database'
3
+ import { response } from '@stacksjs/router'
4
+ import { readCartCookie } from '../../Storefront/CartCookie'
5
+
6
+ const CART_COOKIE = 'stacks_cart'
7
+
8
+ /**
9
+ * Step 2 of multi-step checkout. Saves shipping address fields on the
10
+ * cart and advances to the payment step.
11
+ */
12
+ export default new Action({
13
+ name: 'CheckoutShippingAction',
14
+ description: 'Save shipping address on the active cart.',
15
+ method: 'POST',
16
+
17
+ async handle(request: any) {
18
+ const name = String(request.get('shipping_name') ?? '').trim()
19
+ const address = String(request.get('shipping_address') ?? '').trim()
20
+ const city = String(request.get('shipping_city') ?? '').trim()
21
+ const state = String(request.get('shipping_state') ?? '').trim()
22
+ const zip = String(request.get('shipping_zip') ?? '').trim()
23
+
24
+ if (!name || !address || !city || !state || !zip)
25
+ return response.json({ error: 'All shipping fields are required.' }, { status: 422 })
26
+
27
+ const token = readCartCookie(request, CART_COOKIE)
28
+ if (!token)
29
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
30
+
31
+ const cart = await (db as any)
32
+ .selectFrom('carts')
33
+ .where('session_token', '=', token)
34
+ .where('status', '=', 'active')
35
+ .selectAll()
36
+ .executeTakeFirst()
37
+
38
+ if (!cart)
39
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
40
+
41
+ await (db as any)
42
+ .updateTable('carts')
43
+ .set({
44
+ shipping_name: name,
45
+ shipping_address: address,
46
+ shipping_city: city,
47
+ shipping_state: state,
48
+ shipping_zip: zip,
49
+ checkout_step: 'payment',
50
+ })
51
+ .where('id', '=', cart.id)
52
+ .execute()
53
+
54
+ const wantsHtml = (request.headers?.get?.('accept') || '').includes('text/html')
55
+ const xhr = request.headers?.get?.('x-requested-with') === 'XMLHttpRequest'
56
+ if (wantsHtml && !xhr)
57
+ return response.redirect('/checkout/payment')
58
+
59
+ return response.json({ ok: true, next: '/checkout/payment' })
60
+ },
61
+ })
@@ -0,0 +1,58 @@
1
+ import { Action } from '@stacksjs/actions'
2
+ import { db } from '@stacksjs/database'
3
+ import { response } from '@stacksjs/router'
4
+ import { readCartCookie } from '../../Storefront/CartCookie'
5
+
6
+ const CART_COOKIE = 'stacks_cart'
7
+
8
+ /**
9
+ * Read-only cart endpoint used by the slide-in CartDrawer to refresh
10
+ * its contents after an add/remove. Returns the same shape the drawer
11
+ * renders directly so the client doesn't have to do any reshaping.
12
+ */
13
+ export default new Action({
14
+ name: 'GetCartAction',
15
+ description: 'Return the current cart for the caller cookie.',
16
+ method: 'GET',
17
+
18
+ async handle(request: any) {
19
+ // Verify HMAC; tampered cookies behave the same as no cookie at
20
+ // all — return an empty cart shell instead of looking up the
21
+ // forged token. Legacy unsigned tokens parse through.
22
+ const token = readCartCookie(request, CART_COOKIE)
23
+ if (!token)
24
+ return response.json({ items: [], subtotal: 0, total_items: 0 })
25
+
26
+ const cart = await (db as any)
27
+ .selectFrom('carts')
28
+ .where('session_token', '=', token)
29
+ .where('status', '=', 'active')
30
+ .selectAll()
31
+ .executeTakeFirst()
32
+
33
+ if (!cart)
34
+ return response.json({ items: [], subtotal: 0, total_items: 0 })
35
+
36
+ const rawItems = await (db as any)
37
+ .selectFrom('cart_items')
38
+ .where('cart_id', '=', cart.id)
39
+ .selectAll()
40
+ .execute()
41
+
42
+ const items = rawItems.map((row: any) => ({
43
+ id: row.id,
44
+ slug: row.product_sku,
45
+ name: row.product_name,
46
+ image: row.product_image,
47
+ qty: Number(row.quantity),
48
+ price: Number(row.unit_price),
49
+ lineTotal: Number(row.total_price || 0),
50
+ }))
51
+
52
+ return response.json({
53
+ items,
54
+ total_items: Number(cart.total_items || 0),
55
+ subtotal: Number(cart.subtotal || 0),
56
+ })
57
+ },
58
+ })
@@ -0,0 +1,195 @@
1
+ import { Action } from '@stacksjs/actions'
2
+ import { config } from '@stacksjs/config'
3
+ import { db } from '@stacksjs/database'
4
+ import { response } from '@stacksjs/router'
5
+ import { sendOrderConfirmation } from '../../Mail/OrderConfirmation'
6
+ import { readCartCookie } from '../../Storefront/CartCookie'
7
+ import { totalsFor } from './_shipping'
8
+
9
+ const CART_COOKIE = 'stacks_cart'
10
+
11
+ /**
12
+ * Step 3 of multi-step checkout — the actual "place order" call.
13
+ *
14
+ * Pulls everything we collected in earlier steps off the cart row
15
+ * (email + shipping_*), creates a Customer if we don't have one for
16
+ * this email yet, materializes an Order + OrderItems, decrements
17
+ * inventory, marks the cart as `converted`, and clears the cookie so
18
+ * a refresh starts fresh.
19
+ *
20
+ * No real card is charged — a Stripe call would slot in between the
21
+ * cart lookup and the order creation. The mock card form on the
22
+ * payment view doesn't actually submit any sensitive data.
23
+ */
24
+ export default new Action({
25
+ name: 'PlaceOrderAction',
26
+ description: 'Convert the active cart into an Order + OrderItems.',
27
+ method: 'POST',
28
+
29
+ async handle(request: any) {
30
+ const token = readCartCookie(request, CART_COOKIE)
31
+ if (!token)
32
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
33
+
34
+ const cart = await (db as any)
35
+ .selectFrom('carts')
36
+ .where('session_token', '=', token)
37
+ .where('status', '=', 'active')
38
+ .selectAll()
39
+ .executeTakeFirst()
40
+
41
+ if (!cart)
42
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
43
+
44
+ const items = await (db as any)
45
+ .selectFrom('cart_items')
46
+ .where('cart_id', '=', cart.id)
47
+ .selectAll()
48
+ .execute()
49
+
50
+ if (items.length === 0)
51
+ return response.json({ error: 'Your cart is empty.' }, { status: 400 })
52
+
53
+ if (!cart.email || !cart.shipping_name || !cart.shipping_address)
54
+ return response.json({ error: 'Checkout details are incomplete.' }, { status: 422 })
55
+
56
+ // One customer per email — repeat shoppers reuse the same row so
57
+ // the dashboard's customer total isn't inflated by checkouts.
58
+ let customer = await (db as any)
59
+ .selectFrom('customers')
60
+ .where('email', '=', cart.email)
61
+ .selectAll()
62
+ .executeTakeFirst()
63
+
64
+ if (!customer) {
65
+ await (db as any)
66
+ .insertInto('customers')
67
+ .values({ name: cart.shipping_name, email: cart.email })
68
+ .execute()
69
+ customer = await (db as any)
70
+ .selectFrom('customers')
71
+ .where('email', '=', cart.email)
72
+ .selectAll()
73
+ .executeTakeFirst()
74
+ }
75
+
76
+ const itemsSubtotal = items.reduce((s: number, i: any) => s + Number(i.total_price || 0), 0)
77
+ const { subtotal, shipping, total } = totalsFor(itemsSubtotal)
78
+
79
+ const fullAddress = [
80
+ cart.shipping_address,
81
+ [cart.shipping_city, cart.shipping_state, cart.shipping_zip].filter(Boolean).join(', '),
82
+ ].filter(Boolean).join('\n')
83
+
84
+ await (db as any)
85
+ .insertInto('orders')
86
+ .values({
87
+ customer_id: customer.id,
88
+ status: 'paid',
89
+ order_type: 'shipping',
90
+ total_amount: total,
91
+ delivery_fee: shipping,
92
+ delivery_address: fullAddress,
93
+ })
94
+ .execute()
95
+ // Re-read latest order for this customer — RETURNING * doesn't
96
+ // round-trip the row reliably on sqlite via bun-query-builder.
97
+ const order = await (db as any)
98
+ .selectFrom('orders')
99
+ .where('customer_id', '=', customer.id)
100
+ .orderBy('id', 'desc')
101
+ .limit(1)
102
+ .selectAll()
103
+ .executeTakeFirst()
104
+
105
+ // Map cart_items → order_items, resolving product_id by SKU.
106
+ for (const item of items) {
107
+ const product = await (db as any)
108
+ .selectFrom('products')
109
+ .where('slug', '=', item.product_sku)
110
+ .selectAll()
111
+ .executeTakeFirst()
112
+
113
+ await (db as any)
114
+ .insertInto('order_items')
115
+ .values({
116
+ order_id: order.id,
117
+ product_id: product?.id ?? null,
118
+ quantity: Number(item.quantity),
119
+ price: Number(item.unit_price),
120
+ })
121
+ .execute()
122
+ }
123
+
124
+ // Decrement inventory for what we just sold. Best-effort — we
125
+ // already accepted the order, so a stock-row miss shouldn't
126
+ // fail the response.
127
+ for (const item of items) {
128
+ try {
129
+ const product = await (db as any)
130
+ .selectFrom('products')
131
+ .where('slug', '=', item.product_sku)
132
+ .selectAll()
133
+ .executeTakeFirst()
134
+ if (product) {
135
+ const next = Math.max(0, Number(product.inventory_count || 0) - Number(item.quantity))
136
+ await (db as any)
137
+ .updateTable('products')
138
+ .set({ inventory_count: next })
139
+ .where('id', '=', product.id)
140
+ .execute()
141
+ }
142
+ }
143
+ catch { /* keep going */ }
144
+ }
145
+
146
+ await (db as any)
147
+ .updateTable('carts')
148
+ .set({ status: 'converted', checkout_step: 'placed' })
149
+ .where('id', '=', cart.id)
150
+ .execute()
151
+
152
+ request.cookies?.delete?.(CART_COOKIE, { path: '/' })
153
+
154
+ // Fire the receipt email asynchronously so a mailer hiccup
155
+ // never fails an otherwise-good checkout. The customer can still
156
+ // see their order on the post-checkout page even if the email
157
+ // never lands.
158
+ const baseUrl = (() => {
159
+ let raw = process.env.APP_URL || config.app.url || ''
160
+ if (raw && !/^https?:\/\//i.test(raw)) raw = `https://${raw}`
161
+ return raw.replace(/\/$/, '')
162
+ })()
163
+ sendOrderConfirmation({
164
+ to: cart.email,
165
+ orderId: order.id,
166
+ customerName: cart.shipping_name || customer.name,
167
+ items: items.map((row: any) => ({
168
+ name: row.product_name,
169
+ qty: Number(row.quantity),
170
+ lineTotal: Number(row.total_price || 0),
171
+ })),
172
+ subtotal,
173
+ shipping,
174
+ total,
175
+ shippingAddress: fullAddress,
176
+ orderUrl: `${baseUrl}/orders/${order.id}`,
177
+ }).catch((err: unknown) => {
178
+ const message = err instanceof Error ? err.message : String(err)
179
+ console.error(`[PlaceOrderAction] order receipt email failed for order #${order.id}:`, message)
180
+ })
181
+
182
+ const wantsHtml = (request.headers?.get?.('accept') || '').includes('text/html')
183
+ const xhr = request.headers?.get?.('x-requested-with') === 'XMLHttpRequest'
184
+ if (wantsHtml && !xhr)
185
+ return response.redirect(`/orders/${order.id}`)
186
+
187
+ return response.json({
188
+ ok: true,
189
+ order_id: order.id,
190
+ total,
191
+ subtotal,
192
+ shipping,
193
+ })
194
+ },
195
+ })
@@ -0,0 +1,140 @@
1
+ import { Action } from '@stacksjs/actions'
2
+ import { db } from '@stacksjs/database'
3
+ import { rateLimit, response } from '@stacksjs/router'
4
+ import { readCartCookie } from '../../Storefront/CartCookie'
5
+
6
+ const CART_COOKIE = 'stacks_cart'
7
+
8
+ /**
9
+ * Public review-submission endpoint. Posted from `/orders/{id}` by
10
+ * the buyer after their order ships.
11
+ *
12
+ * Trust model:
13
+ * - Verifies the submitter actually owns the order by matching the
14
+ * `email` on the order against the `email` they're posting with,
15
+ * and additionally accepts a still-valid cart cookie path for
16
+ * guest shoppers who haven't enrolled in account auth.
17
+ * - Marks `is_verified_purchase=1` only when that email-on-order
18
+ * check passes.
19
+ * - Always inserts with `is_approved=0`. The dashboard's reviews
20
+ * index shows pending entries to admins for moderation.
21
+ *
22
+ * Spam handling: rate-limit per IP (5/min) so a hostile actor can't
23
+ * dump 1000 boilerplate reviews from one address. Honeypot field
24
+ * (`website`) catches drive-by bots — a non-empty value short-circuits
25
+ * with a fake-success response.
26
+ */
27
+ export default new Action({
28
+ name: 'SubmitReviewAction',
29
+ description: 'Buyer-submitted review tied to a shipped order. Marked pending until moderated.',
30
+ method: 'POST',
31
+
32
+ async handle(request: any) {
33
+ await rateLimit('review-submit', 5).per('minute')
34
+
35
+ const orderId = Number(request.get('order_id') ?? 0)
36
+ const productSlug = String(request.get('product_slug') ?? '').trim()
37
+ const rating = Math.max(1, Math.min(5, Number(request.get('rating') ?? 0)))
38
+ const title = String(request.get('title') ?? '').trim()
39
+ const content = String(request.get('content') ?? '').trim()
40
+ const email = String(request.get('email') ?? '').trim().toLowerCase()
41
+ // Honeypot. Bots fill every field; a real form keeps this hidden
42
+ // and untouched. Pretend to succeed so the bot moves on without
43
+ // retrying with a different shape.
44
+ const honeypot = String(request.get('website') ?? '').trim()
45
+ if (honeypot)
46
+ return response.json({ success: true })
47
+
48
+ if (!orderId || !productSlug || !rating || !title || !content || !email)
49
+ return response.json({ success: false, message: 'All fields are required.' }, { status: 422 })
50
+
51
+ if (title.length > 100)
52
+ return response.json({ success: false, message: 'Title is too long.' }, { status: 422 })
53
+ if (content.length > 2000)
54
+ return response.json({ success: false, message: 'Review is too long.' }, { status: 422 })
55
+
56
+ // Verify the order + ownership. Two acceptable proofs of ownership:
57
+ // (a) email on the order row matches the submitted email
58
+ // (b) shopper still has the cart cookie that placed the order
59
+ // Either is enough — (a) is the common case for a returning buyer
60
+ // clicking the link in their receipt; (b) covers a buyer who never
61
+ // closes the post-checkout tab.
62
+ const order = await (db as any)
63
+ .selectFrom('orders')
64
+ .where('id', '=', orderId)
65
+ .selectAll()
66
+ .executeTakeFirst()
67
+ if (!order)
68
+ return response.json({ success: false, message: 'Order not found.' }, { status: 404 })
69
+
70
+ let ownsOrder = false
71
+ if (order.customer_id) {
72
+ const customer = await (db as any)
73
+ .selectFrom('customers')
74
+ .where('id', '=', order.customer_id)
75
+ .selectAll()
76
+ .executeTakeFirst()
77
+ if (customer && String(customer.email || '').toLowerCase() === email)
78
+ ownsOrder = true
79
+ }
80
+ if (!ownsOrder) {
81
+ const cookieToken = readCartCookie(request, CART_COOKIE)
82
+ if (cookieToken) {
83
+ const cart = await (db as any)
84
+ .selectFrom('carts')
85
+ .where('session_token', '=', cookieToken)
86
+ .selectAll()
87
+ .executeTakeFirst()
88
+ if (cart && cart.email && String(cart.email).toLowerCase() === email)
89
+ ownsOrder = true
90
+ }
91
+ }
92
+ if (!ownsOrder)
93
+ return response.json({ success: false, message: 'We could not match you to that order.' }, { status: 403 })
94
+
95
+ // Resolve the product row by slug. Reviews use `product_id` as a
96
+ // FK; the storefront submits the slug because it's what the URL
97
+ // and cart row already carry.
98
+ const product = await (db as any)
99
+ .selectFrom('products')
100
+ .where('slug', '=', productSlug)
101
+ .selectAll()
102
+ .executeTakeFirst()
103
+ if (!product)
104
+ return response.json({ success: false, message: 'Unknown product.' }, { status: 422 })
105
+
106
+ // Block duplicates per (order, product) pair so a curious shopper
107
+ // can't refresh-spam the form and clobber the moderation queue.
108
+ const dup = await (db as any)
109
+ .selectFrom('reviews')
110
+ .where('product_id', '=', product.id)
111
+ .where('order_id', '=', orderId)
112
+ .selectAll()
113
+ .executeTakeFirst()
114
+ if (dup)
115
+ return response.json({ success: false, message: 'You already submitted a review for this product on this order.' }, { status: 409 })
116
+
117
+ await (db as any)
118
+ .insertInto('reviews')
119
+ .values({
120
+ product_id: product.id,
121
+ customer_id: order.customer_id ?? null,
122
+ order_id: orderId,
123
+ rating,
124
+ title,
125
+ content,
126
+ is_verified_purchase: 1,
127
+ is_approved: 0,
128
+ is_featured: 0,
129
+ helpful_votes: 0,
130
+ unhelpful_votes: 0,
131
+ purchase_date: order.created_at || new Date().toISOString(),
132
+ })
133
+ .execute()
134
+
135
+ return response.json({
136
+ success: true,
137
+ message: "Thanks — your review is in. We'll publish it once a human gives it a quick look.",
138
+ })
139
+ },
140
+ })