@stacksjs/defaults 0.70.54

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 (286) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +2 -0
  3. package/package.json +20 -0
  4. package/resources/assets/fonts/013717e9.woff +0 -0
  5. package/resources/assets/fonts/03355817.woff2 +0 -0
  6. package/resources/assets/fonts/0380de7e.woff2 +0 -0
  7. package/resources/assets/fonts/0ba5d32a.woff +0 -0
  8. package/resources/assets/fonts/0bd57ddf.woff2 +0 -0
  9. package/resources/assets/fonts/19de0a60.woff2 +0 -0
  10. package/resources/assets/fonts/20b87e84.woff +0 -0
  11. package/resources/assets/fonts/4bbc67e1.woff +0 -0
  12. package/resources/assets/fonts/576fb0d7.woff +0 -0
  13. package/resources/assets/fonts/5ea10ee5.woff2 +0 -0
  14. package/resources/assets/fonts/6413fc0a.woff +0 -0
  15. package/resources/assets/fonts/72c114cf.woff +0 -0
  16. package/resources/assets/fonts/73c57e73.woff2 +0 -0
  17. package/resources/assets/fonts/813dca6c.woff +0 -0
  18. package/resources/assets/fonts/8a9b0995.woff2 +0 -0
  19. package/resources/assets/fonts/90b4832f.woff +0 -0
  20. package/resources/assets/fonts/9394ab85.woff2 +0 -0
  21. package/resources/assets/fonts/9b3c7d7f.woff2 +0 -0
  22. package/resources/assets/fonts/Monaco.ttf +0 -0
  23. package/resources/assets/fonts/b1b36d74.woff +0 -0
  24. package/resources/assets/fonts/b5d74798.woff2 +0 -0
  25. package/resources/assets/fonts/b9f81a4d.woff +0 -0
  26. package/resources/assets/fonts/c9784008.woff2 +0 -0
  27. package/resources/assets/fonts/cf692227.woff +0 -0
  28. package/resources/assets/fonts/d1c6ab51.woff2 +0 -0
  29. package/resources/assets/fonts/e2eb62fc.woff +0 -0
  30. package/resources/assets/fonts/fe21f8d8.woff2 +0 -0
  31. package/resources/assets/fonts/nps/CampmateScript-Regular.woff2 +0 -0
  32. package/resources/assets/fonts/nps/NPS_2026-variable.woff2 +0 -0
  33. package/resources/assets/fonts/nps/RedwoodSerif-Regular.woff2 +0 -0
  34. package/resources/assets/fonts/nps/SequoiaSans-Regular.woff2 +0 -0
  35. package/resources/assets/fonts/nps/Switchback-Regular.woff2 +0 -0
  36. package/resources/assets/images/app-icon.png +0 -0
  37. package/resources/assets/images/bg-img.png +0 -0
  38. package/resources/assets/images/park-ridge.svg +15 -0
  39. package/resources/assets/images/topography.svg +1 -0
  40. package/resources/assets/scripts/main.ts +2153 -0
  41. package/resources/assets/styles/README.md +19 -0
  42. package/resources/assets/styles/docs/main.css +1 -0
  43. package/resources/assets/styles/docs/overrides.css +1 -0
  44. package/resources/assets/styles/docs/vars.css +8 -0
  45. package/resources/assets/styles/main.css +1419 -0
  46. package/resources/components/Button.stx +70 -0
  47. package/resources/components/Buttons/BaseButton.stx +39 -0
  48. package/resources/components/Buttons/Counter.stx +28 -0
  49. package/resources/components/Buttons/ToggleDark.stx +11 -0
  50. package/resources/components/Container.stx +10 -0
  51. package/resources/components/Dashboard/.gitkeep +0 -0
  52. package/resources/components/Dashboard/Auth/ForgotPassword.stx +127 -0
  53. package/resources/components/Dashboard/Auth/Login.stx +212 -0
  54. package/resources/components/Dashboard/Auth/Register.stx +306 -0
  55. package/resources/components/Dashboard/Avatar.stx +123 -0
  56. package/resources/components/Dashboard/Billing/ActivePlan.stx +57 -0
  57. package/resources/components/Dashboard/Billing/CardBrands.stx +32 -0
  58. package/resources/components/Dashboard/Billing/CardForm.stx +34 -0
  59. package/resources/components/Dashboard/Billing/OneTimePayment.stx +28 -0
  60. package/resources/components/Dashboard/Billing/PaymentForm.stx +33 -0
  61. package/resources/components/Dashboard/Billing/PaymentMethod.stx +66 -0
  62. package/resources/components/Dashboard/Billing/PaymentMethodList.stx +52 -0
  63. package/resources/components/Dashboard/Billing/Plans.stx +136 -0
  64. package/resources/components/Dashboard/Buttons/AppButton.stx +48 -0
  65. package/resources/components/Dashboard/Buttons/IconButton.stx +20 -0
  66. package/resources/components/Dashboard/Card.stx +78 -0
  67. package/resources/components/Dashboard/Chart.stx +75 -0
  68. package/resources/components/Dashboard/CodeEditor.stx +41 -0
  69. package/resources/components/Dashboard/Commerce/BulkActionBar.stx +70 -0
  70. package/resources/components/Dashboard/Commerce/CategoriesTable.stx +133 -0
  71. package/resources/components/Dashboard/Commerce/CouponsTable.stx +161 -0
  72. package/resources/components/Dashboard/Commerce/CustomersTable.stx +142 -0
  73. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +80 -0
  74. package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryTable.stx +85 -0
  75. package/resources/components/Dashboard/Commerce/Delivery/DriversTable.stx +99 -0
  76. package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysTable.stx +92 -0
  77. package/resources/components/Dashboard/Commerce/Delivery/LicenseTemplatesTable.stx +88 -0
  78. package/resources/components/Dashboard/Commerce/Delivery/Pagination.stx +122 -0
  79. package/resources/components/Dashboard/Commerce/Delivery/SearchFilter.stx +23 -0
  80. package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodsTable.stx +80 -0
  81. package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesTable.stx +59 -0
  82. package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesTable.stx +71 -0
  83. package/resources/components/Dashboard/Commerce/Delivery/TabNavigation.stx +36 -0
  84. package/resources/components/Dashboard/Commerce/Forms/CouponsForm.stx +191 -0
  85. package/resources/components/Dashboard/Commerce/OrdersTable.stx +131 -0
  86. package/resources/components/Dashboard/Commerce/ProductsTable.stx +170 -0
  87. package/resources/components/Dashboard/CreateRecordModal.stx +363 -0
  88. package/resources/components/Dashboard/DashboardLayout.stx +155 -0
  89. package/resources/components/Dashboard/Deployments/ActivityFeed.stx +54 -0
  90. package/resources/components/Dashboard/Deployments/DeployScript.stx +23 -0
  91. package/resources/components/Dashboard/Deployments/DeploymentHistory.stx +97 -0
  92. package/resources/components/Dashboard/Deployments/DeploymentList.stx +94 -0
  93. package/resources/components/Dashboard/Deployments/LiveTerminalOutput.stx +18 -0
  94. package/resources/components/Dashboard/Elements/Dropdown.stx +57 -0
  95. package/resources/components/Dashboard/Email/EmailActivityChart.stx +111 -0
  96. package/resources/components/Dashboard/Email/EmailCompose.stx +72 -0
  97. package/resources/components/Dashboard/Email/EmailDetail.stx +105 -0
  98. package/resources/components/Dashboard/Email/EmailList.stx +117 -0
  99. package/resources/components/Dashboard/Email/EmailSearch.stx +40 -0
  100. package/resources/components/Dashboard/Email/EmailSidebar.stx +133 -0
  101. package/resources/components/Dashboard/GlobalSearch.stx +124 -0
  102. package/resources/components/Dashboard/MobileSidebar.stx +47 -0
  103. package/resources/components/Dashboard/Modals/BaseModal.stx +50 -0
  104. package/resources/components/Dashboard/Modals/Popups/Alert.stx +112 -0
  105. package/resources/components/Dashboard/Modals/Popups/Toast.stx +70 -0
  106. package/resources/components/Dashboard/Modals/ToastWrapper.stx +35 -0
  107. package/resources/components/Dashboard/Monitoring/ErrorDetailModal.stx +228 -0
  108. package/resources/components/Dashboard/Monitoring/ErrorsTable.stx +184 -0
  109. package/resources/components/Dashboard/Navbar.stx +194 -0
  110. package/resources/components/Dashboard/NavbarModern.stx +188 -0
  111. package/resources/components/Dashboard/NotificationErrorModal.stx +105 -0
  112. package/resources/components/Dashboard/NotificationStatusBadge.stx +20 -0
  113. package/resources/components/Dashboard/Pagination.stx +90 -0
  114. package/resources/components/Dashboard/Queue/QueueTable.stx +127 -0
  115. package/resources/components/Dashboard/Settings/Forms/AIForm.stx +126 -0
  116. package/resources/components/Dashboard/Settings/Forms/AnalyticsForm.stx +52 -0
  117. package/resources/components/Dashboard/Settings/Forms/AppForm.stx +157 -0
  118. package/resources/components/Dashboard/Settings/Forms/CLIForm.stx +66 -0
  119. package/resources/components/Dashboard/Settings/Forms/CacheForm.stx +253 -0
  120. package/resources/components/Dashboard/Settings/Forms/CloudForm.stx +441 -0
  121. package/resources/components/Dashboard/Settings/Forms/DNSForm.stx +307 -0
  122. package/resources/components/Dashboard/Settings/Forms/DatabaseForm.stx +168 -0
  123. package/resources/components/Dashboard/Settings/Forms/EmailForm.stx +100 -0
  124. package/resources/components/Dashboard/Settings/Forms/FileSystemForm.stx +259 -0
  125. package/resources/components/Dashboard/Settings/Forms/HashingForm.stx +119 -0
  126. package/resources/components/Dashboard/Settings/Forms/LibraryForm.stx +389 -0
  127. package/resources/components/Dashboard/Settings/Forms/QueueForm.stx +219 -0
  128. package/resources/components/Dashboard/Settings/Forms/SearchEngineForm.stx +48 -0
  129. package/resources/components/Dashboard/Settings/Forms/SecurityForm.stx +143 -0
  130. package/resources/components/Dashboard/Settings/Forms/ServicesForm.stx +194 -0
  131. package/resources/components/Dashboard/Settings/Forms/StorageForm.stx +191 -0
  132. package/resources/components/Dashboard/Settings/Forms/TeamsForm.stx +33 -0
  133. package/resources/components/Dashboard/Settings/SettingsFormManager.stx +181 -0
  134. package/resources/components/Dashboard/SettingsHeader.stx +88 -0
  135. package/resources/components/Dashboard/SettingsSidebar.stx +234 -0
  136. package/resources/components/Dashboard/Sidebar.stx +23 -0
  137. package/resources/components/Dashboard/SidebarModern.stx +249 -0
  138. package/resources/components/Dashboard/Skeleton/LoadingCard.stx +15 -0
  139. package/resources/components/Dashboard/Skeleton/LoadingDetails.stx +26 -0
  140. package/resources/components/Dashboard/Table.stx +82 -0
  141. package/resources/components/Dashboard/TerminalContainer.stx +97 -0
  142. package/resources/components/Dashboard/Tooltip.stx +166 -0
  143. package/resources/components/Dashboard/Transaction/index.stx +88 -0
  144. package/resources/components/Dashboard/UI/ActivityTable.stx +54 -0
  145. package/resources/components/Dashboard/UI/Avatar.stx +102 -0
  146. package/resources/components/Dashboard/UI/Badge.stx +66 -0
  147. package/resources/components/Dashboard/UI/Button.stx +73 -0
  148. package/resources/components/Dashboard/UI/Card.stx +51 -0
  149. package/resources/components/Dashboard/UI/ChartCard.stx +36 -0
  150. package/resources/components/Dashboard/UI/Checkbox.stx +74 -0
  151. package/resources/components/Dashboard/UI/ConfirmDialog.stx +74 -0
  152. package/resources/components/Dashboard/UI/DataTable.stx +45 -0
  153. package/resources/components/Dashboard/UI/Dropdown.stx +72 -0
  154. package/resources/components/Dashboard/UI/DropdownItem.stx +80 -0
  155. package/resources/components/Dashboard/UI/EmptyState.stx +50 -0
  156. package/resources/components/Dashboard/UI/FilterBar.stx +48 -0
  157. package/resources/components/Dashboard/UI/Input.stx +77 -0
  158. package/resources/components/Dashboard/UI/Modal.stx +75 -0
  159. package/resources/components/Dashboard/UI/PageHeader.stx +69 -0
  160. package/resources/components/Dashboard/UI/PageLayout.stx +84 -0
  161. package/resources/components/Dashboard/UI/Pagination.stx +126 -0
  162. package/resources/components/Dashboard/UI/QuickLinks.stx +31 -0
  163. package/resources/components/Dashboard/UI/RouterLink.stx +31 -0
  164. package/resources/components/Dashboard/UI/Select.stx +84 -0
  165. package/resources/components/Dashboard/UI/ServiceHealth.stx +38 -0
  166. package/resources/components/Dashboard/UI/StatsCard.stx +79 -0
  167. package/resources/components/Dashboard/UI/Table.stx +143 -0
  168. package/resources/components/Dashboard/UI/Tabs.stx +45 -0
  169. package/resources/components/Dashboard/UI/Textarea.stx +93 -0
  170. package/resources/components/Dashboard/UI/Toggle.stx +84 -0
  171. package/resources/components/Dashboard/UI/WindowControls.stx +135 -0
  172. package/resources/components/Dashboard/Widget.stx +89 -0
  173. package/resources/components/Dashboard/WindowControls.stx +119 -0
  174. package/resources/components/Dashboard/index.ts +106 -0
  175. package/resources/components/Docs/Demo/ComboboxCode.md +114 -0
  176. package/resources/components/Docs/Demo/ComboboxDemo.stx +91 -0
  177. package/resources/components/Docs/Demo/DialogCode.md +42 -0
  178. package/resources/components/Docs/Demo/DialogDemo.stx +76 -0
  179. package/resources/components/Docs/Demo/DocsPlayground.stx +39 -0
  180. package/resources/components/Docs/Demo/DropdownCode.md +109 -0
  181. package/resources/components/Docs/Demo/DropdownDemo.stx +82 -0
  182. package/resources/components/Docs/Demo/Hero.stx +100 -0
  183. package/resources/components/Docs/Demo/ListboxCode.md +87 -0
  184. package/resources/components/Docs/Demo/ListboxDemo.stx +59 -0
  185. package/resources/components/Docs/Demo/NotificationCode.md +173 -0
  186. package/resources/components/Docs/Demo/NotificationDemo.stx +99 -0
  187. package/resources/components/Docs/Demo/PopoverCode.md +161 -0
  188. package/resources/components/Docs/Demo/PopoverDemo.stx +96 -0
  189. package/resources/components/Docs/Demo/RadioGroupCode.md +98 -0
  190. package/resources/components/Docs/Demo/RadioGroupDemo.stx +53 -0
  191. package/resources/components/Docs/Demo/StepperCode.md +216 -0
  192. package/resources/components/Docs/Demo/StepperDemo.stx +137 -0
  193. package/resources/components/Docs/Demo/SwitchCode.md +24 -0
  194. package/resources/components/Docs/Demo/SwitchDemo.stx +28 -0
  195. package/resources/components/Docs/Home.stx +7 -0
  196. package/resources/components/Docs/HomeContributors.stx +23 -0
  197. package/resources/components/Docs/HomeSponsors.stx +17 -0
  198. package/resources/components/Docs/HomeTeam.stx +18 -0
  199. package/resources/components/Docs/TeamMember.stx +79 -0
  200. package/resources/components/Email/EmailButton.stx +32 -0
  201. package/resources/components/Email/EmailDivider.stx +20 -0
  202. package/resources/components/Email/EmailImage.stx +24 -0
  203. package/resources/components/Email/EmailLayout.stx +55 -0
  204. package/resources/components/Email/EmailLink.stx +22 -0
  205. package/resources/components/Email/EmailSection.stx +20 -0
  206. package/resources/components/Email/EmailText.stx +30 -0
  207. package/resources/components/Forum/ForumBreadcrumb.stx +38 -0
  208. package/resources/components/Forum/ForumCategory.stx +16 -0
  209. package/resources/components/Forum/ForumCategoryItem.stx +46 -0
  210. package/resources/components/Forum/ForumLayout.stx +36 -0
  211. package/resources/components/Forum/ForumPagination.stx +39 -0
  212. package/resources/components/Forum/ForumPost.stx +71 -0
  213. package/resources/components/Forum/ForumReplyForm.stx +76 -0
  214. package/resources/components/Forum/ForumSidebar.stx +86 -0
  215. package/resources/components/Forum/ForumTopicItem.stx +77 -0
  216. package/resources/components/Forum/ForumTopicList.stx +23 -0
  217. package/resources/components/HelloWorld.stx +253 -0
  218. package/resources/components/Logo.stx +10 -0
  219. package/resources/components/Marketing/CallToAction.stx +30 -0
  220. package/resources/components/Marketing/ComingSoon.stx +155 -0
  221. package/resources/components/Marketing/Faqs.stx +99 -0
  222. package/resources/components/Marketing/Feature.stx +32 -0
  223. package/resources/components/Marketing/Fields.stx +28 -0
  224. package/resources/components/Marketing/Footer.stx +33 -0
  225. package/resources/components/Marketing/Header.stx +51 -0
  226. package/resources/components/Marketing/Hero.stx +46 -0
  227. package/resources/components/Marketing/Layout.stx +26 -0
  228. package/resources/components/Marketing/NavLink.stx +13 -0
  229. package/resources/components/Marketing/Plan.stx +43 -0
  230. package/resources/components/Marketing/Pricing.stx +120 -0
  231. package/resources/components/Marketing/PrimaryFeatures.stx +80 -0
  232. package/resources/components/Marketing/PrimaryFeatures2.stx +98 -0
  233. package/resources/components/Marketing/SecondaryFeatures.stx +80 -0
  234. package/resources/components/Marketing/Testimonials.stx +120 -0
  235. package/resources/components/Pagination.stx +149 -0
  236. package/resources/components/Playground.stx +9 -0
  237. package/resources/components/README.md +87 -0
  238. package/resources/components/Storefront/AnnouncementBar.stx +17 -0
  239. package/resources/components/Storefront/CartDrawer.stx +227 -0
  240. package/resources/components/Storefront/CheckoutSteps.stx +50 -0
  241. package/resources/components/Storefront/Footer.stx +81 -0
  242. package/resources/components/Storefront/Header.stx +66 -0
  243. package/resources/components/Storefront/OrderSummary.stx +79 -0
  244. package/resources/components/Storefront/ProductCard.stx +63 -0
  245. package/resources/components/Storefront/ProductGallery.stx +88 -0
  246. package/resources/components/Storefront/QuantitySelector.stx +97 -0
  247. package/resources/components/index.ts +13 -0
  248. package/resources/emails/email-verification.stx +46 -0
  249. package/resources/emails/layouts/base.html +113 -0
  250. package/resources/emails/password-changed.stx +55 -0
  251. package/resources/emails/password-reset.stx +43 -0
  252. package/resources/emails/subscription-confirmation.stx +99 -0
  253. package/resources/emails/welcome.stx +48 -0
  254. package/resources/functions/README.md +28 -0
  255. package/resources/functions/counter.ts +13 -0
  256. package/resources/functions/dark.ts +4 -0
  257. package/resources/functions/dashboard/analytics.ts +238 -0
  258. package/resources/functions/dashboard/config-io.ts +316 -0
  259. package/resources/functions/dashboard/data.ts +375 -0
  260. package/resources/functions/dashboard/library.ts +250 -0
  261. package/resources/functions/dashboard/sidebar.ts +537 -0
  262. package/resources/functions/dashboard/system.ts +150 -0
  263. package/resources/layouts/403.stx +188 -0
  264. package/resources/layouts/404.stx +34 -0
  265. package/resources/layouts/README.md +14 -0
  266. package/resources/layouts/dashboard/default.stx +20 -0
  267. package/resources/layouts/dashboard/guest.stx +10 -0
  268. package/resources/layouts/default.stx +3 -0
  269. package/resources/layouts/maintenance.stx +11 -0
  270. package/resources/layouts/storefront.stx +73 -0
  271. package/resources/layouts/system-tray/default.stx +3 -0
  272. package/resources/modules/.gitkeep +0 -0
  273. package/resources/plugins/.gitkeep +0 -0
  274. package/resources/plugins/preloader.ts +308 -0
  275. package/resources/types/README.md +3 -0
  276. package/resources/views/cart.stx +149 -0
  277. package/resources/views/checkout/contact.stx +101 -0
  278. package/resources/views/checkout/payment.stx +114 -0
  279. package/resources/views/checkout/shipping.stx +120 -0
  280. package/resources/views/coming-soon.stx +9 -0
  281. package/resources/views/dashboard/custom-page.stx +45 -0
  282. package/resources/views/dashboard/index.stx +24 -0
  283. package/resources/views/emails/welcome.stx +0 -0
  284. package/resources/views/errors/tester.stx +26 -0
  285. package/resources/views/index.stx +2865 -0
  286. package/resources/views/orders/[id].stx +130 -0
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Main Preloader
3
+ *
4
+ * This file is loaded before the main (Bun) process is started.
5
+ * You may use this file to preload/define plugins that will
6
+ * automatically be injected into the Bun process.
7
+ */
8
+
9
+ // Skip preloader for fast CLI commands (e.g. `buddy dev`, `buddy --version`) to
10
+ // maximize startup speed. We must NOT skip when running a server script directly
11
+ // (e.g. `bun --watch storage/framework/core/actions/src/dev/api.ts`) — Bun
12
+ // consumes `--watch` so `args` ends up empty in that subprocess, which used to
13
+ // trip the `args.length === 0` short-circuit and silently disable auto-imports.
14
+ const args = process.argv.slice(2)
15
+ const fastCommands = [
16
+ 'dev',
17
+ 'build',
18
+ 'test',
19
+ 'lint',
20
+ '--version',
21
+ '-v',
22
+ 'version',
23
+ '--help',
24
+ '-h',
25
+ 'help',
26
+ // Database / codegen — must not pull the full auto-import graph (router,
27
+ // orm models, …) before bun-query-builder can diff schemas. A broken
28
+ // `@stacksjs/bun-router` install used to make `generate:migrations` exit 1
29
+ // with no output because the preloader died while loading `@stacksjs/router`.
30
+ 'migrate',
31
+ 'fresh',
32
+ 'seed',
33
+ 'generate',
34
+ 'make',
35
+ 'key:generate',
36
+ 'scaffold:crud',
37
+ ]
38
+ const isRepl = !process.argv[1]
39
+ const skipPreloader = isRepl || (args.length > 0 && fastCommands.some(cmd => args[0] === cmd || args[0].startsWith(`${cmd}:`)))
40
+
41
+ if (!skipPreloader) {
42
+ // Detect production/deployment commands and set environment accordingly BEFORE loading env files
43
+ // This ensures the correct .env.{env} file is loaded with proper encryption/decryption
44
+ const productionCommands = ['cloud:remove', 'cloud:rm', 'cloud:destroy', 'cloud:cleanup', 'cloud:clean-up', 'undeploy']
45
+ const isProductionCommand = productionCommands.includes(args[0])
46
+
47
+ // Handle deploy command which can have an optional env argument: `deploy [env]`
48
+ const isDeployCommand = args[0] === 'deploy'
49
+ if (isDeployCommand) {
50
+ // Check if second arg is an environment (not a flag starting with -)
51
+ const deployEnv = args[1] && !args[1].startsWith('-') ? args[1] : 'production'
52
+ process.env.APP_ENV = deployEnv
53
+ process.env.NODE_ENV = deployEnv
54
+ }
55
+ else if (isProductionCommand) {
56
+ process.env.APP_ENV = 'production'
57
+ process.env.NODE_ENV = 'production'
58
+ }
59
+
60
+ // Load .env files with encryption support using our native Bun plugin
61
+ const { autoLoadEnv } = await import('@stacksjs/env')
62
+
63
+ // Auto-load .env files based on environment
64
+ // Set quiet: true to prevent duplicate logging across multiple processes
65
+ //
66
+ // keysFile MUST be passed here: autoLoadEnv only resolves a decryption
67
+ // private key from a keys FILE when explicitly told which one to read —
68
+ // without it, an encrypted .env.production (DOTENV_PUBLIC_KEY_PRODUCTION
69
+ // + `encrypted:...` values) loads with every encrypted value left as raw
70
+ // ciphertext in process.env, silently breaking anything that reads
71
+ // process.env.SOME_SECRET directly (e.g. deploy-time credentials like
72
+ // HCLOUD_TOKEN/PORKBUN_API_KEY) with no error — it just looks like a
73
+ // bogus/expired credential downstream.
74
+ autoLoadEnv({ quiet: true, keysFile: '.env.keys' })
75
+ }
76
+
77
+ // stx template engine plugin
78
+ // enables .stx file processing
79
+ // NOTE: Commented out until bun-plugin-stx is properly installed
80
+ // Uncomment after running: bun add bun-plugin-stx
81
+ // eslint-disable-next-line antfu/no-top-level-await
82
+ // await import('bun-plugin-stx')
83
+
84
+ // Auto-import ALL Stacks framework modules into globalThis
85
+ // This allows using Action, response, Activity, etc. without ANY imports.
86
+ // Exported so server entrypoints (e.g. `dev/api.ts`) can opt back in
87
+ // explicitly when needed — see #1835 root cause 3.
88
+ export async function loadAutoImports() {
89
+ const { Glob } = await import('bun')
90
+ const path = await import('@stacksjs/path')
91
+
92
+ // CRITICAL: Never overwrite these built-in globals
93
+ const protectedGlobals = new Set([
94
+ 'process', 'globalThis', 'global', 'window', 'self',
95
+ 'console', 'require', 'module', 'exports', '__dirname', '__filename',
96
+ 'Buffer', 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
97
+ 'setImmediate', 'clearImmediate', 'queueMicrotask',
98
+ 'fetch', 'Request', 'Response', 'Headers', 'URL', 'URLSearchParams',
99
+ 'TextEncoder', 'TextDecoder', 'Blob', 'File', 'FormData',
100
+ 'crypto', 'performance', 'navigator', 'location',
101
+ 'Promise', 'Symbol', 'Proxy', 'Reflect', 'WeakMap', 'WeakSet', 'Map', 'Set',
102
+ 'Array', 'Object', 'String', 'Number', 'Boolean', 'Date', 'RegExp', 'Error',
103
+ 'JSON', 'Math', 'Intl', 'eval', 'isNaN', 'isFinite', 'parseInt', 'parseFloat',
104
+ 'encodeURI', 'encodeURIComponent', 'decodeURI', 'decodeURIComponent',
105
+ 'Bun', 'Deno', 'Node',
106
+ ])
107
+
108
+ // 1. Load Stacks framework packages into globalThis
109
+ const stacksPackages = [
110
+ '@stacksjs/actions',
111
+ '@stacksjs/router',
112
+ '@stacksjs/orm',
113
+ '@stacksjs/validation',
114
+ '@stacksjs/strings',
115
+ '@stacksjs/arrays',
116
+ '@stacksjs/objects',
117
+ '@stacksjs/collections',
118
+ '@stacksjs/path',
119
+ '@stacksjs/storage',
120
+ '@stacksjs/env',
121
+ '@stacksjs/config',
122
+ '@stacksjs/logging',
123
+ '@stacksjs/cache',
124
+ '@stacksjs/queue',
125
+ '@stacksjs/events',
126
+ '@stacksjs/notifications',
127
+ '@stacksjs/email',
128
+ '@stacksjs/security',
129
+ '@stacksjs/auth',
130
+ '@stacksjs/database',
131
+ '@stacksjs/error-handling',
132
+ // Signal helpers (`state`, `derived`, `effect`) and browser-side
133
+ // composables (`useDark`, `usePreferredDark`, `useStorage`) need to
134
+ // land in globalThis before step 2 imports any file under
135
+ // resources/functions/ — counter.ts and dark.ts call those at
136
+ // module top level, so missing globals throw and leave the module
137
+ // in TDZ, surfacing later as `Cannot access 'count' before
138
+ // initialization` when the auto-imports barrel re-imports them.
139
+ '@stacksjs/stx',
140
+ '@stacksjs/browser',
141
+ ]
142
+
143
+ for (const pkg of stacksPackages) {
144
+ try {
145
+ const module = await import(pkg)
146
+ for (const [name, value] of Object.entries(module)) {
147
+ // Skip default exports and protected globals
148
+ if (name === 'default' || protectedGlobals.has(name)) continue
149
+ if (typeof value !== 'undefined') {
150
+ (globalThis as any)[name] = value
151
+ }
152
+ }
153
+ } catch {
154
+ // Package might not exist or not be built yet
155
+ }
156
+ }
157
+
158
+ // 2. Load all functions from resources/functions
159
+ const functionsPath = path.resourcesPath('functions')
160
+ const glob = new Glob('**/*.ts')
161
+
162
+ for await (const file of glob.scan({
163
+ cwd: functionsPath,
164
+ absolute: true,
165
+ onlyFiles: true,
166
+ })) {
167
+ if (file.endsWith('.d.ts')) continue
168
+
169
+ try {
170
+ const module = await import(file)
171
+ for (const [name, value] of Object.entries(module)) {
172
+ // Skip default exports and protected globals
173
+ if (name === 'default' || protectedGlobals.has(name)) continue
174
+ if (typeof value !== 'undefined') {
175
+ (globalThis as any)[name] = value
176
+ }
177
+ }
178
+ } catch {
179
+ // Some files may have client-side dependencies, skip them
180
+ }
181
+ }
182
+
183
+ // 3. Load all defineModel()-based model instances into globalThis
184
+ // This enables using Post.where('title', 'test') without imports
185
+ // Priority: user models (app/Models) override framework defaults
186
+ const modelDirs = [
187
+ path.userModelsPath(),
188
+ path.storagePath('framework/defaults/app/Models'),
189
+ ]
190
+
191
+ const loadedModels = new Set<string>()
192
+
193
+ for (const dir of modelDirs) {
194
+ try {
195
+ for await (const file of glob.scan({
196
+ cwd: dir,
197
+ absolute: true,
198
+ onlyFiles: true,
199
+ })) {
200
+ if (file.endsWith('.d.ts') || file.endsWith('/index.ts')) continue
201
+
202
+ const modelName = file.split('/').pop()?.replace('.ts', '') || ''
203
+ if (!modelName || loadedModels.has(modelName) || protectedGlobals.has(modelName)) continue
204
+
205
+ try {
206
+ const module = await import(file)
207
+ if (module.default) {
208
+ (globalThis as any)[modelName] = module.default
209
+ loadedModels.add(modelName)
210
+ }
211
+ } catch {
212
+ // Model may have unresolved dependencies during bootstrap
213
+ }
214
+ }
215
+ } catch {
216
+ // Directory may not exist
217
+ }
218
+ }
219
+
220
+ // 4. Load all Job instances from app/Jobs into globalThis
221
+ // This enables using SendWelcomeEmail.dispatch() without imports
222
+ const jobsDir = path.userJobsPath()
223
+ const loadedJobs = new Set<string>()
224
+
225
+ try {
226
+ for await (const file of glob.scan({
227
+ cwd: jobsDir,
228
+ absolute: true,
229
+ onlyFiles: true,
230
+ })) {
231
+ if (file.endsWith('.d.ts') || file.endsWith('/index.ts')) continue
232
+
233
+ const jobName = file.split('/').pop()?.replace('.ts', '') || ''
234
+ if (!jobName || loadedJobs.has(jobName) || protectedGlobals.has(jobName)) continue
235
+
236
+ try {
237
+ const module = await import(file)
238
+ if (module.default) {
239
+ (globalThis as any)[jobName] = module.default
240
+ loadedJobs.add(jobName)
241
+ }
242
+ } catch {
243
+ // Job may have unresolved dependencies during bootstrap
244
+ }
245
+ }
246
+ } catch {
247
+ // Directory may not exist
248
+ }
249
+
250
+ // 5. Load all Controller classes into globalThis
251
+ // This enables using ComingSoonController without imports
252
+ // Priority: user controllers > default controllers
253
+ const controllerDirs = [
254
+ path.userControllersPath(),
255
+ path.storagePath('framework/defaults/app/Controllers'),
256
+ ]
257
+ const loadedControllers = new Set<string>()
258
+
259
+ for (const dir of controllerDirs) {
260
+ try {
261
+ for await (const file of glob.scan({
262
+ cwd: dir,
263
+ absolute: true,
264
+ onlyFiles: true,
265
+ })) {
266
+ if (file.endsWith('.d.ts') || file.endsWith('/index.ts')) continue
267
+
268
+ const controllerName = file.split('/').pop()?.replace('.ts', '') || ''
269
+ if (!controllerName || loadedControllers.has(controllerName) || protectedGlobals.has(controllerName)) continue
270
+
271
+ try {
272
+ const module = await import(file)
273
+ if (module.default) {
274
+ (globalThis as any)[controllerName] = module.default
275
+ loadedControllers.add(controllerName)
276
+ }
277
+ } catch {
278
+ // Controller may have unresolved dependencies during bootstrap
279
+ }
280
+ }
281
+ } catch {
282
+ // Directory may not exist
283
+ }
284
+ }
285
+ }
286
+
287
+ // Load auto-imports for server/API contexts (serve, any server process)
288
+ // Skip for fast commands (dev, build, test, etc.) and CLI info commands.
289
+ // `args[0]` may be undefined when running a script directly (e.g. dev subprocess);
290
+ // guard so .includes() doesn't accidentally treat that as a CLI info command.
291
+ // `./buddy dev` server subprocesses set STACKS_DEV_SERVER=1. They load only
292
+ // what they need themselves — the API injects globals via injectGlobalAutoImports
293
+ // and reads the cached package-discovery manifest, while the frontend/docs
294
+ // servers never touch models — so the preloader's eager ~800ms auto-import +
295
+ // discoverPackages pass is redundant work on the critical boot path. Skip it.
296
+ const skipAutoImports = skipPreloader || process.env.STACKS_DEV_SERVER === '1' || (args.length > 0 && ['--version', '-v', 'version', '--help', '-h', 'help'].includes(args[0]))
297
+ if (!skipAutoImports) {
298
+ await loadAutoImports()
299
+
300
+ // Run package auto-discovery after all imports are loaded
301
+ try {
302
+ const { discoverPackages } = await import('@stacksjs/actions')
303
+ await discoverPackages()
304
+ }
305
+ catch {
306
+ // Discovery may fail during early bootstrap — not critical
307
+ }
308
+ }
@@ -0,0 +1,3 @@
1
+ # The Types Folder
2
+
3
+ Any type you export in this namespace will automatically be available without import throughout your application.
@@ -0,0 +1,149 @@
1
+ @extends('layouts/storefront')
2
+
3
+ @section('title', 'Your cart')
4
+
5
+ <script server>
6
+ const Database = require('bun:sqlite').Database
7
+ const path = require('path')
8
+
9
+ const dbPath = path.resolve(process.cwd(), process.env.DB_DATABASE_PATH || 'database/stacks.sqlite')
10
+ const db = new Database(dbPath, { readonly: true })
11
+
12
+ const token = (typeof requestContext !== 'undefined') ? requestContext.cookie('stacks_cart') : null
13
+ let items = []
14
+ let cart = null
15
+
16
+ if (token) {
17
+ cart = db.query(`SELECT * FROM carts WHERE session_token = ?1 AND status = 'active' LIMIT 1`).get(token)
18
+ if (cart) {
19
+ items = db.query(`
20
+ SELECT ci.id, ci.quantity, ci.unit_price, ci.total_price, ci.product_name,
21
+ ci.product_image, ci.product_sku, p.weight_grams
22
+ FROM cart_items ci
23
+ LEFT JOIN products p ON p.slug = ci.product_sku
24
+ WHERE ci.cart_id = ?1
25
+ ORDER BY ci.id ASC
26
+ `).all(cart.id).map((row) => {
27
+ const qty = Number(row.quantity)
28
+ const price = Number(row.unit_price)
29
+ const lineTotal = Number(row.total_price)
30
+ return {
31
+ id: row.id,
32
+ slug: row.product_sku,
33
+ name: row.product_name,
34
+ weight: row.weight_grams ? `${row.weight_grams}g` : '',
35
+ qty,
36
+ priceLabel: `$${price.toFixed(2)}`,
37
+ lineTotal,
38
+ lineTotalLabel: `$${lineTotal.toFixed(2)}`,
39
+ image: row.product_image,
40
+ }
41
+ })
42
+ }
43
+ }
44
+
45
+ // Mirror the rule used by PlaceOrderAction so the price the shopper
46
+ // sees in their cart matches the total they're actually charged. Both
47
+ // sides read STOREFRONT_FREE_SHIPPING_THRESHOLD / STOREFRONT_FLAT_SHIPPING
48
+ // from the environment with the same defaults — keep them in sync via
49
+ // app/Actions/Storefront/_shipping.ts when changing.
50
+ const FREE_SHIPPING_THRESHOLD = Number(process.env.STOREFRONT_FREE_SHIPPING_THRESHOLD ?? 40) || 40
51
+ const FLAT_SHIPPING = Number(process.env.STOREFRONT_FLAT_SHIPPING ?? 5) || 5
52
+ const subtotal = items.reduce((sum, i) => sum + i.lineTotal, 0)
53
+ const shipping = subtotal <= 0 ? 0 : (subtotal >= FREE_SHIPPING_THRESHOLD ? 0 : FLAT_SHIPPING)
54
+ const total = subtotal + shipping
55
+ const remainingForFree = Math.max(0, FREE_SHIPPING_THRESHOLD - subtotal)
56
+
57
+ // Pre-format every numeric so the OrderSummary component template doesn't
58
+ // have to call .toFixed() on a defineProps local — STX's SSR pass doesn't
59
+ // reliably expose those locals, so callers do the formatting.
60
+ const subtotalLabel = `$${subtotal.toFixed(2)}`
61
+ const shippingLabel = shipping === 0 ? 'Free' : `$${shipping.toFixed(2)}`
62
+ const totalLabel = `$${total.toFixed(2)}`
63
+ const freeShippingNote = (shipping > 0 && remainingForFree > 0)
64
+ ? `Add $${remainingForFree.toFixed(2)} more for free shipping.`
65
+ : ''
66
+ </script>
67
+
68
+ @section('content')
69
+ <div class="mx-auto px-6 py-12 max-w-5xl">
70
+
71
+ <p class="font-medium text-stone-500 text-xs tracking-wider uppercase">Your bowl</p>
72
+ <h1 class="mt-2 font-bold text-4xl text-stone-900 tracking-tight">Cart</h1>
73
+ <p class="mt-2 text-stone-600">{{ items.length }} item{{ items.length === 1 ? '' : 's' }}{{ items.length > 0 ? ' ready to ship' : '' }}.</p>
74
+
75
+ @if (items.length === 0)
76
+ <div class="mt-12 p-12 md:p-16 text-center bg-stone-50 border border-dashed border-stone-300 rounded-3xl">
77
+ <div class="inline-flex items-center justify-center mx-auto h-14 w-14 bg-stone-100 rounded-full">
78
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7 text-stone-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 00-3 3h15.75m-12.75-3h11.218c.51 0 .956-.343 1.087-.835l1.872-7.024A1.125 1.125 0 0019.797 5.25H5.106M7.5 14.25L5.106 5.25M6 20.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm12.75 0a.75.75 0 11-1.5 0 .75.75 0 011.5 0z" /></svg>
79
+ </div>
80
+ <p class="mt-5 font-medium text-base text-stone-700">Your cart is empty.</p>
81
+ <p class="mt-1 text-sm text-stone-500">Pick a treat and we'll start your bowl.</p>
82
+ <a href="/products" class="inline-flex gap-2 items-center mt-6 px-6 py-3 font-semibold text-sm text-stone-50 bg-stone-900 hover:bg-stone-800 rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-stone-50 focus-visible:ring-stone-900 transition-colors">
83
+ Browse the shop
84
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" /></svg>
85
+ </a>
86
+ </div>
87
+ @else
88
+ <div class="grid gap-10 items-start lg:gap-12 lg:grid-cols-[2fr_1fr] mt-10">
89
+
90
+ <div class="space-y-4">
91
+ @foreach (items as item)
92
+ <article class="flex gap-4 p-4 bg-stone-50 border border-stone-200 rounded-2xl hover:border-stone-300 transition-colors">
93
+ <a
94
+ href="/products/{{ item.slug }}"
95
+ class="block overflow-hidden flex-shrink-0 h-24 w-24 bg-stone-200 rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-stone-50 focus-visible:ring-stone-900"
96
+ aria-label="View {{ item.name }}"
97
+ >
98
+ <img src="{{ item.image }}" alt="" class="object-cover h-full w-full">
99
+ </a>
100
+ <div class="flex flex-1 flex-col min-w-0">
101
+ <div class="flex gap-3 items-start justify-between">
102
+ <div class="min-w-0">
103
+ <a href="/products/{{ item.slug }}" class="block font-semibold text-stone-900 truncate hover:underline">{{ item.name }}</a>
104
+ @if (item.weight)
105
+ <p class="mt-0.5 text-stone-500 text-xs">{{ item.weight }} · {{ item.priceLabel }} each</p>
106
+ @else
107
+ <p class="mt-0.5 text-stone-500 text-xs">{{ item.priceLabel }} each</p>
108
+ @endif
109
+ </div>
110
+ <p class="font-semibold text-stone-900 whitespace-nowrap">{{ item.lineTotalLabel }}</p>
111
+ </div>
112
+ <div class="flex gap-3 items-end justify-between mt-auto pt-3">
113
+ <form action="/api/cart/update" method="POST" class="inline-flex overflow-hidden items-center border border-stone-300 rounded-full" data-cart-row>
114
+ <input type="hidden" name="item_id" value="{{ item.id }}">
115
+ <button type="submit" name="quantity" value="{{ item.qty - 1 }}" class="px-3 py-1.5 text-stone-600 hover:text-stone-900 focus-visible:bg-stone-100 hover:bg-stone-100 focus-visible:outline-none transition-colors" aria-label="Decrease quantity">
116
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14"/></svg>
117
+ </button>
118
+ <span class="px-2 min-w-[1.5rem] font-semibold tabular-nums text-center text-sm text-stone-900">{{ item.qty }}</span>
119
+ <button type="submit" name="quantity" value="{{ item.qty + 1 }}" class="px-3 py-1.5 text-stone-600 hover:text-stone-900 focus-visible:bg-stone-100 hover:bg-stone-100 focus-visible:outline-none transition-colors" aria-label="Increase quantity">
120
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14m-7-7h14"/></svg>
121
+ </button>
122
+ </form>
123
+ <form action="/api/cart/update" method="POST">
124
+ <input type="hidden" name="item_id" value="{{ item.id }}">
125
+ <input type="hidden" name="quantity" value="0">
126
+ <button type="submit" class="font-medium text-stone-500 text-xs underline-offset-4 focus-visible:text-stone-900 focus-visible:underline hover:text-stone-900 hover:underline focus-visible:outline-none transition-colors" aria-label="Remove {{ item.name }}">Remove</button>
127
+ </form>
128
+ </div>
129
+ </div>
130
+ </article>
131
+ @endforeach
132
+ </div>
133
+
134
+ <OrderSummary
135
+ subtotalLabel="{{ subtotalLabel }}"
136
+ shippingLabel="{{ shippingLabel }}"
137
+ totalLabel="{{ totalLabel }}"
138
+ freeShippingNote="{{ freeShippingNote }}"
139
+ ctaHref="/checkout/contact"
140
+ ctaLabel="Checkout"
141
+ secondaryHref="/products"
142
+ secondaryLabel="Keep shopping"
143
+ :sticky="true"
144
+ />
145
+
146
+ </div>
147
+ @endif
148
+ </div>
149
+ @endsection
@@ -0,0 +1,101 @@
1
+ @extends('layouts/storefront')
2
+
3
+ @section('title', 'Checkout — Contact')
4
+
5
+ <script server>
6
+ const Database = require('bun:sqlite').Database
7
+ const path = require('path')
8
+
9
+ const dbPath = path.resolve(process.cwd(), process.env.DB_DATABASE_PATH || 'database/stacks.sqlite')
10
+ const db = new Database(dbPath, { readonly: true })
11
+
12
+ const token = (typeof requestContext !== 'undefined') ? requestContext.cookie('stacks_cart') : null
13
+ let items = []
14
+ let cart = null
15
+
16
+ if (token) {
17
+ cart = db.query(`SELECT * FROM carts WHERE session_token = ?1 AND status = 'active' LIMIT 1`).get(token)
18
+ if (cart) {
19
+ items = db.query(`
20
+ SELECT product_name, quantity, total_price
21
+ FROM cart_items WHERE cart_id = ?1 ORDER BY id ASC
22
+ `).all(cart.id).map((row) => {
23
+ const qty = Number(row.quantity)
24
+ const lineTotal = Number(row.total_price)
25
+ return {
26
+ name: row.product_name,
27
+ qty,
28
+ lineTotal,
29
+ lineTotalLabel: `$${lineTotal.toFixed(2)}`,
30
+ }
31
+ })
32
+ }
33
+ }
34
+
35
+ // Mirror the rule in PlaceOrderAction's _shipping helper so the running
36
+ // totals on every checkout step match what gets charged.
37
+ const FREE_SHIPPING_THRESHOLD = Number(process.env.STOREFRONT_FREE_SHIPPING_THRESHOLD ?? 40) || 40
38
+ const FLAT_SHIPPING = Number(process.env.STOREFRONT_FLAT_SHIPPING ?? 5) || 5
39
+ const subtotal = items.reduce((s, i) => s + i.lineTotal, 0)
40
+ const shipping = subtotal <= 0 ? 0 : (subtotal >= FREE_SHIPPING_THRESHOLD ? 0 : FLAT_SHIPPING)
41
+ const total = subtotal + shipping
42
+ const remainingForFree = Math.max(0, FREE_SHIPPING_THRESHOLD - subtotal)
43
+
44
+ const subtotalLabel = `$${subtotal.toFixed(2)}`
45
+ const shippingLabel = shipping === 0 ? 'Free' : `$${shipping.toFixed(2)}`
46
+ const totalLabel = `$${total.toFixed(2)}`
47
+ const freeShippingNote = (shipping > 0 && remainingForFree > 0)
48
+ ? `Add $${remainingForFree.toFixed(2)} more for free shipping.`
49
+ : ''
50
+
51
+ const prefilledEmail = cart?.email || ''
52
+ </script>
53
+
54
+ @section('content')
55
+ <div class="mx-auto px-6 py-12 max-w-5xl">
56
+ <CheckoutSteps current="contact" />
57
+
58
+ @if (items.length === 0)
59
+ <div class="p-12 text-center border border-dashed border-stone-300 rounded-3xl">
60
+ <p class="text-stone-500">Your cart is empty.</p>
61
+ <a href="/products" class="inline-flex mt-6 px-6 py-3 font-semibold text-sm text-stone-50 bg-stone-900 hover:bg-stone-800 rounded-full">Browse the shop</a>
62
+ </div>
63
+ @else
64
+ <div class="grid gap-10 items-start md:grid-cols-[1fr_360px]">
65
+ <div>
66
+ <h1 class="font-bold text-3xl text-stone-900 tracking-tight">Contact</h1>
67
+ <p class="mt-2 text-stone-600">We'll send your receipt and tracking here.</p>
68
+
69
+ <form action="/api/checkout/contact" method="POST" class="mt-8 space-y-5">
70
+ <div>
71
+ <label class="font-semibold text-stone-500 text-xs tracking-wider uppercase">Email</label>
72
+ <input
73
+ type="email"
74
+ name="email"
75
+ required
76
+ autocomplete="email"
77
+ value="{{ prefilledEmail }}"
78
+ class="mt-1 px-4 py-3 w-full text-sm border border-stone-300 rounded-2xl focus:border-stone-900 focus:outline-none"
79
+ >
80
+ </div>
81
+ <div class="flex gap-4 items-center justify-between">
82
+ <a href="/cart" class="text-sm text-stone-500 hover:text-stone-900">← Back to cart</a>
83
+ <button type="submit" class="px-6 py-3 font-semibold text-sm text-stone-50 bg-stone-900 hover:bg-stone-800 rounded-full transition-colors">
84
+ Continue to shipping
85
+ </button>
86
+ </div>
87
+ </form>
88
+ </div>
89
+
90
+ <OrderSummary
91
+ :items="items"
92
+ subtotalLabel="{{ subtotalLabel }}"
93
+ shippingLabel="{{ shippingLabel }}"
94
+ totalLabel="{{ totalLabel }}"
95
+ freeShippingNote="{{ freeShippingNote }}"
96
+ :showItems="true"
97
+ />
98
+ </div>
99
+ @endif
100
+ </div>
101
+ @endsection