appos 0.6.0-0 → 0.7.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/dist/alert-BdX0Zt8k.js +103 -0
  2. package/dist/animated-check-CKu20goQ.js +68 -0
  3. package/dist/api/auth.d.mts +4 -0
  4. package/dist/api/auth.mjs +276 -0
  5. package/dist/api/cache.d.mts +3 -0
  6. package/dist/api/cache.mjs +28 -0
  7. package/dist/{exports/cli/index.d.mts → api/cli.d.mts} +8 -7
  8. package/dist/{exports/cli/index.mjs → api/cli.mjs} +46 -56
  9. package/dist/api/container.d.mts +6 -0
  10. package/dist/api/container.mjs +52 -0
  11. package/dist/api/database.d.mts +5 -0
  12. package/dist/api/database.mjs +8 -0
  13. package/dist/api/event.d.mts +6 -0
  14. package/dist/api/event.mjs +5 -0
  15. package/dist/api/instrumentation.d.mts +4 -0
  16. package/dist/api/instrumentation.mjs +11 -0
  17. package/dist/api/mailer.d.mts +6 -0
  18. package/dist/api/mailer.mjs +114 -0
  19. package/dist/api/observability.d.mts +4 -0
  20. package/dist/api/observability.mjs +79 -0
  21. package/dist/api/openapi.d.mts +6 -0
  22. package/dist/api/openapi.mjs +5 -0
  23. package/dist/api/server.d.mts +6 -0
  24. package/dist/api/server.mjs +8 -0
  25. package/dist/{exports/web/routes.d.mts → api/ssr.d.mts} +26 -11
  26. package/dist/{exports/web/routes.mjs → api/ssr.mjs} +24 -28
  27. package/dist/api/storage.d.mts +6 -0
  28. package/dist/{exports/api/index.mjs → api/storage.mjs} +77 -736
  29. package/dist/api/worker.d.mts +26 -0
  30. package/dist/api/worker.mjs +3 -0
  31. package/dist/api/workflow.d.mts +6 -0
  32. package/dist/api/workflow.mjs +7 -0
  33. package/dist/app-context-Cossa4Qc.mjs +3 -0
  34. package/dist/auth-BBivVOI9.mjs +26 -0
  35. package/dist/{exports/web/index.d.ts → auth-CmsO5ob5.d.ts} +6657 -9434
  36. package/dist/auth-D0zoZI7U.d.mts +5145 -0
  37. package/dist/auth-schema-OUnjUQlj.mjs +385 -0
  38. package/dist/badge-BFQXkO9d.js +49 -0
  39. package/dist/brand-C669gH_G.d.ts +88 -0
  40. package/dist/brand-CjbfdIEo.js +114 -0
  41. package/dist/button-CBH7xJ8q.js +81 -0
  42. package/dist/cache-jHw6mJPK.d.mts +75 -0
  43. package/dist/card-X792kQrC.js +154 -0
  44. package/dist/checkbox-e3A3glfd.js +33 -0
  45. package/dist/{exports/constants-BicCnEiJ.mjs → constants-DCwXUedR.mjs} +40 -6
  46. package/dist/container-xweZOaov.d.mts +2842 -0
  47. package/dist/context-9Yd81kh5.mjs +13 -0
  48. package/dist/context-La08hSVU.js +45 -0
  49. package/dist/database-Ca_pujXd.d.mts +102 -0
  50. package/dist/database-DSEtnffO.mjs +220 -0
  51. package/dist/{exports/storybook/index.d.ts → devtools/storybook.d.ts} +1 -1
  52. package/dist/{exports/storybook/index.js → devtools/storybook.js} +1 -1
  53. package/dist/devtools/test-mock.mjs +3 -0
  54. package/dist/{exports/tests/setup.mjs → devtools/test-setup.mjs} +1 -1
  55. package/dist/{exports/tests/api.d.mts → devtools/test.d.mts} +16 -6
  56. package/dist/{exports/tests/api.mjs → devtools/test.mjs} +30 -15
  57. package/dist/{exports/vite/index.d.mts → devtools/vite.d.mts} +65 -6
  58. package/dist/{exports/vite/index.mjs → devtools/vite.mjs} +157 -6
  59. package/dist/empty-BonqCObb.js +61 -0
  60. package/dist/env-C-0yH_Q3.mjs +26 -0
  61. package/dist/event-1yFQJHwn.mjs +236 -0
  62. package/dist/field-7rMKJCeh.js +115 -0
  63. package/dist/input-D9PbuBOa.js +27 -0
  64. package/dist/input-otp-zHrdocki.js +48 -0
  65. package/dist/{exports/instrumentation-Dqv_rRlR.mjs → instrumentation-DCouyaIn.mjs} +1 -1
  66. package/dist/label-C0h_-ojZ.js +26 -0
  67. package/dist/logger-rlLu_iK1.d.mts +20 -0
  68. package/dist/observability-Bd2pNUXs.d.mts +43 -0
  69. package/dist/openapi-DVd0_Ppp.mjs +467 -0
  70. package/dist/panel-Cy7DsMUA.mjs +57 -0
  71. package/dist/panel-D1XK_PR5.mjs +5 -0
  72. package/dist/redis-a5sw5J3L.mjs +41 -0
  73. package/dist/routes-BB8_4xq3.mjs +1123 -0
  74. package/dist/routes-Dv-T8LMT.mjs +4 -0
  75. package/dist/separator-DDbWY6ol.js +28 -0
  76. package/dist/server-CWYF5Oeg.mjs +1673 -0
  77. package/dist/spinner-CaEB5f1z.js +28 -0
  78. package/dist/textarea-CFblOAyj.js +25 -0
  79. package/dist/universal/auth.d.ts +139 -0
  80. package/dist/universal/auth.js +108 -0
  81. package/dist/universal/config.d.ts +47 -0
  82. package/dist/universal/config.js +128 -0
  83. package/dist/use-mobile-Dg2CI44J.js +19 -0
  84. package/dist/utils-4n921m5r.js +52 -0
  85. package/dist/utils-NKi1RiLK.d.ts +50 -0
  86. package/dist/web/auth.d.ts +4 -0
  87. package/dist/web/auth.js +88 -0
  88. package/dist/web/hooks.d.ts +4 -0
  89. package/dist/web/hooks.js +3 -0
  90. package/dist/web/i18n.d.ts +76 -0
  91. package/dist/web/i18n.js +58 -0
  92. package/dist/web/router.d.ts +3 -0
  93. package/dist/web/router.js +4 -0
  94. package/dist/web/ui/accordion.d.ts +79 -0
  95. package/dist/web/ui/accordion.js +112 -0
  96. package/dist/web/ui/alert-dialog.d.ts +200 -0
  97. package/dist/web/ui/alert-dialog.js +239 -0
  98. package/dist/web/ui/alert.d.ts +84 -0
  99. package/dist/web/ui/alert.js +4 -0
  100. package/dist/web/ui/animated-check.d.ts +38 -0
  101. package/dist/web/ui/animated-check.js +6 -0
  102. package/dist/web/ui/aspect-ratio.d.ts +26 -0
  103. package/dist/web/ui/aspect-ratio.js +28 -0
  104. package/dist/web/ui/auth.d.ts +4 -0
  105. package/dist/web/ui/auth.js +3432 -0
  106. package/dist/web/ui/avatar.d.ts +115 -0
  107. package/dist/web/ui/avatar.js +134 -0
  108. package/dist/web/ui/badge.d.ts +32 -0
  109. package/dist/web/ui/badge.js +4 -0
  110. package/dist/web/ui/brand.d.ts +3 -0
  111. package/dist/web/ui/brand.js +6 -0
  112. package/dist/web/ui/breadcrumb.d.ts +130 -0
  113. package/dist/web/ui/breadcrumb.js +166 -0
  114. package/dist/web/ui/button-group.d.ts +28 -0
  115. package/dist/web/ui/button-group.js +43 -0
  116. package/dist/web/ui/button.d.ts +83 -0
  117. package/dist/web/ui/button.js +6 -0
  118. package/dist/web/ui/calendar.d.ts +26 -0
  119. package/dist/web/ui/calendar.js +107 -0
  120. package/dist/web/ui/card.d.ts +134 -0
  121. package/dist/web/ui/card.js +4 -0
  122. package/dist/web/ui/carousel.d.ts +56 -0
  123. package/dist/web/ui/carousel.js +135 -0
  124. package/dist/web/ui/chart.d.ts +90 -0
  125. package/dist/web/ui/chart.js +142 -0
  126. package/dist/web/ui/checkbox.d.ts +22 -0
  127. package/dist/web/ui/checkbox.js +6 -0
  128. package/dist/web/ui/collapsible.d.ts +15 -0
  129. package/dist/web/ui/collapsible.js +27 -0
  130. package/dist/web/ui/command.d.ts +55 -0
  131. package/dist/web/ui/command.js +93 -0
  132. package/dist/web/ui/context-menu.d.ts +80 -0
  133. package/dist/web/ui/context-menu.js +133 -0
  134. package/dist/web/ui/dialog.d.ts +169 -0
  135. package/dist/web/ui/dialog.js +212 -0
  136. package/dist/web/ui/drawer.d.ts +44 -0
  137. package/dist/web/ui/drawer.js +80 -0
  138. package/dist/web/ui/dropdown-menu.d.ts +84 -0
  139. package/dist/web/ui/dropdown-menu.js +137 -0
  140. package/dist/web/ui/empty.d.ts +36 -0
  141. package/dist/web/ui/empty.js +4 -0
  142. package/dist/web/ui/error-page.d.ts +32 -0
  143. package/dist/web/ui/error-page.js +87 -0
  144. package/dist/web/ui/field.d.ts +67 -0
  145. package/dist/web/ui/field.js +8 -0
  146. package/dist/web/ui/hover-card.d.ts +20 -0
  147. package/dist/web/ui/hover-card.js +39 -0
  148. package/dist/web/ui/input-group.d.ts +45 -0
  149. package/dist/web/ui/input-group.js +81 -0
  150. package/dist/web/ui/input-otp.d.ts +28 -0
  151. package/dist/web/ui/input-otp.js +6 -0
  152. package/dist/web/ui/input.d.ts +22 -0
  153. package/dist/web/ui/input.js +4 -0
  154. package/dist/web/ui/item.d.ts +61 -0
  155. package/dist/web/ui/item.js +122 -0
  156. package/dist/web/ui/kbd.d.ts +14 -0
  157. package/dist/web/ui/kbd.js +21 -0
  158. package/dist/web/ui/label.d.ts +22 -0
  159. package/dist/web/ui/label.js +6 -0
  160. package/dist/web/ui/menubar.d.ts +80 -0
  161. package/dist/web/ui/menubar.js +136 -0
  162. package/dist/web/ui/navigation-menu.d.ts +46 -0
  163. package/dist/web/ui/navigation-menu.js +84 -0
  164. package/dist/web/ui/pagination.d.ts +131 -0
  165. package/dist/web/ui/pagination.js +171 -0
  166. package/dist/web/ui/popover.d.ts +33 -0
  167. package/dist/web/ui/popover.js +57 -0
  168. package/dist/web/ui/progress.d.ts +74 -0
  169. package/dist/web/ui/progress.js +93 -0
  170. package/dist/web/ui/radio-group.d.ts +15 -0
  171. package/dist/web/ui/radio-group.js +31 -0
  172. package/dist/web/ui/resizable.d.ts +20 -0
  173. package/dist/web/ui/resizable.js +31 -0
  174. package/dist/web/ui/scroll-area.d.ts +16 -0
  175. package/dist/web/ui/scroll-area.js +39 -0
  176. package/dist/web/ui/select.d.ts +167 -0
  177. package/dist/web/ui/select.js +211 -0
  178. package/dist/web/ui/separator.d.ts +23 -0
  179. package/dist/web/ui/separator.js +6 -0
  180. package/dist/web/ui/sheet.d.ts +42 -0
  181. package/dist/web/ui/sheet.js +91 -0
  182. package/dist/web/ui/sidebar.d.ts +160 -0
  183. package/dist/web/ui/sidebar.js +382 -0
  184. package/dist/web/ui/skeleton.d.ts +22 -0
  185. package/dist/web/ui/skeleton.js +26 -0
  186. package/dist/web/ui/slider.d.ts +26 -0
  187. package/dist/web/ui/slider.js +55 -0
  188. package/dist/web/ui/sonner.d.ts +9 -0
  189. package/dist/web/ui/sonner.js +33 -0
  190. package/dist/web/ui/spinner.d.ts +22 -0
  191. package/dist/web/ui/spinner.js +4 -0
  192. package/dist/web/ui/switch.d.ts +25 -0
  193. package/dist/web/ui/switch.js +34 -0
  194. package/dist/web/ui/table.d.ts +38 -0
  195. package/dist/web/ui/table.js +69 -0
  196. package/dist/web/ui/tabs.d.ts +84 -0
  197. package/dist/web/ui/tabs.js +103 -0
  198. package/dist/web/ui/textarea.d.ts +21 -0
  199. package/dist/web/ui/textarea.js +4 -0
  200. package/dist/web/ui/toggle-group.d.ts +28 -0
  201. package/dist/web/ui/toggle-group.js +55 -0
  202. package/dist/web/ui/toggle.d.ts +32 -0
  203. package/dist/web/ui/toggle.js +53 -0
  204. package/dist/web/ui/tooltip.d.ts +72 -0
  205. package/dist/web/ui/tooltip.js +91 -0
  206. package/dist/worker-D4L3BmuS.mjs +24 -0
  207. package/dist/{exports/send-email-CXxlkfFL.mjs → workflow-BUI7kC5c.mjs} +118 -765
  208. package/package.json +382 -90
  209. package/src/devtools/panel/index.ts +114 -0
  210. package/src/devtools/panel/modules/emails/compatibility.ts +289 -0
  211. package/src/devtools/panel/modules/emails/discovery.ts +242 -0
  212. package/src/devtools/panel/modules/emails/linter.ts +501 -0
  213. package/src/devtools/panel/modules/emails/render.ts +155 -0
  214. package/src/devtools/panel/modules/emails/routes.ts +502 -0
  215. package/src/devtools/panel/modules/emails/schema.ts +82 -0
  216. package/src/devtools/panel/modules/emails/spam-checker.ts +231 -0
  217. package/src/{storybook → devtools/storybook}/.storybook/main.ts +12 -4
  218. package/src/{storybook → devtools/storybook}/.storybook/manager.ts +1 -1
  219. package/src/{storybook → devtools/storybook}/.storybook/preview.tsx +7 -1
  220. package/src/{storybook → devtools/storybook}/docs/Introduction.mdx +3 -1
  221. package/src/{web/client/auth-paths.ts → universal/auth.ts} +54 -6
  222. package/src/universal/config.test.ts +473 -0
  223. package/src/universal/config.ts +205 -0
  224. package/src/universal/date.ts +1 -0
  225. package/src/universal/locales/en/ui.json +232 -0
  226. package/src/universal/locales/zh-CN/ui.json +232 -0
  227. package/src/universal/locales/zh-TW/ui.json +232 -0
  228. package/src/universal/toolkit.ts +1 -0
  229. package/src/universal/zod.ts +1 -0
  230. package/src/web/auth.ts +6 -0
  231. package/src/web/client/auth.ts +6 -11
  232. package/src/web/client/i18n.d.ts +2 -0
  233. package/src/web/client/i18n.ts +6 -1
  234. package/src/web/devtools/index.ts +1 -0
  235. package/src/web/devtools/modules/dashboard.tsx +151 -0
  236. package/src/web/devtools/modules/emails.tsx +1338 -0
  237. package/src/web/devtools/overlay.tsx +109 -0
  238. package/src/web/devtools/panel.tsx +353 -0
  239. package/src/web/font/index.ts +1 -3
  240. package/src/web/hooks.ts +4 -0
  241. package/src/web/i18n.ts +11 -0
  242. package/src/web/index.ts +1 -2
  243. package/src/web/router.ts +5 -0
  244. package/src/web/routes/auth/_layout.tsx +17 -15
  245. package/src/web/routes/auth/email-otp.tsx +2 -2
  246. package/src/web/routes/auth/forgot-password.tsx +1 -1
  247. package/src/web/routes/auth/login.tsx +3 -2
  248. package/src/web/routes/auth/phone-otp.tsx +2 -2
  249. package/src/web/routes/auth/reset-password.tsx +3 -7
  250. package/src/web/routes/auth/signup.tsx +2 -2
  251. package/src/web/routes/auth/utils.ts +21 -10
  252. package/src/web/routes/auth/verify-email.tsx +2 -2
  253. package/src/web/routes.ts +4 -9
  254. package/src/web/ui/alert-dialog.stories.tsx +2 -2
  255. package/src/web/ui/auth/auth-layout.stories.tsx +81 -72
  256. package/src/web/ui/auth/auth-layout.tsx +70 -138
  257. package/src/web/ui/auth/brand-content.stories.tsx +272 -0
  258. package/src/web/ui/auth/brand-content.tsx +431 -0
  259. package/src/web/ui/auth/context.tsx +2 -2
  260. package/src/web/ui/auth/hooks.ts +1 -1
  261. package/src/web/ui/auth/index.ts +24 -1
  262. package/src/web/ui/auth.ts +4 -0
  263. package/src/web/ui/checkbox.stories.tsx +2 -1
  264. package/src/web/ui/collapsible.stories.tsx +2 -2
  265. package/src/web/ui/command.stories.tsx +1 -1
  266. package/src/web/ui/context-menu.stories.tsx +1 -1
  267. package/src/web/ui/dialog.stories.tsx +4 -4
  268. package/src/web/ui/drawer.stories.tsx +4 -4
  269. package/src/web/ui/dropdown-menu.stories.tsx +2 -2
  270. package/src/web/ui/empty.stories.tsx +2 -2
  271. package/src/web/ui/error-page.stories.tsx +1 -1
  272. package/src/web/ui/error-page.tsx +1 -1
  273. package/src/web/ui/field.stories.tsx +5 -6
  274. package/src/web/ui/globals.css +2 -1
  275. package/src/web/ui/hover-card.stories.tsx +3 -5
  276. package/src/web/ui/input-group.stories.tsx +2 -2
  277. package/src/web/ui/input-otp.stories.tsx +1 -1
  278. package/src/web/ui/input.stories.tsx +2 -1
  279. package/src/web/ui/item.stories.tsx +3 -3
  280. package/src/web/ui/kbd.stories.tsx +1 -1
  281. package/src/web/ui/label.stories.tsx +4 -1
  282. package/src/web/ui/locales/en/devtools.json +102 -0
  283. package/src/web/ui/locales/zh-CN/devtools.json +102 -0
  284. package/src/web/ui/locales/zh-TW/devtools.json +102 -0
  285. package/src/web/ui/menubar.stories.tsx +1 -1
  286. package/src/web/ui/navigation-menu.stories.tsx +1 -1
  287. package/src/web/ui/navigation-menu.tsx +3 -3
  288. package/src/web/ui/pagination.stories.tsx +1 -1
  289. package/src/web/ui/popover.stories.tsx +4 -4
  290. package/src/web/ui/progress.stories.tsx +1 -1
  291. package/src/web/ui/radio-group.stories.tsx +3 -4
  292. package/src/web/ui/resizable.stories.tsx +1 -1
  293. package/src/web/ui/scroll-area.stories.tsx +2 -1
  294. package/src/web/ui/select.stories.tsx +1 -1
  295. package/src/web/ui/sheet.stories.tsx +4 -4
  296. package/src/web/ui/sidebar.stories.tsx +1 -1
  297. package/src/web/ui/sidebar.tsx +1 -1
  298. package/src/web/ui/skeleton.stories.tsx +1 -1
  299. package/src/web/ui/slider.stories.tsx +1 -1
  300. package/src/web/ui/sonner.stories.tsx +2 -1
  301. package/src/web/ui/spinner.stories.tsx +2 -1
  302. package/src/web/ui/switch.stories.tsx +2 -1
  303. package/src/web/ui/table.stories.tsx +3 -3
  304. package/src/web/ui/tabs.stories.tsx +5 -8
  305. package/src/web/ui/textarea.stories.tsx +3 -1
  306. package/src/web/ui/toggle.stories.tsx +1 -1
  307. package/src/web/ui/tooltip.stories.tsx +2 -2
  308. package/dist/exports/api/index.d.mts +0 -5
  309. package/dist/exports/api/orm-seed.d.mts +0 -1
  310. package/dist/exports/api/orm-seed.mjs +0 -3
  311. package/dist/exports/api/orm.d.mts +0 -3
  312. package/dist/exports/api/orm.mjs +0 -5
  313. package/dist/exports/api/workflows/index.d.mts +0 -74
  314. package/dist/exports/api/workflows/index.mjs +0 -4
  315. package/dist/exports/app-context-B1VJ9qnH.mjs +0 -3
  316. package/dist/exports/auth-BCOIpGDO.d.mts +0 -870
  317. package/dist/exports/index-Di4PdhuL.d.mts +0 -7174
  318. package/dist/exports/instrumentation.d.mts +0 -2
  319. package/dist/exports/instrumentation.mjs +0 -5
  320. package/dist/exports/mock-DLfalkIV.mjs +0 -9
  321. package/dist/exports/openapi-uisUTLq7.mjs +0 -1483
  322. package/dist/exports/orm-D-7F2n1J.d.mts +0 -10
  323. package/dist/exports/orm-DbH3_5aw.mjs +0 -36
  324. package/dist/exports/server-cD8Pckgj.mjs +0 -509
  325. package/dist/exports/ssr-BsfNjYlJ.mjs +0 -16
  326. package/dist/exports/tests/mock.mjs +0 -5
  327. package/dist/exports/tests/react.d.mts +0 -2
  328. package/dist/exports/tests/react.mjs +0 -5
  329. package/dist/exports/web/index.js +0 -8178
  330. package/dist/exports/web/ssr.d.mts +0 -20
  331. package/dist/exports/web/ssr.mjs +0 -3
  332. /package/dist/{exports/app-context-LF4QmPUC.mjs → app-context-CaxDuPj-.mjs} +0 -0
  333. /package/dist/{exports/chunk-DCbLExaX.mjs → chunk-BkPCcwIn.mjs} +0 -0
  334. /package/dist/{exports/tests/mock.d.mts → devtools/test-mock.d.mts} +0 -0
  335. /package/dist/{exports/tests/setup.d.mts → devtools/test-setup.d.mts} +0 -0
  336. /package/dist/{exports/instrumentation-CFIspF8-.d.mts → instrumentation-DhJYpza5.d.mts} +0 -0
  337. /package/dist/{exports/vendors → universal}/date.d.ts +0 -0
  338. /package/dist/{exports/vendors → universal}/date.js +0 -0
  339. /package/dist/{exports/vendors → universal}/toolkit.d.ts +0 -0
  340. /package/dist/{exports/vendors → universal}/toolkit.js +0 -0
  341. /package/dist/{exports/vendors → universal}/zod.d.ts +0 -0
  342. /package/dist/{exports/vendors → universal}/zod.js +0 -0
  343. /package/dist/{exports/vite-compat-CICObU9F.mjs → vite-compat-El4psBQm.mjs} +0 -0
  344. /package/dist/{exports/youch-handler-CHwX0Fou.mjs → youch-handler-D951Exws.mjs} +0 -0
  345. /package/src/{storybook → devtools/storybook}/components/ColorGrid.tsx +0 -0
  346. /package/src/{storybook → devtools/storybook}/components/IconGallery.tsx +0 -0
  347. /package/src/{storybook → devtools/storybook}/components/SpacingScale.tsx +0 -0
  348. /package/src/{storybook → devtools/storybook}/components/TypographyScale.tsx +0 -0
  349. /package/src/{storybook → devtools/storybook}/components/index.ts +0 -0
  350. /package/src/{storybook → devtools/storybook}/docs/foundations/Colors.mdx +0 -0
  351. /package/src/{storybook → devtools/storybook}/docs/foundations/Icons.mdx +0 -0
  352. /package/src/{storybook → devtools/storybook}/docs/foundations/Spacing.mdx +0 -0
  353. /package/src/{storybook → devtools/storybook}/docs/foundations/Typography.mdx +0 -0
  354. /package/src/{storybook → devtools/storybook}/index.ts +0 -0
  355. /package/src/{storybook → devtools/storybook}/shims/void-elements.js +0 -0
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Spam checking module using Postmark SpamCheck API.
3
+ *
4
+ * Uses the free Postmark SpamAssassin API to detect spam patterns in emails.
5
+ * No API key required.
6
+ */
7
+
8
+ /**
9
+ * A single spam rule matched by SpamAssassin.
10
+ */
11
+ export interface SpamRule {
12
+ /**
13
+ * The SpamAssassin rule name.
14
+ */
15
+ rule: string;
16
+
17
+ /**
18
+ * Human-readable description of the rule.
19
+ */
20
+ description: string;
21
+
22
+ /**
23
+ * Points added to the spam score by this rule.
24
+ */
25
+ score: number;
26
+ }
27
+
28
+ /**
29
+ * Result of spam checking an email.
30
+ */
31
+ export interface SpamCheckResult {
32
+ /**
33
+ * Whether the check was successful.
34
+ */
35
+ success: boolean;
36
+
37
+ /**
38
+ * The total spam score (lower is better, typically 5+ is spam).
39
+ */
40
+ score: number;
41
+
42
+ /**
43
+ * List of SpamAssassin rules that matched.
44
+ */
45
+ rules: SpamRule[];
46
+
47
+ /**
48
+ * Time taken to check in milliseconds.
49
+ */
50
+ checkTime: number;
51
+
52
+ /**
53
+ * Error message if the check failed.
54
+ */
55
+ error?: string;
56
+ }
57
+
58
+ /**
59
+ * Postmark SpamCheck API response structure.
60
+ */
61
+ interface PostmarkSpamResponse {
62
+ success: boolean;
63
+ score: string;
64
+ rules: Array<{
65
+ score: string;
66
+ description: string;
67
+ }>;
68
+ report?: string;
69
+ }
70
+
71
+ /**
72
+ * Constructs a raw email message from HTML and text content.
73
+ *
74
+ * SpamAssassin requires a full email message with headers and body.
75
+ * This creates a minimal MIME message for analysis.
76
+ *
77
+ * @param html - The HTML content of the email.
78
+ * @param text - The plain text content of the email.
79
+ * @param subject - Optional subject line.
80
+ * @returns Raw email message string.
81
+ */
82
+ function constructRawEmail(
83
+ html: string,
84
+ text: string,
85
+ subject = "Test Email",
86
+ ): string {
87
+ const boundary = `----=_Part_${Date.now()}_${Math.random().toString(36).substring(2)}`;
88
+
89
+ const headers = [
90
+ "MIME-Version: 1.0",
91
+ "From: test@example.com",
92
+ "To: recipient@example.com",
93
+ `Subject: ${subject}`,
94
+ `Content-Type: multipart/alternative; boundary="${boundary}"`,
95
+ "",
96
+ ].join("\r\n");
97
+
98
+ const textPart = [
99
+ `--${boundary}`,
100
+ "Content-Type: text/plain; charset=utf-8",
101
+ "Content-Transfer-Encoding: quoted-printable",
102
+ "",
103
+ text,
104
+ ].join("\r\n");
105
+
106
+ const htmlPart = [
107
+ `--${boundary}`,
108
+ "Content-Type: text/html; charset=utf-8",
109
+ "Content-Transfer-Encoding: quoted-printable",
110
+ "",
111
+ html,
112
+ ].join("\r\n");
113
+
114
+ const closing = `--${boundary}--`;
115
+
116
+ return [headers, textPart, htmlPart, closing].join("\r\n");
117
+ }
118
+
119
+ /**
120
+ * Checks email content for spam patterns using Postmark SpamCheck API.
121
+ *
122
+ * Algorithm:
123
+ * 1. Construct a raw MIME email from HTML and text content.
124
+ * 2. Send to Postmark's free SpamCheck API.
125
+ * 3. Parse the response and extract rules.
126
+ * 4. Return structured result with score and matched rules.
127
+ *
128
+ * @param html - The HTML content of the email.
129
+ * @param text - The plain text content of the email.
130
+ * @param subject - Optional subject line for the test email.
131
+ * @returns Spam check result with score and matched rules.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * const result = await checkSpamScore(htmlContent, textContent);
136
+ * console.log(`Spam score: ${result.score}`);
137
+ * for (const rule of result.rules) {
138
+ * console.log(`[${rule.score}] ${rule.description}`);
139
+ * }
140
+ * ```
141
+ */
142
+ export async function checkSpamScore(
143
+ html: string,
144
+ text: string,
145
+ subject?: string,
146
+ ): Promise<SpamCheckResult> {
147
+ const start = performance.now();
148
+
149
+ try {
150
+ const rawEmail = constructRawEmail(html, text, subject);
151
+
152
+ const response = await fetch("https://spamcheck.postmarkapp.com/filter", {
153
+ method: "POST",
154
+ headers: {
155
+ "Content-Type": "application/json",
156
+ Accept: "application/json",
157
+ },
158
+ body: JSON.stringify({
159
+ email: rawEmail,
160
+ options: "long",
161
+ }),
162
+ });
163
+
164
+ if (!response.ok) {
165
+ return {
166
+ success: false,
167
+ score: 0,
168
+ rules: [],
169
+ checkTime: performance.now() - start,
170
+ error: `SpamCheck API returned ${response.status}`,
171
+ };
172
+ }
173
+
174
+ const data = (await response.json()) as PostmarkSpamResponse;
175
+
176
+ if (!data.success) {
177
+ return {
178
+ success: false,
179
+ score: 0,
180
+ rules: [],
181
+ checkTime: performance.now() - start,
182
+ error: "SpamCheck API returned unsuccessful response",
183
+ };
184
+ }
185
+
186
+ // Parse the rules from the report
187
+ const rules: SpamRule[] = data.rules.map((rule) => ({
188
+ rule: extractRuleName(rule.description),
189
+ description: cleanRuleDescription(rule.description),
190
+ score: Number.parseFloat(rule.score),
191
+ }));
192
+
193
+ return {
194
+ success: true,
195
+ score: Number.parseFloat(data.score),
196
+ rules,
197
+ checkTime: performance.now() - start,
198
+ };
199
+ } catch (error) {
200
+ return {
201
+ success: false,
202
+ score: 0,
203
+ rules: [],
204
+ checkTime: performance.now() - start,
205
+ error: error instanceof Error ? error.message : "Unknown error",
206
+ };
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Extracts the rule name from a SpamAssassin rule description.
212
+ *
213
+ * @param description - The full rule description.
214
+ * @returns The rule name or "UNKNOWN".
215
+ */
216
+ function extractRuleName(description: string): string {
217
+ // SpamAssassin rule names are usually the first word in uppercase
218
+ const match = /^([A-Z0-9_]+)/.exec(description.trim());
219
+ return match?.[1] ?? "UNKNOWN";
220
+ }
221
+
222
+ /**
223
+ * Cleans up a SpamAssassin rule description for display.
224
+ *
225
+ * @param description - The raw rule description.
226
+ * @returns Cleaned description.
227
+ */
228
+ function cleanRuleDescription(description: string): string {
229
+ // Remove the rule name prefix if present
230
+ return description.replace(/^[A-Z0-9_]+\s*/, "").trim();
231
+ }
@@ -11,17 +11,17 @@ import {
11
11
  getStoredFontsConfig,
12
12
  resolveFontConfig,
13
13
  viteFontPlugin,
14
- } from "appos/vite";
14
+ } from "appos/devtools/vite";
15
15
  import type { Plugin } from "vite";
16
16
  import { mergeConfig } from "vite";
17
17
  import {
18
18
  type ParsedTheme,
19
19
  parseThemeFromString,
20
- } from "../../web/lib/colors.ts";
20
+ } from "../../../web/lib/colors.ts";
21
21
 
