@stone-js/starters 0.8.3

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 (352) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -0
  3. package/basic-react-declarative/LICENSE +21 -0
  4. package/basic-react-declarative/README.md +39 -0
  5. package/basic-react-declarative/app/Application.tsx +89 -0
  6. package/basic-react-declarative/assets/css/index.css +26 -0
  7. package/basic-react-declarative/package.json +39 -0
  8. package/basic-react-declarative/public/logo.png +0 -0
  9. package/basic-react-declarative/tests/Application.spec.ts +96 -0
  10. package/basic-react-declarative/tests/__snapshots__/Application.spec.ts.snap +3 -0
  11. package/basic-react-declarative/tsconfig.json +33 -0
  12. package/basic-react-declarative/vitest.config.ts +24 -0
  13. package/basic-react-imperative/LICENSE +21 -0
  14. package/basic-react-imperative/README.md +39 -0
  15. package/basic-react-imperative/app/Application.tsx +89 -0
  16. package/basic-react-imperative/assets/css/index.css +26 -0
  17. package/basic-react-imperative/package.json +39 -0
  18. package/basic-react-imperative/public/logo.png +0 -0
  19. package/basic-react-imperative/tests/Application.spec.ts +80 -0
  20. package/basic-react-imperative/tests/__snapshots__/Application.spec.ts.snap +3 -0
  21. package/basic-react-imperative/tsconfig.json +33 -0
  22. package/basic-react-imperative/vitest.config.ts +24 -0
  23. package/basic-service-declarative/LICENSE +21 -0
  24. package/basic-service-declarative/README.md +39 -0
  25. package/basic-service-declarative/app/Application.ts +56 -0
  26. package/basic-service-declarative/package.json +34 -0
  27. package/basic-service-declarative/tests/Application.spec.ts +60 -0
  28. package/basic-service-declarative/tsconfig.json +25 -0
  29. package/basic-service-declarative/vitest.config.ts +24 -0
  30. package/basic-service-imperative/LICENSE +21 -0
  31. package/basic-service-imperative/README.md +39 -0
  32. package/basic-service-imperative/app/Application.ts +60 -0
  33. package/basic-service-imperative/package.json +34 -0
  34. package/basic-service-imperative/tests/Application.spec.ts +52 -0
  35. package/basic-service-imperative/tsconfig.json +25 -0
  36. package/basic-service-imperative/vitest.config.ts +24 -0
  37. package/continuum-showcase/README.md +44 -0
  38. package/continuum-showcase/app/env.d.ts +34 -0
  39. package/continuum-showcase/app/layouts/MainLayout.tsx +20 -0
  40. package/continuum-showcase/app/pages/BlogPostPage.tsx +62 -0
  41. package/continuum-showcase/app/pages/HomePage.tsx +58 -0
  42. package/continuum-showcase/package.json +25 -0
  43. package/continuum-showcase/stone.config.mjs +20 -0
  44. package/full-react-declarative/.env.example +1 -0
  45. package/full-react-declarative/.env.public.example +1 -0
  46. package/full-react-declarative/LICENSE +21 -0
  47. package/full-react-declarative/README.md +39 -0
  48. package/full-react-declarative/app/Application.ts +85 -0
  49. package/full-react-declarative/app/clients/AxiosClient.ts +136 -0
  50. package/full-react-declarative/app/clients/CommentClient.ts +61 -0
  51. package/full-react-declarative/app/clients/PostClient.ts +90 -0
  52. package/full-react-declarative/app/clients/SecurityClient.ts +66 -0
  53. package/full-react-declarative/app/clients/UserClient.ts +97 -0
  54. package/full-react-declarative/app/components/ChangePasswordForm/ChangePasswordForm.tsx +50 -0
  55. package/full-react-declarative/app/components/CommentForm/CommentForm.tsx +37 -0
  56. package/full-react-declarative/app/components/CommentItem/CommentItem.tsx +42 -0
  57. package/full-react-declarative/app/components/CommentWidget/CommentWidget.tsx +95 -0
  58. package/full-react-declarative/app/components/LoginForm/LoginForm.css +0 -0
  59. package/full-react-declarative/app/components/LoginForm/LoginForm.tsx +71 -0
  60. package/full-react-declarative/app/components/PostDetails/PostDetails.tsx +44 -0
  61. package/full-react-declarative/app/components/PostForm/PostForm.css +0 -0
  62. package/full-react-declarative/app/components/PostForm/PostForm.tsx +47 -0
  63. package/full-react-declarative/app/components/PostItem/PostItem.css +0 -0
  64. package/full-react-declarative/app/components/PostItem/PostItem.tsx +34 -0
  65. package/full-react-declarative/app/components/RegisterForm/RegisterForm.tsx +110 -0
  66. package/full-react-declarative/app/components/UserForm/UserForm.tsx +47 -0
  67. package/full-react-declarative/app/configurations/AppConfiguration.ts +17 -0
  68. package/full-react-declarative/app/error-pages/DefaultErrorPage/DefaultErrorPage.css +0 -0
  69. package/full-react-declarative/app/error-pages/DefaultErrorPage/DefaultErrorPage.tsx +52 -0
  70. package/full-react-declarative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.css +0 -0
  71. package/full-react-declarative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.tsx +53 -0
  72. package/full-react-declarative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.css +0 -0
  73. package/full-react-declarative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.tsx +54 -0
  74. package/full-react-declarative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.css +0 -0
  75. package/full-react-declarative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.tsx +53 -0
  76. package/full-react-declarative/app/errors/ForbiddenError.ts +11 -0
  77. package/full-react-declarative/app/errors/PostNotFoundError.ts +11 -0
  78. package/full-react-declarative/app/errors/UnauthorizedError.ts +11 -0
  79. package/full-react-declarative/app/errors/UserNotFoundError.ts +11 -0
  80. package/full-react-declarative/app/events/UserEvent.ts +18 -0
  81. package/full-react-declarative/app/layout/AppLayout/AppLayout.css +20 -0
  82. package/full-react-declarative/app/layout/AppLayout/AppLayout.tsx +101 -0
  83. package/full-react-declarative/app/layout/ErrorLayout/ErrorLayout.css +0 -0
  84. package/full-react-declarative/app/layout/ErrorLayout/ErrorLayout.tsx +41 -0
  85. package/full-react-declarative/app/layout/SecurityLayout/SecurityLayout.css +0 -0
  86. package/full-react-declarative/app/layout/SecurityLayout/SecurityLayout.tsx +39 -0
  87. package/full-react-declarative/app/middleware/AuthMiddleware.ts +85 -0
  88. package/full-react-declarative/app/models/Comment.ts +31 -0
  89. package/full-react-declarative/app/models/Post.ts +22 -0
  90. package/full-react-declarative/app/models/User.ts +62 -0
  91. package/full-react-declarative/app/pages/home/HomePage.tsx +44 -0
  92. package/full-react-declarative/app/pages/login/LoginPage.css +0 -0
  93. package/full-react-declarative/app/pages/login/LoginPage.tsx +73 -0
  94. package/full-react-declarative/app/pages/posts/CreatePostPage/CreatePostPage.css +0 -0
  95. package/full-react-declarative/app/pages/posts/CreatePostPage/CreatePostPage.tsx +67 -0
  96. package/full-react-declarative/app/pages/posts/PostPage/PostPage.tsx +60 -0
  97. package/full-react-declarative/app/pages/posts/ShowPostPage/ShowPostPage.tsx +83 -0
  98. package/full-react-declarative/app/pages/posts/UpdatePostPage/UpdatePostPage.tsx +77 -0
  99. package/full-react-declarative/app/pages/register/RegisterPage.tsx +68 -0
  100. package/full-react-declarative/app/pages/users/CreateUserPage.tsx +48 -0
  101. package/full-react-declarative/app/pages/users/ShowUserPage.tsx +62 -0
  102. package/full-react-declarative/app/pages/users/UpdateUserPage.tsx +57 -0
  103. package/full-react-declarative/app/pages/users/UserPage.tsx +57 -0
  104. package/full-react-declarative/app/providers/AppServiceProvider.ts +43 -0
  105. package/full-react-declarative/app/services/CommentService.ts +59 -0
  106. package/full-react-declarative/app/services/PostService.ts +108 -0
  107. package/full-react-declarative/app/services/SecurityService.ts +80 -0
  108. package/full-react-declarative/app/services/TokenService.ts +116 -0
  109. package/full-react-declarative/app/services/UserService.ts +126 -0
  110. package/full-react-declarative/app/utils.ts +17 -0
  111. package/full-react-declarative/assets/css/index.css +301 -0
  112. package/full-react-declarative/assets/img/logo.png +0 -0
  113. package/full-react-declarative/package.json +46 -0
  114. package/full-react-declarative/public/logo.png +0 -0
  115. package/full-react-declarative/public/vite.svg +1 -0
  116. package/full-react-declarative/stone.config.mjs +12 -0
  117. package/full-react-declarative/tsconfig.json +29 -0
  118. package/full-react-declarative/vitest.config.ts +24 -0
  119. package/full-react-imperative/.env.example +1 -0
  120. package/full-react-imperative/.env.public.example +1 -0
  121. package/full-react-imperative/LICENSE +21 -0
  122. package/full-react-imperative/README.md +39 -0
  123. package/full-react-imperative/app/Application.ts +79 -0
  124. package/full-react-imperative/app/clients/AxiosClient.ts +124 -0
  125. package/full-react-imperative/app/clients/CommentClient.ts +57 -0
  126. package/full-react-imperative/app/clients/PostClient.ts +86 -0
  127. package/full-react-imperative/app/clients/SecurityClient.ts +60 -0
  128. package/full-react-imperative/app/clients/UserClient.ts +93 -0
  129. package/full-react-imperative/app/clients/contracts/IAxiosClient.ts +97 -0
  130. package/full-react-imperative/app/clients/contracts/ICommentClient.ts +31 -0
  131. package/full-react-imperative/app/clients/contracts/IPostClient.ts +55 -0
  132. package/full-react-imperative/app/clients/contracts/ISecurityClient.ts +33 -0
  133. package/full-react-imperative/app/clients/contracts/IUserClient.ts +61 -0
  134. package/full-react-imperative/app/components/ChangePasswordForm/ChangePasswordForm.tsx +50 -0
  135. package/full-react-imperative/app/components/CommentForm/CommentForm.css +35 -0
  136. package/full-react-imperative/app/components/CommentForm/CommentForm.tsx +45 -0
  137. package/full-react-imperative/app/components/CommentItem/CommentItem.css +74 -0
  138. package/full-react-imperative/app/components/CommentItem/CommentItem.tsx +62 -0
  139. package/full-react-imperative/app/components/CommentWidget/CommentWidget.css +25 -0
  140. package/full-react-imperative/app/components/CommentWidget/CommentWidget.tsx +119 -0
  141. package/full-react-imperative/app/components/Dropdown/Dropdown.css +52 -0
  142. package/full-react-imperative/app/components/Dropdown/Dropdown.tsx +40 -0
  143. package/full-react-imperative/app/components/LayoutHeader/LayoutHeader.css +62 -0
  144. package/full-react-imperative/app/components/LayoutHeader/LayoutHeader.tsx +61 -0
  145. package/full-react-imperative/app/components/LayoutLeftMenu/LayoutLeftMenu.css +25 -0
  146. package/full-react-imperative/app/components/LayoutLeftMenu/LayoutLeftMenu.tsx +32 -0
  147. package/full-react-imperative/app/components/LoginForm/LoginForm.css +0 -0
  148. package/full-react-imperative/app/components/LoginForm/LoginForm.tsx +71 -0
  149. package/full-react-imperative/app/components/NotificationBadge/NotificationBadge.css +41 -0
  150. package/full-react-imperative/app/components/NotificationBadge/NotificationBadge.tsx +63 -0
  151. package/full-react-imperative/app/components/PostCard/PostCard.css +129 -0
  152. package/full-react-imperative/app/components/PostCard/PostCard.tsx +65 -0
  153. package/full-react-imperative/app/components/PostForm/PostForm.css +92 -0
  154. package/full-react-imperative/app/components/PostForm/PostForm.tsx +76 -0
  155. package/full-react-imperative/app/components/PostSkeleton/PostSkeleton.css +65 -0
  156. package/full-react-imperative/app/components/PostSkeleton/PostSkeleton.tsx +25 -0
  157. package/full-react-imperative/app/components/PostWidget/PostWidget.tsx +95 -0
  158. package/full-react-imperative/app/components/ProfileForm/ProfileForm.css +84 -0
  159. package/full-react-imperative/app/components/ProfileForm/ProfileForm.tsx +79 -0
  160. package/full-react-imperative/app/components/RegisterForm/RegisterForm.tsx +110 -0
  161. package/full-react-imperative/app/components/RightAsidePanel/RightAsidePanel.css +32 -0
  162. package/full-react-imperative/app/components/RightAsidePanel/RightAsidePanel.tsx +62 -0
  163. package/full-react-imperative/app/components/SettingsForm/SettingsForm.css +126 -0
  164. package/full-react-imperative/app/components/SettingsForm/SettingsForm.tsx +86 -0
  165. package/full-react-imperative/app/components/UserAvatar/UserAvatar.css +18 -0
  166. package/full-react-imperative/app/components/UserAvatar/UserAvatar.tsx +60 -0
  167. package/full-react-imperative/app/components/UserBadge/UserBadge.css +33 -0
  168. package/full-react-imperative/app/components/UserBadge/UserBadge.tsx +49 -0
  169. package/full-react-imperative/app/components/UserCard/UserCard.css +70 -0
  170. package/full-react-imperative/app/components/UserCard/UserCard.tsx +43 -0
  171. package/full-react-imperative/app/configurations/AppConfiguration.ts +19 -0
  172. package/full-react-imperative/app/error-pages/DefaultErrorPage/DefaultErrorPage.css +0 -0
  173. package/full-react-imperative/app/error-pages/DefaultErrorPage/DefaultErrorPage.tsx +41 -0
  174. package/full-react-imperative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.css +0 -0
  175. package/full-react-imperative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.tsx +42 -0
  176. package/full-react-imperative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.css +0 -0
  177. package/full-react-imperative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.tsx +49 -0
  178. package/full-react-imperative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.css +0 -0
  179. package/full-react-imperative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.tsx +42 -0
  180. package/full-react-imperative/app/errors/ForbiddenError.ts +11 -0
  181. package/full-react-imperative/app/errors/PostNotFoundError.ts +11 -0
  182. package/full-react-imperative/app/errors/UnauthorizedError.ts +11 -0
  183. package/full-react-imperative/app/errors/UserNotFoundError.ts +11 -0
  184. package/full-react-imperative/app/events/UserEvent.ts +18 -0
  185. package/full-react-imperative/app/layout/AppLayout/AppLayout.css +106 -0
  186. package/full-react-imperative/app/layout/AppLayout/AppLayout.tsx +48 -0
  187. package/full-react-imperative/app/layout/ErrorLayout/ErrorLayout.css +0 -0
  188. package/full-react-imperative/app/layout/ErrorLayout/ErrorLayout.tsx +45 -0
  189. package/full-react-imperative/app/layout/SecurityLayout/SecurityLayout.css +0 -0
  190. package/full-react-imperative/app/layout/SecurityLayout/SecurityLayout.tsx +43 -0
  191. package/full-react-imperative/app/layout/SettingsLayout/SettingsLayout.css +99 -0
  192. package/full-react-imperative/app/layout/SettingsLayout/SettingsLayout.tsx +44 -0
  193. package/full-react-imperative/app/middleware/AuthMiddleware.ts +56 -0
  194. package/full-react-imperative/app/models/Comment.ts +35 -0
  195. package/full-react-imperative/app/models/Post.ts +27 -0
  196. package/full-react-imperative/app/models/User.ts +68 -0
  197. package/full-react-imperative/app/pages/Settings/SettingsPage.tsx +23 -0
  198. package/full-react-imperative/app/pages/home/HomePage.tsx +58 -0
  199. package/full-react-imperative/app/pages/login/LoginPage.css +0 -0
  200. package/full-react-imperative/app/pages/login/LoginPage.tsx +65 -0
  201. package/full-react-imperative/app/pages/posts/ShowPostPage/ShowPostPage.tsx +64 -0
  202. package/full-react-imperative/app/pages/posts/UpdatePostPage/UpdatePostPage.tsx +56 -0
  203. package/full-react-imperative/app/pages/register/RegisterPage.tsx +71 -0
  204. package/full-react-imperative/app/pages/users/ShowUserPage/ShowUserPage.css +64 -0
  205. package/full-react-imperative/app/pages/users/ShowUserPage/ShowUserPage.tsx +104 -0
  206. package/full-react-imperative/app/pages/users/UpdateUserPage/UpdateUserPage.css +0 -0
  207. package/full-react-imperative/app/pages/users/UpdateUserPage/UpdateUserPage.tsx +43 -0
  208. package/full-react-imperative/app/pages/users/UserPage/UserPage.css +31 -0
  209. package/full-react-imperative/app/pages/users/UserPage/UserPage.tsx +59 -0
  210. package/full-react-imperative/app/pages/utils.ts +67 -0
  211. package/full-react-imperative/app/providers/AppServiceProvider.ts +40 -0
  212. package/full-react-imperative/app/services/CommentService.ts +53 -0
  213. package/full-react-imperative/app/services/PostService.ts +102 -0
  214. package/full-react-imperative/app/services/SecurityService.ts +72 -0
  215. package/full-react-imperative/app/services/TokenService.ts +108 -0
  216. package/full-react-imperative/app/services/UserService.ts +115 -0
  217. package/full-react-imperative/app/services/contracts/ICommentService.ts +30 -0
  218. package/full-react-imperative/app/services/contracts/IPostService.ts +65 -0
  219. package/full-react-imperative/app/services/contracts/ISecurityService.ts +39 -0
  220. package/full-react-imperative/app/services/contracts/ITokenService.ts +44 -0
  221. package/full-react-imperative/app/services/contracts/IUserService.ts +70 -0
  222. package/full-react-imperative/app/utils.ts +31 -0
  223. package/full-react-imperative/assets/css/index.css +301 -0
  224. package/full-react-imperative/assets/img/logo.png +0 -0
  225. package/full-react-imperative/package.json +48 -0
  226. package/full-react-imperative/public/logo.png +0 -0
  227. package/full-react-imperative/public/vite.svg +1 -0
  228. package/full-react-imperative/stone.config.mjs +12 -0
  229. package/full-react-imperative/tsconfig.json +29 -0
  230. package/full-react-imperative/vitest.config.ts +24 -0
  231. package/full-service-declarative/.env.example +2 -0
  232. package/full-service-declarative/LICENSE +21 -0
  233. package/full-service-declarative/README.md +65 -0
  234. package/full-service-declarative/app/Application.ts +327 -0
  235. package/full-service-declarative/app/commands/ListSessionsCommand.ts +70 -0
  236. package/full-service-declarative/app/commands/ListUsersCommand.ts +56 -0
  237. package/full-service-declarative/app/configurations/AppConfiguration.ts +52 -0
  238. package/full-service-declarative/app/configurations/UserLiveConfiguration.ts +28 -0
  239. package/full-service-declarative/app/database/DatabaseClient.ts +43 -0
  240. package/full-service-declarative/app/database/schema.ts +43 -0
  241. package/full-service-declarative/app/error-handlers/SecurityErrorHandler.ts +61 -0
  242. package/full-service-declarative/app/errors/CredentialsError.ts +12 -0
  243. package/full-service-declarative/app/events/UserEvent.ts +17 -0
  244. package/full-service-declarative/app/handlers/CommentEventHandler.ts +103 -0
  245. package/full-service-declarative/app/handlers/PostEventHandler.ts +104 -0
  246. package/full-service-declarative/app/handlers/SecurityEventHandler.ts +108 -0
  247. package/full-service-declarative/app/handlers/UserEventHandler.ts +159 -0
  248. package/full-service-declarative/app/listeners/UserEventListener.ts +35 -0
  249. package/full-service-declarative/app/middleware/AuthMiddleware.ts +54 -0
  250. package/full-service-declarative/app/models/Comment.ts +38 -0
  251. package/full-service-declarative/app/models/Post.ts +50 -0
  252. package/full-service-declarative/app/models/Session.ts +14 -0
  253. package/full-service-declarative/app/models/User.ts +77 -0
  254. package/full-service-declarative/app/providers/DrizzleServiceProvider.ts +59 -0
  255. package/full-service-declarative/app/repositories/CommentRepository.ts +155 -0
  256. package/full-service-declarative/app/repositories/PostRepository.ts +138 -0
  257. package/full-service-declarative/app/repositories/SessionRepository.ts +123 -0
  258. package/full-service-declarative/app/repositories/UserRepository.ts +99 -0
  259. package/full-service-declarative/app/services/CommentService.ts +112 -0
  260. package/full-service-declarative/app/services/PostService.ts +100 -0
  261. package/full-service-declarative/app/services/SecurityService.ts +232 -0
  262. package/full-service-declarative/app/services/SessionService.ts +130 -0
  263. package/full-service-declarative/app/services/UserService.ts +110 -0
  264. package/full-service-declarative/app/subscribers/UserEventSubscriber.ts +38 -0
  265. package/full-service-declarative/drizzle.config.ts +13 -0
  266. package/full-service-declarative/package.json +48 -0
  267. package/full-service-declarative/stone.config.mjs +12 -0
  268. package/full-service-declarative/tsconfig.json +25 -0
  269. package/full-service-declarative/vitest.config.ts +24 -0
  270. package/full-service-imperative/.env.example +2 -0
  271. package/full-service-imperative/LICENSE +21 -0
  272. package/full-service-imperative/README.md +65 -0
  273. package/full-service-imperative/app/Application.ts +317 -0
  274. package/full-service-imperative/app/commands/ListSessionsCommand.ts +54 -0
  275. package/full-service-imperative/app/commands/ListUsersCommand.ts +42 -0
  276. package/full-service-imperative/app/configurations/AppConfiguration.ts +44 -0
  277. package/full-service-imperative/app/configurations/UserLiveConfiguration.ts +26 -0
  278. package/full-service-imperative/app/database/DatabaseClient.ts +39 -0
  279. package/full-service-imperative/app/database/schema.ts +43 -0
  280. package/full-service-imperative/app/error-handlers/SecurityErrorHandler.ts +58 -0
  281. package/full-service-imperative/app/errors/CredentialsError.ts +12 -0
  282. package/full-service-imperative/app/events/UserEvent.ts +17 -0
  283. package/full-service-imperative/app/handlers/CommentEventHandler.ts +99 -0
  284. package/full-service-imperative/app/handlers/PostEventHandler.ts +99 -0
  285. package/full-service-imperative/app/handlers/SecurityEventHandler.ts +83 -0
  286. package/full-service-imperative/app/handlers/UserEventHandler.ts +132 -0
  287. package/full-service-imperative/app/listeners/UserEventListener.ts +23 -0
  288. package/full-service-imperative/app/middleware/AuthMiddleware.ts +44 -0
  289. package/full-service-imperative/app/models/Comment.ts +38 -0
  290. package/full-service-imperative/app/models/Post.ts +50 -0
  291. package/full-service-imperative/app/models/Session.ts +14 -0
  292. package/full-service-imperative/app/models/User.ts +77 -0
  293. package/full-service-imperative/app/providers/DrizzleServiceProvider.ts +56 -0
  294. package/full-service-imperative/app/repositories/CommentRepository.ts +148 -0
  295. package/full-service-imperative/app/repositories/PostRepository.ts +130 -0
  296. package/full-service-imperative/app/repositories/SessionRepository.ts +115 -0
  297. package/full-service-imperative/app/repositories/UserRepository.ts +91 -0
  298. package/full-service-imperative/app/repositories/contracts/ICommentRepository.ts +72 -0
  299. package/full-service-imperative/app/repositories/contracts/IPostRepository.ts +63 -0
  300. package/full-service-imperative/app/repositories/contracts/ISessionRepository.ts +65 -0
  301. package/full-service-imperative/app/repositories/contracts/IUserRepository.ts +55 -0
  302. package/full-service-imperative/app/services/CommentService.ts +109 -0
  303. package/full-service-imperative/app/services/PostService.ts +97 -0
  304. package/full-service-imperative/app/services/SecurityService.ts +224 -0
  305. package/full-service-imperative/app/services/SessionService.ts +124 -0
  306. package/full-service-imperative/app/services/UserService.ts +105 -0
  307. package/full-service-imperative/app/services/contracts/ICommentService.ts +62 -0
  308. package/full-service-imperative/app/services/contracts/IPostService.ts +53 -0
  309. package/full-service-imperative/app/services/contracts/ISecurityService.ts +97 -0
  310. package/full-service-imperative/app/services/contracts/ISessionService.ts +73 -0
  311. package/full-service-imperative/app/services/contracts/IUserService.ts +57 -0
  312. package/full-service-imperative/app/subscribers/UserEventSubscriber.ts +28 -0
  313. package/full-service-imperative/drizzle.config.ts +13 -0
  314. package/full-service-imperative/package.json +48 -0
  315. package/full-service-imperative/stone.config.mjs +12 -0
  316. package/full-service-imperative/tsconfig.json +25 -0
  317. package/full-service-imperative/vitest.config.ts +24 -0
  318. package/package.json +225 -0
  319. package/standard-react-declarative/LICENSE +21 -0
  320. package/standard-react-declarative/README.md +39 -0
  321. package/standard-react-declarative/app/Application.ts +45 -0
  322. package/standard-react-declarative/app/pages/welcome/WelcomePage.tsx +57 -0
  323. package/standard-react-declarative/app/services/WelcomeService.ts +38 -0
  324. package/standard-react-declarative/assets/css/index.css +26 -0
  325. package/standard-react-declarative/package.json +42 -0
  326. package/standard-react-declarative/tsconfig.json +33 -0
  327. package/standard-react-declarative/vitest.config.ts +24 -0
  328. package/standard-react-imperative/LICENSE +21 -0
  329. package/standard-react-imperative/README.md +39 -0
  330. package/standard-react-imperative/app/Application.ts +41 -0
  331. package/standard-react-imperative/app/pages/welcome/WelcomePage.tsx +50 -0
  332. package/standard-react-imperative/app/services/WelcomeService.ts +38 -0
  333. package/standard-react-imperative/assets/css/index.css +26 -0
  334. package/standard-react-imperative/package.json +42 -0
  335. package/standard-react-imperative/tsconfig.json +33 -0
  336. package/standard-react-imperative/vitest.config.ts +24 -0
  337. package/standard-service-declarative/LICENSE +21 -0
  338. package/standard-service-declarative/README.md +39 -0
  339. package/standard-service-declarative/app/Application.ts +39 -0
  340. package/standard-service-declarative/app/handlers/WelcomeEventHandler.ts +45 -0
  341. package/standard-service-declarative/app/services/WelcomeService.ts +38 -0
  342. package/standard-service-declarative/package.json +36 -0
  343. package/standard-service-declarative/tsconfig.json +25 -0
  344. package/standard-service-declarative/vitest.config.ts +24 -0
  345. package/standard-service-imperative/LICENSE +21 -0
  346. package/standard-service-imperative/README.md +39 -0
  347. package/standard-service-imperative/app/Application.ts +11 -0
  348. package/standard-service-imperative/app/handlers/welcomeEventHandler.ts +31 -0
  349. package/standard-service-imperative/app/services/welcomeService.ts +38 -0
  350. package/standard-service-imperative/package.json +35 -0
  351. package/standard-service-imperative/tsconfig.json +25 -0
  352. package/standard-service-imperative/vitest.config.ts +24 -0