22
22
  const __dirname = dirname(fileURLToPath(import.meta.url));
23
23
  const storybookDir = join(__dirname, "..");
24
- const apposRoot = join(__dirname, "../../..");
24
+ const apposRoot = join(__dirname, "../../../..");
25
25
  const appRoot = process.cwd();
26
26
  const appName = `${process.env.APP_NAME || "AppOS"} Design System`;
27
27
 
@@ -142,6 +142,14 @@ export default {
142
142
  })();
143
143
  window.STORYBOOK_THEME = ${JSON.stringify(buildStorybookTheme(theme))};
144
144
  window.STORYBOOK_BRAND_TITLE = '<img src="/logo.png" alt="" style="height: 28px; margin-right: 4px; vertical-align: middle;" />' + ${JSON.stringify(appName)};
145
+ </script>`,
146
+ previewHead: (head) => `${head}
147
+ <link rel="icon" href="/favicon.ico" />
148
+ <title>${appName}</title>
149
+ <style>${fontCss}</style>
150
+ <script>
151
+ window.STORYBOOK_THEME = ${JSON.stringify(buildStorybookTheme(theme))};
152
+ window.STORYBOOK_BRAND_TITLE = '<img src="/logo.png" alt="" style="height: 28px; margin-right: 4px; vertical-align: middle;" />' + ${JSON.stringify(appName)};
145
153
  </script>`,
146
154
  staticDirs: [join(appRoot, "public")],
147
155
  stories: [
@@ -187,8 +195,8 @@ window.STORYBOOK_BRAND_TITLE = '<img src="/logo.png" alt="" style="height: 28px;
187
195
  resolve: {
188
196
  alias: {
189
197
  "#api": join(appRoot, "api"),
190
- "#isomorphic": join(appRoot, "isomorphic"),
191
198
  "#src": join(apposRoot, "src"),
199
+ "#universal": join(appRoot, "universal"),
192
200
  "#web": join(appRoot, "web"),
193
201
  "void-elements": join(storybookDir, "shims/void-elements.js"),
194
202
  },
@@ -2,7 +2,7 @@ import { addons } from "storybook/manager-api";
2
2
  import { create } from "storybook/theming";
3
3
 
4
4
  /** Storybook theme configuration from CSS variables. */
5
- interface StorybookTheme {
5
+ export interface StorybookTheme {
6
6
  base: "light" | "dark";
7
7
  colorPrimary: string;
8
8
  colorSecondary: string;
@@ -5,8 +5,11 @@ import { withThemeByClassName } from "@storybook/addon-themes";
5
5
  import type { Preview, ReactRenderer } from "@storybook/react";
6
6
  import i18n from "i18next";
7
7
  import { I18nextProvider, initReactI18next } from "react-i18next";
8
+ import { create } from "storybook/theming";
8
9
  import { withRouter } from "storybook-addon-remix-react-router";
9
- import enUI from "../../web/ui/locales/en/ui.json";
10
+ import enUI from "../../../web/ui/locales/en/ui.json";
11
+ // Import to get Window.STORYBOOK_THEME declaration
12
+ import type {} from "./manager.ts";
10
13
 
11
14
  // Initialize i18n synchronously for Storybook with bundled translations.
12
15
  i18n.use(initReactI18next).init({
@@ -64,6 +67,9 @@ export default {
64
67
  * nothing. It can be removed once the bug is fixed.
65
68
  */
66
69
  container: DocsContainer,
70
+ theme: window.STORYBOOK_THEME
71
+ ? create(window.STORYBOOK_THEME)
72
+ : undefined,
67
73
  source: {
68
74
  type: "dynamic",
69
75
  excludeDecorators: true,
@@ -16,7 +16,9 @@ Explore foundations, components, and patterns that power your product.
16
16
  ## Usage
17
17
 
18
18
  ```tsx