@@ -0,0 +1,224 @@
1
+ import bcrypt from 'bcryptjs'
2
+ import jwt from 'jsonwebtoken'
3
+ import { ISessionService } from './contracts/ISessionService'
4
+ import { ISecurityService } from './contracts/ISecurityService'
5
+ import { BadCredentialsError } from '../errors/CredentialsError'
6
+ import { IUserRepository } from '../repositories/contracts/IUserRepository'
7
+ import { defineService, IBlueprint, isEmpty, isNotEmpty } from '@stone-js/core'
8
+ import { BadRequestError, IncomingHttpEvent, UnauthorizedError } from '@stone-js/http-core'
9
+ import { UserLogin, UserToken, UserRegister, UserChangePassword, UserModel, UserTokenPayload } from '../models/User'
10
+
11
+ /**
12
+ * Security Service Options
13
+ */
14
+ export interface SecurityServiceOptions {
15
+ blueprint: IBlueprint
16
+ userRepository: IUserRepository
17
+ sessionService: ISessionService
18
+ }
19
+
20
+ /**
21
+ * Factory Security Service
22
+ */
23
+ export function factorySecurityService ({ blueprint, userRepository, sessionService }: SecurityServiceOptions): ISecurityService {
24
+ return {
25
+ /**
26
+ * Login a user
27
+ *
28
+ * @param credentials - The user to login
29
+ * @returns The user token
30
+ */
31
+ async login (event: IncomingHttpEvent, credentials: UserLogin): Promise<UserToken> {
32
+ const user = await userRepository.findBy(credentials)
33
+
34
+ if (isEmpty(user)) {
35
+ throw new BadCredentialsError(`The user with email ${credentials.email} does not exist`)
36
+ }
37
+
38
+ if (!(await this.comparePassword(credentials.password, user.password))) {
39
+ throw new BadCredentialsError('Invalid user password')
40
+ }
41
+
42
+ return {
43
+ tokenType: 'bearer',
44
+ expiresIn: blueprint.get<number>('security.jwt.expiresIn', 3600),
45
+ accessToken: await this.generateToken(user, event.ip, event.userAgent)
46
+ }
47
+ },
48
+
49
+ /**
50
+ * Refresh a token
51
+ *
52
+ * @param token - The token to refresh
53
+ */
54
+ async refresh (token: string): Promise<UserToken> {
55
+ const payload = this.verifyToken(token)
56
+ const user = await userRepository.findById(payload.user.id)
57
+
58
+ if (isEmpty(user)) {
59
+ throw new UnauthorizedError('User not found')
60
+ }
61
+
62
+ return {
63
+ tokenType: 'bearer',
64
+ expiresIn: blueprint.get<number>('security.jwt.expiresIn', 3600),
65
+ accessToken: await this.generateToken(user, payload.session.ip, payload.session.userAgent ?? undefined)
66
+ }
67
+ },
68
+
69
+ /**
70
+ * Logout a user
71
+ *
72
+ * @param token - The token to logout
73
+ */
74
+ async logout (token: string): Promise<void> {
75
+ const payload = this.verifyToken(token)
76
+ await sessionService.close(payload.session)
77
+ },
78
+
79
+ /**
80
+ * Authenticate a user
81
+ *
82
+ * @param token - The token to authenticate
83
+ * @returns The authenticated user
84
+ */
85
+ async authenticate (token: string, ip: string, userAgent?: string): Promise<UserModel> {
86
+ const payload = this.verifyToken(token)
87
+ const user = await userRepository.findById(payload.user.id)
88
+
89
+ if (payload.session.ip !== ip) {
90
+ throw new UnauthorizedError('Invalid IP address')
91
+ } else if (payload.session.userAgent !== userAgent) {
92
+ throw new UnauthorizedError('Invalid user agent')
93
+ } else if (isEmpty(user)) {
94
+ throw new UnauthorizedError('User not found')
95
+ }
96
+
97
+ await sessionService.updateLastActivity(payload.session)
98
+
99
+ return user
100
+ },
101
+
102
+ /**
103
+ * Hashes a password before storing it in the database.
104
+ *
105
+ * @param password - The plaintext password.
106
+ * @returns The hashed password.
107
+ */
108
+ async hashPassword (password: string): Promise<string> {
109
+ return await bcrypt.hash(password, blueprint.get<number>('security.bcrypt.saltRounds', 10))
110
+ },
111
+
112
+ /**
113
+ * Compares a plaintext password with a hashed password.
114
+ *
115
+ * @param password - The plaintext password.
116
+ * @param hashedPassword - The stored hashed password.
117
+ * @returns `true` if the password matches, otherwise `false`.
118
+ */
119
+ async comparePassword (password: string, hashedPassword?: string | null): Promise<boolean> {
120
+ return await bcrypt.compare(password, hashedPassword ?? '')
121
+ },
122
+
123
+ /**
124
+ * Generates a JWT token for a user.
125
+ *
126
+ * @param user - The user information to include in the token.
127
+ * @returns The generated JWT token.
128
+ */
129
+ async generateToken (user: UserModel, ip: string, userAgent?: string): Promise<string> {
130
+ let session = await sessionService.getLatest(user)
131
+
132
+ if (
133
+ isEmpty(session) ||
134
+ session?.ip !== ip ||
135
+ isNotEmpty(session.closedAt) ||
136
+ session?.userAgent !== userAgent
137
+ ) {
138
+ session = await sessionService.createForUser(user, ip, userAgent)
139
+ } else {
140
+ session = await sessionService.extend(
141
+ session,
142
+ blueprint.get<number>('security.jwt.expiresIn', 3600)
143
+ )
144
+ }
145
+
146
+ return jwt.sign(
147
+ {
148
+ user: {
149
+ ...user,
150
+ password: undefined
151
+ },
152
+ session
153
+ },
154
+ blueprint.get<string>('security.secret', 'secret'),
155
+ blueprint.get<jwt.SignOptions>('security.jwt')
156
+ )
157
+ },
158
+
159
+ /**
160
+ * Verifies a JWT token and returns the decoded payload.
161
+ *
162
+ * @param token - The JWT token to verify.
163
+ * @returns The decoded user payload or null if invalid.
164
+ */
165
+ verifyToken (token: string): UserTokenPayload {
166
+ try {
167
+ return jwt.verify(
168
+ token,
169
+ blueprint.get<string>('security.secret', 'secret')
170
+ ) as UserTokenPayload
171
+ } catch (error: any) {
172
+ throw new UnauthorizedError('Invalid token', { cause: error })
173
+ }
174
+ },
175
+
176
+ /**
177
+ * Register a user
178
+ *
179
+ * @param user - The user to register
180
+ */
181
+ async register (payload: UserRegister): Promise<void> {
182
+ const user = await userRepository.findBy({ email: payload.email })
183
+
184
+ if (isNotEmpty(user)) {
185
+ throw new BadRequestError(`The user with email ${payload.email} already exists`)
186
+ }
187
+
188
+ const password = await this.hashPassword(payload.password)
189
+
190
+ await userRepository.create({
191
+ ...payload,
192
+ password,
193
+ updatedAt: Date.now(),
194
+ createdAt: Date.now()
195
+ })
196
+ },
197
+
198
+ /**
199
+ * Change the user password
200
+ *
201
+ * @param user - The user to change the password
202
+ * @param password - The password to change
203
+ */
204
+ async changePassword (user?: UserModel, password?: UserChangePassword): Promise<void> {
205
+ if (isEmpty(user)) {
206
+ throw new UnauthorizedError('User not found')
207
+ }
208
+
209
+ if (isEmpty(password) || !(await this.comparePassword(password.password, user.password))) {
210
+ throw new UnauthorizedError('Invalid user password')
211
+ }
212
+
213
+ await userRepository.update(user.id, { password: password.newPassword })
214
+ }
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Security Service
220
+ *
221
+ * The alias is required to get benefits of desctructuring Dependency Injection.
222
+ * And because the front-end class will be minified, we need to use alias to keep the class name.
223
+ */
224
+ export const SecurityService = defineService(factorySecurityService, { isFactory: true, singleton: true, alias: 'securityService' })
@@ -0,0 +1,124 @@
1
+ import { randomUUID } from 'node:crypto'
2
+ import { UserModel } from '../models/User'
3
+ import { Session } from '../models/Session'
4
+ import { defineService } from '@stone-js/core'
5
+ import { ISessionService } from './contracts/ISessionService'
6
+ import { ISessionRepository } from '../repositories/contracts/ISessionRepository'
7
+
8
+ /**
9
+ * Session Service Options
10
+ */
11
+ export interface SessionServiceOptions {
12
+ sessionRepository: ISessionRepository
13
+ }
14
+
15
+ /**
16
+ * Factory Session Service
17
+ */
18
+ export function factorySessionService ({ sessionRepository }: SessionServiceOptions): ISessionService {
19
+ return {
20
+ /**
21
+ * Finds all sessions.
22
+ *
23
+ * @param limit - The limit of sessions to list
24
+ * @returns The list of sessions
25
+ */
26
+ async list (limit: number): Promise<Session[]> {
27
+ return await sessionRepository.list(limit)
28
+ },
29
+
30
+ /**
31
+ * Finds a sessions by user.
32
+ *
33
+ * @param user - The user to look up
34
+ * @param limit - The limit of sessions to list
35
+ * @returns The list of sessions
36
+ */
37
+ async getByUser (user: UserModel, limit: number): Promise<Session[]> {
38
+ return await sessionRepository.listByUser(user, limit)
39
+ },
40
+
41
+ /**
42
+ * Finds a session by ID.
43
+ *
44
+ * @param sessionId - The session ID to look up
45
+ * @returns The session data or `undefined` if not found
46
+ */
47
+ async getById (id: number): Promise<Session | undefined> {
48
+ return await sessionRepository.findById(id)
49
+ },
50
+
51
+ /**
52
+ * Finds the latest session of a user.
53
+ *
54
+ * @param user - The user to look up
55
+ * @returns The latest session or `undefined` if not found
56
+ */
57
+ async getLatest (user: UserModel): Promise<Session | undefined> {
58
+ return await sessionRepository.getLatest(user)
59
+ },
60
+
61
+ /**
62
+ * Creates a new session for a user.
63
+ *
64
+ * @param user - The user to create the session for
65
+ * @param ip - The IP address of the user
66
+ * @param userAgent - The user agent of the user
67
+ * @returns The created session
68
+ */
69
+ async createForUser (user: UserModel, ip: string, userAgent?: string): Promise<Session> {
70
+ const session = {
71
+ ip,
72
+ userAgent,
73
+ userId: user.id,
74
+ createdAt: Date.now(),
75
+ uuid: randomUUID(),
76
+ lastActivityAt: Date.now(),
77
+ expiresAt: Date.now() + 3600
78
+ }
79
+
80
+ return await sessionRepository.create(session)
81
+ },
82
+
83
+ /**
84
+ * Updates the last activity timestamp of a session.
85
+ *
86
+ * @param sessionId - The session ID to update
87
+ * @returns `true` if the session was updated, otherwise `false`
88
+ */
89
+ async updateLastActivity (session: Session): Promise<void> {
90
+ await sessionRepository.update(session.id, { lastActivityAt: Date.now() })
91
+ },
92
+
93
+ /**
94
+ * Extends a session expiration time.
95
+ *
96
+ * @param sessionId - The session ID to extend
97
+ * @param additionalTime - Additional time in milliseconds
98
+ * @returns `true` if the session was extended, otherwise `false`
99
+ */
100
+ async extend (session: Session, additionalTime: number): Promise<Session> {
101
+ session.expiresAt = Date.now() + additionalTime
102
+ await sessionRepository.update(session.id, session)
103
+ return session
104
+ },
105
+
106
+ /**
107
+ * Closes a session.
108
+ *
109
+ * @param sessionId - The session ID to close
110
+ */
111
+ async close (session: Session): Promise<void> {
112
+ session.closedAt = Date.now()
113
+ await sessionRepository.update(session.id, session)
114
+ }
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Session Service
120
+ *
121
+ * The alias is required to get benefits of desctructuring Dependency Injection.
122
+ * And because the front-end class will be minified, we need to use alias to keep the class name.
123
+ */
124
+ export const SessionService = defineService(factorySessionService, { isFactory: true, singleton: true, alias: 'sessionService' })
@@ -0,0 +1,105 @@
1
+ import { UserModel } from '../models/User'
2
+ import { UserEvent } from '../events/UserEvent'
3
+ import { NotFoundError } from '@stone-js/http-core'
4
+ import { DependencyResolver } from '@stone-js/router'
5
+ import { IUserService } from './contracts/IUserService'
6
+ import { defineService, EventEmitter, isNotEmpty } from '@stone-js/core'
7
+ import { IUserRepository } from '../repositories/contracts/IUserRepository'
8
+
9
+ /**
10
+ * User Service Options
11
+ */
12
+ export interface UserServiceOptions {
13
+ eventEmitter: EventEmitter
14
+ userRepository: IUserRepository
15
+ }
16
+
17
+ /**
18
+ * Factory User Service
19
+ */
20
+ export function factoryUserService ({ userRepository, eventEmitter }: UserServiceOptions): IUserService {
21
+ return {
22
+ /**
23
+ * List users
24
+ *
25
+ * @param limit - The limit of users to list
26
+ */
27
+ async list (limit: number = 10): Promise<UserModel[]> {
28
+ return await userRepository.list(limit)
29
+ },
30
+
31
+ /**
32
+ * Find a user
33
+ *
34
+ * @param conditions - The conditions to find the user
35
+ * @returns The found user
36
+ */
37
+ async findBy (conditions: Record<string, any>): Promise<UserModel> {
38
+ const user = await userRepository.findById(conditions.id)
39
+ if (isNotEmpty<UserModel>(user)) return user
40
+ throw new NotFoundError(`User with ID ${String(conditions.id)} not found`)
41
+ },
42
+
43
+ /**
44
+ * Find a user
45
+ *
46
+ * @param conditions - The conditions to find the user
47
+ * @returns The found user
48
+ */
49
+ async findByEmail (conditions: Record<string, any>): Promise<UserModel | undefined> {
50
+ return await userRepository.findBy(conditions)
51
+ },
52
+
53
+ /**
54
+ * Create a user
55
+ *
56
+ * @param payload - The user data to create
57
+ */
58
+ async create (payload: Omit<UserModel, 'id'>): Promise<bigint | undefined> {
59
+ await eventEmitter.emit(new UserEvent(payload))
60
+ return await userRepository.create({ ...payload, createdAt: Date.now(), updatedAt: Date.now() })
61
+ },
62
+
63
+ /**
64
+ * Update a user
65
+ *
66
+ * @param id - The id of the user to update
67
+ * @param payload - The user data to update
68
+ * @returns The updated user
69
+ */
70
+ async update (id: number, payload: UserModel): Promise<UserModel> {
71
+ const user = await userRepository.update(id, payload)
72
+ if (isNotEmpty<UserModel>(user)) return user
73
+ throw new NotFoundError(`User with ID ${id} not found`)
74
+ },
75
+
76
+ /**
77
+ * Delete a user
78
+ *
79
+ * @param id - The id of the user to delete
80
+ */
81
+ async delete (id: number): Promise<boolean> {
82
+ return await userRepository.delete(id)
83
+ }
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Resolve route binding
89
+ *
90
+ * @param key - The key of the binding
91
+ * @param value - The value of the binding
92
+ * @param container - The container
93
+ */
94
+ export async function userResolveRouteBinding (key: string, value: any, container?: DependencyResolver): Promise<UserModel | undefined> {
95
+ const userService = container?.resolve<IUserService>('userService')
96
+ return await userService?.findBy({ [key]: value })
97
+ }
98
+
99
+ /**
100
+ * User Service
101
+ *
102
+ * The alias is required to get benefits of desctructuring Dependency Injection.
103
+ * And because the front-end class will be minified, we need to use alias to keep the class name.
104
+ */
105
+ export const UserService = defineService(factoryUserService, { isFactory: true, singleton: true, alias: 'userService' })
@@ -0,0 +1,62 @@
1
+ import { Comment, CommentModel } from '../../models/Comment'
2
+
3
+ /**
4
+ * Comment Service contract
5
+ */
6
+ export interface ICommentService {
7
+ /**
8
+ * List comments.
9
+ *
10
+ * @param limit - The limit of comments to list.
11
+ */
12
+ list: (limit?: number) => Promise<Comment[]>
13
+
14
+ /**
15
+ * Retrieve comments for a specific post.
16
+ *
17
+ * @param postId - The post ID.
18
+ * @param limit - The number of comments to retrieve.
19
+ */
20
+ listByPost: (postId: number, limit?: number) => Promise<Comment[]>
21
+
22
+ /**
23
+ * Retrieve comments by a specific user.
24
+ *
25
+ * @param authorId - The author ID.
26
+ * @param limit - The number of comments to retrieve.
27
+ */
28
+ listByAuthor: (authorId: number, limit?: number) => Promise<Comment[]>
29
+
30
+ /**
31
+ * Find a comment by ID.
32
+ *
33
+ * @param id - The ID of the comment.
34
+ * @returns The found comment.
35
+ * @throws NotFoundError if comment is not found.
36
+ */
37
+ findById: (id: number) => Promise<Comment>
38
+
39
+ /**
40
+ * Create a new comment.
41
+ *
42
+ * @param payload - The comment data to create.
43
+ */
44
+ create: (payload: Omit<CommentModel, 'id'>) => Promise<bigint | undefined>
45
+
46
+ /**
47
+ * Update an existing comment.
48
+ *
49
+ * @param id - The ID of the comment.
50
+ * @param payload - The comment data to update.
51
+ * @returns The updated comment.
52
+ * @throws NotFoundError if comment is not found.
53
+ */
54
+ update: (id: number, payload: Partial<CommentModel>) => Promise<Comment>
55
+
56
+ /**
57
+ * Delete a comment.
58
+ *
59
+ * @param id - The ID of the comment.
60
+ */
61
+ delete: (id: number) => Promise<boolean>
62
+ }
@@ -0,0 +1,53 @@
1
+ import { Post, PostCreateModel, PostModel } from '../../models/Post'
2
+
3
+ /**
4
+ * Post Service contract
5
+ */
6
+ export interface IPostService {
7
+ /**
8
+ * List posts.
9
+ *
10
+ * @param limit - The limit of posts to list.
11
+ */
12
+ list: (limit?: number) => Promise<Post[]>
13
+
14
+ /**
15
+ * Retrieve posts by a specific user.
16
+ *
17
+ * @param authorId - The author ID.
18
+ * @param limit - The number of posts to retrieve.
19
+ */
20
+ listByAuthor: (authorId: number, limit?: number) => Promise<Post[]>
21
+
22
+ /**
23
+ * Find a post by ID.
24
+ *
25
+ * @param id - The ID of the post.
26
+ * @returns The found post.
27
+ * @throws NotFoundError if post is not found.
28
+ */
29
+ findById: (id: number) => Promise<Post>
30
+
31
+ /**
32
+ * Create a new post.
33
+ *
34
+ * @param payload - The post data to create.
35
+ */
36
+ create: (payload: Omit<PostCreateModel, 'id'>) => Promise<bigint | undefined>
37
+
38
+ /**
39
+ * Update an existing post.
40
+ *
41
+ * @param id - The ID of the post.
42
+ * @param payload - The post data to update.
43
+ * @returns `true` if the update was successful.
44
+ */
45
+ update: (id: number, payload: Partial<PostModel>) => Promise<boolean>
46
+
47
+ /**
48
+ * Delete a post.
49
+ *
50
+ * @param id - The ID of the post.
51
+ */
52
+ delete: (id: number) => Promise<boolean>
53
+ }
@@ -0,0 +1,97 @@
1
+ import { IncomingHttpEvent } from '@stone-js/http-core'
2
+ import { UserLogin, UserToken, UserModel, UserTokenPayload, UserRegister, UserChangePassword } from '../../models/User'
3
+
4
+ /**
5
+ * Security Service contract
6
+ */
7
+ export interface ISecurityService {
8
+ /**
9
+ * Logs in a user and returns a JWT token.
10
+ *
11
+ * @param event - The incoming HTTP event containing IP and user agent.
12
+ * @param credentials - The user's email and password.
13
+ * @returns The user token.
14
+ * @throws BadCredentialsError if credentials are invalid.
15
+ */
16
+ login: (event: IncomingHttpEvent, credentials: UserLogin) => Promise<UserToken>
17
+
18
+ /**
19
+ * Refreshes an access token using a valid existing token.
20
+ *
21
+ * @param token - The current JWT token.
22
+ * @returns The refreshed user token.
23
+ * @throws UnauthorizedError if the token is invalid or user not found.
24
+ */
25
+ refresh: (token: string) => Promise<UserToken>
26
+
27
+ /**
28
+ * Logs out a user by closing the associated session.
29
+ *
30
+ * @param token - The JWT token of the user session.
31
+ */
32
+ logout: (token: string) => Promise<void>
33
+
34
+ /**
35
+ * Authenticates a user based on a token, IP, and user agent.
36
+ *
37
+ * @param token - The JWT token to verify.
38
+ * @param ip - The IP address of the request.
39
+ * @param userAgent - Optional user agent string.
40
+ * @returns The authenticated user.
41
+ * @throws UnauthorizedError if token or session info is invalid.
42
+ */
43
+ authenticate: (token: string, ip: string, userAgent?: string) => Promise<UserModel>
44
+
45
+ /**
46
+ * Hashes a plaintext password using bcrypt.
47
+ *
48
+ * @param password - The plaintext password.
49
+ * @returns The hashed password.
50
+ */
51
+ hashPassword: (password: string) => Promise<string>
52
+
53
+ /**
54
+ * Compares a plaintext password with a hashed one.
55
+ *
56
+ * @param password - The plaintext password.
57
+ * @param hashedPassword - The hashed password.
58
+ * @returns `true` if the password matches, `false` otherwise.
59
+ */
60
+ comparePassword: (password: string, hashedPassword?: string | null) => Promise<boolean>
61
+
62
+ /**
63
+ * Generates a signed JWT token for a user and session.
64
+ *
65
+ * @param user - The user to generate a token for.
66
+ * @param ip - The IP address of the request.
67
+ * @param userAgent - Optional user agent.
68
+ * @returns The generated JWT token string.
69
+ */
70
+ generateToken: (user: UserModel, ip: string, userAgent?: string) => Promise<string>
71
+
72
+ /**
73
+ * Verifies a JWT token and returns the payload.
74
+ *
75
+ * @param token - The JWT token to verify.
76
+ * @returns The decoded payload.
77
+ * @throws UnauthorizedError if the token is invalid.
78
+ */
79
+ verifyToken: (token: string) => UserTokenPayload
80
+
81
+ /**
82
+ * Registers a new user.
83
+ *
84
+ * @param payload - The user registration data.
85
+ * @throws BadRequestError if the email is already in use.
86
+ */
87
+ register: (payload: UserRegister) => Promise<void>
88
+
89
+ /**
90
+ * Changes the password of a user.
91
+ *
92
+ * @param user - The user whose password is being changed.
93
+ * @param password - The old and new passwords.
94
+ * @throws UnauthorizedError if validation fails.
95
+ */
96
+ changePassword: (user?: UserModel, password?: UserChangePassword) => Promise<void>
97
+ }