19
- import { Button, Card, Input } from "appos/web";
19
+ import { Button } from "appos/web/ui/button";
20
+ import { Card } from "appos/web/ui/card";
21
+ import { Input } from "appos/web/ui/input";
20
22
 
21
23
  function MyComponent() {
22
24
  return (
@@ -1,13 +1,43 @@
1
1
  /**
2
- * Client-safe authentication path utilities.
3
- *
4
- * This module contains auth path configuration and redirect utilities that are
5
- * safe to import in client-side code (no Node.js APIs).
6
- *
7
- * For route building (uses Node.js APIs), see routes/auth/utils.ts.
2
+ * Universal auth constants and types - no Node.js or browser-specific APIs.
8
3
  */
9
4
  import { redirect } from "react-router";
10
5
 
6
+ /**
7
+ * Default base path for auth routes.
8
+ */
9
+ export const AUTH_BASE_PATH = "/auth" as const;
10
+
11
+ /**
12
+ * Default base URL (empty - same origin).
13
+ */
14
+ export const AUTH_BASE_URL = "" as const;
15
+
16
+ /**
17
+ * Array of all supported captcha providers.
18
+ * Use with z.enum() for config validation.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * CAPTCHA_PROVIDER: z.enum(captchaProviders).optional(),
23
+ * ```
24
+ */
25
+ export const captchaProviders = [
26
+ "captchafox",
27
+ "cloudflare-turnstile",
28
+ "google-recaptcha",
29
+ "hcaptcha",
30
+ ] as const;
31
+
32
+ /**
33
+ * Captcha provider type.
34
+ */
35
+ export type CaptchaProvider = (typeof captchaProviders)[number];
36
+
37
+ // ============================================================================
38
+ // Auth Paths
39
+ // ============================================================================
40
+
11
41
  /**
12
42
  * Configuration for authentication route paths.
13
43
  *
@@ -81,6 +111,10 @@ export const DEFAULT_AUTH_PATHS: AuthPaths = {
81
111
  emailOtp: "/email-login",
82
112
  };
83
113
 
114
+ // ============================================================================
115
+ // Auth Redirect Utilities
116
+ // ============================================================================
117
+
84
118
  /**
85
119
  * Creates a redirect response to the login page with the return URL preserved.
86
120
  *
@@ -146,3 +180,17 @@ export function definePostAuthRedirect(
146
180
  const redirectTo = url.searchParams.get("redirect") || fallbackPath;
147
181
  return redirect(redirectTo);
148
182
  }
183
+
184
+ // ============================================================================
185
+ // Auth Layout Types (used for config, no React runtime deps)
186
+ // ============================================================================
187
+
188
+ /**
189
+ * Available layout variants for authentication pages.
190
+ */
191
+ export const authLayoutVariants = ["centered", "split", "minimal"] as const;
192
+
193
+ /**
194
+ * Auth layout variant type.
195
+ */
196
+ export type AuthLayoutVariant = (typeof authLayoutVariants)[number];