@podosoft/podokit 0.2.0 → 0.3.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 (204) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/templates/fullstack-nest-svelte/apps/api/package.json +9 -9
  4. package/dist/templates/fullstack-nest-svelte/apps/api/src/app.module.ts +3 -0
  5. package/dist/templates/fullstack-nest-svelte/apps/web/package.json +5 -4
  6. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
  7. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
  8. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
  9. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
  10. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/index.ts +17 -0
  11. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  12. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  13. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  14. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
  15. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
  16. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
  17. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
  18. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
  19. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/index.ts +2 -0
  20. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  21. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
  22. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  23. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  24. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  25. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  26. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  27. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  28. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  29. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  30. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
  31. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  32. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  33. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
  34. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  35. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
  36. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
  37. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
  38. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  39. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  40. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  41. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  42. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
  43. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
  44. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  45. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  46. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  47. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  48. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
  49. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/index.ts +37 -0
  50. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
  51. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  52. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
  53. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
  54. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
  55. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
  56. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  57. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  58. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
  59. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
  60. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select.svelte +11 -0
  61. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/index.ts +7 -0
  62. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
  63. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
  64. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  65. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
  66. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
  67. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/index.ts +28 -0
  68. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
  69. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
  70. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
  71. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
  72. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
  73. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
  74. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
  75. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table.svelte +17 -0
  76. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
  77. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  78. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
  79. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
  80. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
  81. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
  82. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  83. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  84. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  85. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  86. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  87. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/ko.ts +5 -2
  88. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.decorator.ts +9 -0
  89. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.guard.ts +29 -0
  90. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.module.ts +9 -0
  91. package/dist/templates/modules/api-key-auth/files/apps/api/src/machine/machine.controller.ts +14 -0
  92. package/dist/templates/modules/api-key-auth/module.manifest.json +19 -0
  93. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-log.entity.ts +25 -0
  94. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.controller.ts +16 -0
  95. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.interceptor.ts +39 -0
  96. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +13 -0
  97. package/dist/templates/modules/audit-log/files/apps/api/src/migrations/1720300000000-InitAuditLogs.ts +25 -0
  98. package/dist/templates/modules/audit-log/module.manifest.json +16 -0
  99. package/dist/templates/modules/auth/files/apps/api/src/account/account.controller.ts +13 -0
  100. package/dist/templates/modules/auth/files/apps/api/src/account/account.module.ts +5 -0
  101. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +36 -0
  102. package/dist/templates/modules/auth/files/apps/api/src/health/health.controller.ts +26 -0
  103. package/dist/templates/modules/auth/module.manifest.json +70 -0
  104. package/dist/templates/modules/bullmq/module.manifest.json +11 -3
  105. package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +29 -0
  106. package/dist/templates/modules/logging/module.manifest.json +27 -0
  107. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.ts +26 -0
  108. package/dist/templates/modules/rate-limit/module.manifest.json +25 -0
  109. package/dist/templates/todo/apps/api/package.json +9 -9
  110. package/dist/templates/todo/apps/api/src/app.module.ts +3 -0
  111. package/dist/templates/todo/apps/web/package.json +5 -4
  112. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
  113. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
  114. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
  115. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
  116. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/index.ts +17 -0
  117. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  118. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  119. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  120. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
  121. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
  122. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
  123. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
  124. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
  125. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/index.ts +2 -0
  126. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  127. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
  128. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  129. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  130. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  131. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  132. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  133. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  134. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  135. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  136. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
  137. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  138. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  139. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
  140. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  141. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
  142. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
  143. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
  144. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  145. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  146. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  147. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  148. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
  149. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
  150. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  151. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  152. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  153. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  154. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
  155. package/dist/templates/todo/apps/web/src/lib/components/ui/select/index.ts +37 -0
  156. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
  157. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  158. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
  159. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
  160. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
  161. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
  162. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  163. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  164. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
  165. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
  166. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select.svelte +11 -0
  167. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/index.ts +7 -0
  168. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
  169. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
  170. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  171. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
  172. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
  173. package/dist/templates/todo/apps/web/src/lib/components/ui/table/index.ts +28 -0
  174. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
  175. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
  176. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
  177. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
  178. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
  179. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
  180. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
  181. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table.svelte +17 -0
  182. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
  183. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  184. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
  185. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
  186. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
  187. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
  188. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  189. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  190. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  191. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  192. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  193. package/dist/templates/todo/apps/web/src/lib/i18n/ko.ts +5 -2
  194. package/package.json +2 -2
  195. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.controller.ts +0 -31
  196. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.module.ts +0 -22
  197. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/auth.service.ts +0 -44
  198. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/dto/login.dto.ts +0 -12
  199. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/dto/register.dto.ts +0 -13
  200. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/jwt-auth.guard.ts +0 -5
  201. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/jwt.strategy.ts +0 -23
  202. package/dist/templates/modules/auth-jwt/files/apps/api/src/auth/user.entity.ts +0 -16
  203. package/dist/templates/modules/auth-jwt/files/apps/api/src/migrations/1720200000000-InitUsers.ts +0 -23
  204. package/dist/templates/modules/auth-jwt/module.manifest.json +0 -31
@@ -0,0 +1,9 @@
1
+ import { Module } from "@nestjs/common";
2
+ import { MachineController } from "../machine/machine.controller";
3
+ import { ApiKeyGuard } from "./api-key.guard";
4
+
5
+ @Module({
6
+ controllers: [MachineController],
7
+ providers: [ApiKeyGuard],
8
+ })
9
+ export class ApiKeyModule {}
@@ -0,0 +1,14 @@
1
+ import { Controller, Get } from "@nestjs/common";
2
+ import { ApiTags } from "@nestjs/swagger";
3
+ import { ApiKeyProtected } from "../api-key/api-key.decorator";
4
+
5
+ @ApiTags("machine")
6
+ @Controller("machine")
7
+ export class MachineController {
8
+ // Reachable with a valid X-API-Key, no user session required.
9
+ @ApiKeyProtected()
10
+ @Get("ping")
11
+ ping(): { ok: true; via: "api-key" } {
12
+ return { ok: true, via: "api-key" };
13
+ }
14
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "api-key-auth",
3
+ "description": "API-key auth for machine/service clients (X-API-Key), separate from user sessions. Provides an ApiKeyGuard and @ApiKeyProtected() to open a route to key holders. Requires auth.",
4
+ "requires": ["auth"],
5
+ "targetApp": "api",
6
+ "env": [
7
+ "# api keys for machine clients (comma-separated)",
8
+ "API_KEYS=dev-key-please-change"
9
+ ],
10
+ "inject": [
11
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:imports", "text": "import { ApiKeyModule } from \"./api-key/api-key.module\";" },
12
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:module-imports", "text": "ApiKeyModule," }
13
+ ],
14
+ "instructions": [
15
+ "Set API_KEYS in .env (comma-separated).",
16
+ "Protect a route for machine clients with @ApiKeyProtected() (bypasses the user session, requires X-API-Key).",
17
+ "Call it: curl -H 'x-api-key: dev-key-please-change' localhost:3000/machine/ping"
18
+ ]
19
+ }
@@ -0,0 +1,25 @@
1
+ import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm";
2
+
3
+ @Entity("audit_logs")
4
+ export class AuditLog {
5
+ @PrimaryGeneratedColumn("uuid")
6
+ id!: string;
7
+
8
+ @Column({ type: "varchar", nullable: true })
9
+ userId!: string | null;
10
+
11
+ @Column({ type: "varchar", length: 10 })
12
+ method!: string;
13
+
14
+ @Column({ type: "varchar", length: 2048 })
15
+ path!: string;
16
+
17
+ @Column({ type: "int" })
18
+ statusCode!: number;
19
+
20
+ @Column({ type: "varchar", nullable: true })
21
+ ip!: string | null;
22
+
23
+ @CreateDateColumn({ type: "timestamptz" })
24
+ createdAt!: Date;
25
+ }
@@ -0,0 +1,16 @@
1
+ import { Controller, Get } from "@nestjs/common";
2
+ import { InjectRepository } from "@nestjs/typeorm";
3
+ import { ApiTags } from "@nestjs/swagger";
4
+ import { Repository } from "typeorm";
5
+ import { AuditLog } from "./audit-log.entity";
6
+
7
+ @ApiTags("audit")
8
+ @Controller("audit-logs")
9
+ export class AuditController {
10
+ constructor(@InjectRepository(AuditLog) private readonly logs: Repository<AuditLog>) {}
11
+
12
+ @Get()
13
+ recent(): Promise<AuditLog[]> {
14
+ return this.logs.find({ order: { createdAt: "DESC" }, take: 50 });
15
+ }
16
+ }
@@ -0,0 +1,39 @@
1
+ import { type CallHandler, type ExecutionContext, Injectable, type NestInterceptor } from "@nestjs/common";
2
+ import { InjectRepository } from "@nestjs/typeorm";
3
+ import { fromNodeHeaders } from "better-auth/node";
4
+ import type { Request, Response } from "express";
5
+ import { type Observable, tap } from "rxjs";
6
+ import { Repository } from "typeorm";
7
+ import { auth } from "../auth/auth";
8
+ import { AuditLog } from "./audit-log.entity";
9
+
10
+ const AUDITED_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
11
+
12
+ // Records who performed each mutating request. Skips the auth endpoints.
13
+ @Injectable()
14
+ export class AuditInterceptor implements NestInterceptor {
15
+ constructor(@InjectRepository(AuditLog) private readonly logs: Repository<AuditLog>) {}
16
+
17
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
18
+ const req = context.switchToHttp().getRequest<Request>();
19
+ const path = req.originalUrl ?? req.url;
20
+ if (!AUDITED_METHODS.has(req.method) || path.startsWith("/api/auth")) {
21
+ return next.handle();
22
+ }
23
+ const res = context.switchToHttp().getResponse<Response>();
24
+ return next.handle().pipe(tap(() => void this.record(req, res, path)));
25
+ }
26
+
27
+ private async record(req: Request, res: Response, path: string): Promise<void> {
28
+ let userId: string | null = null;
29
+ try {
30
+ const session = await auth.api.getSession({ headers: fromNodeHeaders(req.headers) });
31
+ userId = session?.user?.id ?? null;
32
+ } catch {
33
+ userId = null;
34
+ }
35
+ await this.logs.save(
36
+ this.logs.create({ userId, method: req.method, path, statusCode: res.statusCode, ip: req.ip ?? null }),
37
+ );
38
+ }
39
+ }
@@ -0,0 +1,13 @@
1
+ import { Module } from "@nestjs/common";
2
+ import { APP_INTERCEPTOR } from "@nestjs/core";
3
+ import { TypeOrmModule } from "@nestjs/typeorm";
4
+ import { AuditController } from "./audit.controller";
5
+ import { AuditInterceptor } from "./audit.interceptor";
6
+ import { AuditLog } from "./audit-log.entity";
7
+
8
+ @Module({
9
+ imports: [TypeOrmModule.forFeature([AuditLog])],
10
+ controllers: [AuditController],
11
+ providers: [{ provide: APP_INTERCEPTOR, useClass: AuditInterceptor }],
12
+ })
13
+ export class AuditModule {}
@@ -0,0 +1,25 @@
1
+ import type { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class InitAuditLogs1720300000000 implements MigrationInterface {
4
+ name = "InitAuditLogs1720300000000";
5
+
6
+ async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS "pgcrypto"`);
8
+ await queryRunner.query(`
9
+ CREATE TABLE "audit_logs" (
10
+ "id" uuid NOT NULL DEFAULT gen_random_uuid(),
11
+ "userId" character varying,
12
+ "method" character varying(10) NOT NULL,
13
+ "path" character varying(2048) NOT NULL,
14
+ "statusCode" integer NOT NULL,
15
+ "ip" character varying,
16
+ "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
17
+ CONSTRAINT "PK_audit_logs_id" PRIMARY KEY ("id")
18
+ )
19
+ `);
20
+ }
21
+
22
+ async down(queryRunner: QueryRunner): Promise<void> {
23
+ await queryRunner.query(`DROP TABLE "audit_logs"`);
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "audit-log",
3
+ "description": "Audit logging: a global interceptor records who did each mutating request (who/method/path/status) to an audit_logs table. Requires auth.",
4
+ "requires": ["auth"],
5
+ "targetApp": "api",
6
+ "env": [],
7
+ "inject": [
8
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:imports", "text": "import { AuditModule } from \"./audit/audit.module\";" },
9
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:module-imports", "text": "AuditModule," }
10
+ ],
11
+ "instructions": [
12
+ "Run migrations to create the audit_logs table: npm run migration:run -w <app>-api",
13
+ "Mutating requests (POST/PUT/PATCH/DELETE) are recorded with the acting user.",
14
+ "List recent entries (requires a session): curl -b cookies.txt localhost:3000/audit-logs"
15
+ ]
16
+ }
@@ -0,0 +1,13 @@
1
+ import { Controller, Get } from "@nestjs/common";
2
+ import { Session, type UserSession } from "@thallesp/nestjs-better-auth";
3
+ import { ApiTags } from "@nestjs/swagger";
4
+
5
+ // Protected by the global AuthGuard. Use @Session() to read the current user.
6
+ @ApiTags("account")
7
+ @Controller("account")
8
+ export class AccountController {
9
+ @Get("me")
10
+ me(@Session() session: UserSession) {
11
+ return session.user;
12
+ }
13
+ }
@@ -0,0 +1,5 @@
1
+ import { Module } from "@nestjs/common";
2
+ import { AccountController } from "./account.controller";
3
+
4
+ @Module({ controllers: [AccountController] })
5
+ export class AccountModule {}
@@ -0,0 +1,36 @@
1
+ import { betterAuth, type BetterAuthOptions } from "better-auth";
2
+ import { twoFactor } from "better-auth/plugins";
3
+ import { Pool } from "pg";
4
+
5
+ // OAuth providers are enabled only when their credentials are present.
6
+ function socialProviders(): NonNullable<BetterAuthOptions["socialProviders"]> {
7
+ const providers: NonNullable<BetterAuthOptions["socialProviders"]> = {};
8
+ if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
9
+ providers.google = {
10
+ clientId: process.env.GOOGLE_CLIENT_ID,
11
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
12
+ };
13
+ }
14
+ if (process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET) {
15
+ providers.github = {
16
+ clientId: process.env.GITHUB_CLIENT_ID,
17
+ clientSecret: process.env.GITHUB_CLIENT_SECRET,
18
+ };
19
+ }
20
+ return providers;
21
+ }
22
+
23
+ export const auth = betterAuth({
24
+ database: new Pool({
25
+ host: process.env.POSTGRES_HOST ?? "localhost",
26
+ port: Number(process.env.POSTGRES_PORT ?? 5432),
27
+ user: process.env.POSTGRES_USER ?? "podokit",
28
+ password: process.env.POSTGRES_PASSWORD ?? "podokit",
29
+ database: process.env.POSTGRES_DB ?? "podokit",
30
+ }),
31
+ emailAndPassword: { enabled: true },
32
+ socialProviders: socialProviders(),
33
+ plugins: process.env.AUTH_TWO_FACTOR === "true" ? [twoFactor()] : [],
34
+ secret: process.env.BETTER_AUTH_SECRET ?? "change-me-in-production-min-32-characters",
35
+ baseURL: process.env.BETTER_AUTH_URL ?? "http://localhost:3000",
36
+ });
@@ -0,0 +1,26 @@
1
+ import { Controller, Get } from "@nestjs/common";
2
+ import { InjectDataSource } from "@nestjs/typeorm";
3
+ import { DataSource } from "typeorm";
4
+ import { Public } from "@thallesp/nestjs-better-auth";
5
+
6
+ // Health checks stay public under the global auth guard.
7
+ @Public()
8
+ @Controller("health")
9
+ export class HealthController {
10
+ constructor(@InjectDataSource() private readonly dataSource: DataSource) {}
11
+
12
+ @Get()
13
+ liveness(): { status: string; uptime: number; timestamp: string } {
14
+ return { status: "ok", uptime: process.uptime(), timestamp: new Date().toISOString() };
15
+ }
16
+
17
+ @Get("ready")
18
+ async readiness(): Promise<{ status: string; db: string }> {
19
+ try {
20
+ await this.dataSource.query("SELECT 1");
21
+ return { status: "ready", db: "up" };
22
+ } catch {
23
+ return { status: "degraded", db: "down" };
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "auth",
3
+ "description": "Full authentication (better-auth): email/password, sessions, and \u2014 via config \u2014 OAuth and 2FA. Installs a global guard so the API is secure by default; health and /api/auth stay public.",
4
+ "requires": [],
5
+ "targetApp": "api",
6
+ "dependencies": {
7
+ "better-auth": "^1.6.23",
8
+ "@thallesp/nestjs-better-auth": "^2.7.0",
9
+ "pg": "^8.12.0"
10
+ },
11
+ "devDependencies": {
12
+ "@types/pg": "^8.11.10"
13
+ },
14
+ "env": [
15
+ "# auth (better-auth) \u2014 set a strong secret (>= 32 chars) in production",
16
+ "BETTER_AUTH_SECRET=change-me-in-production-min-32-characters",
17
+ "BETTER_AUTH_URL=http://localhost:3000",
18
+ "# 2FA (TOTP): set true to enable the plugin",
19
+ "AUTH_TWO_FACTOR=false",
20
+ "# OAuth (optional) \u2014 set a provider's id+secret to enable it",
21
+ "# GOOGLE_CLIENT_ID=",
22
+ "# GOOGLE_CLIENT_SECRET=",
23
+ "# GITHUB_CLIENT_ID=",
24
+ "# GITHUB_CLIENT_SECRET="
25
+ ],
26
+ "inject": [
27
+ {
28
+ "file": "apps/api/src/app.module.ts",
29
+ "marker": "// podokit:imports",
30
+ "text": "import { APP_GUARD } from \"@nestjs/core\";"
31
+ },
32
+ {
33
+ "file": "apps/api/src/app.module.ts",
34
+ "marker": "// podokit:imports",
35
+ "text": "import { AuthModule, AuthGuard } from \"@thallesp/nestjs-better-auth\";"
36
+ },
37
+ {
38
+ "file": "apps/api/src/app.module.ts",
39
+ "marker": "// podokit:imports",
40
+ "text": "import { auth } from \"./auth/auth\";"
41
+ },
42
+ {
43
+ "file": "apps/api/src/app.module.ts",
44
+ "marker": "// podokit:imports",
45
+ "text": "import { AccountModule } from \"./account/account.module\";"
46
+ },
47
+ {
48
+ "file": "apps/api/src/app.module.ts",
49
+ "marker": "// podokit:module-imports",
50
+ "text": "AuthModule.forRoot(auth),"
51
+ },
52
+ {
53
+ "file": "apps/api/src/app.module.ts",
54
+ "marker": "// podokit:module-imports",
55
+ "text": "AccountModule,"
56
+ },
57
+ {
58
+ "file": "apps/api/src/app.module.ts",
59
+ "marker": "// podokit:providers",
60
+ "text": "{ provide: APP_GUARD, useClass: AuthGuard },"
61
+ }
62
+ ],
63
+ "instructions": [
64
+ "Set BETTER_AUTH_SECRET in .env (>= 32 chars).",
65
+ "Create the auth tables: npx @better-auth/cli migrate -y --config apps/api/src/auth/auth.ts",
66
+ "Sign up: curl -c cookies.txt -XPOST localhost:3000/api/auth/sign-up/email -H 'content-type: application/json' -d '{\"email\":\"a@example.com\",\"password\":\"password123\",\"name\":\"A\"}'",
67
+ "Call a protected route with the session: curl -b cookies.txt localhost:3000/account/me",
68
+ "Everything is now protected by default; mark public routes with @Public(). Enable OAuth by setting a provider's env vars; enable 2FA with AUTH_TWO_FACTOR=true."
69
+ ]
70
+ }
@@ -4,7 +4,7 @@
4
4
  "requires": [],
5
5
  "targetApp": "api",
6
6
  "dependencies": {
7
- "@nestjs/bullmq": "^10.2.0",
7
+ "@nestjs/bullmq": "^11.0.4",
8
8
  "bullmq": "^5.34.0"
9
9
  },
10
10
  "scripts": {
@@ -15,8 +15,16 @@
15
15
  "# bullmq uses REDIS_HOST / REDIS_PORT (already defined above)"
16
16
  ],
17
17
  "inject": [
18
- { "file": "apps/api/src/app.module.ts", "marker": "// podokit:imports", "text": "import { JobsModule } from \"./jobs/jobs.module\";" },
19
- { "file": "apps/api/src/app.module.ts", "marker": "// podokit:module-imports", "text": "JobsModule," }
18
+ {
19
+ "file": "apps/api/src/app.module.ts",
20
+ "marker": "// podokit:imports",
21
+ "text": "import { JobsModule } from \"./jobs/jobs.module\";"
22
+ },
23
+ {
24
+ "file": "apps/api/src/app.module.ts",
25
+ "marker": "// podokit:module-imports",
26
+ "text": "JobsModule,"
27
+ }
20
28
  ],
21
29
  "instructions": [
22
30
  "Ensure Redis is running: docker compose -f infra/docker/docker-compose.yml up -d",
@@ -0,0 +1,29 @@
1
+ import { Module } from "@nestjs/common";
2
+ import { randomUUID } from "node:crypto";
3
+ import type { IncomingMessage, ServerResponse } from "node:http";
4
+ import { LoggerModule } from "nestjs-pino";
5
+
6
+ const isProduction = process.env.NODE_ENV === "production";
7
+
8
+ // Structured request logging with a correlation id. Importing this module
9
+ // installs the pino-http middleware for all routes.
10
+ @Module({
11
+ imports: [
12
+ LoggerModule.forRoot({
13
+ pinoHttp: {
14
+ level: process.env.LOG_LEVEL ?? "info",
15
+ // Pretty, single-line logs in dev; JSON in production.
16
+ transport: isProduction ? undefined : { target: "pino-pretty", options: { singleLine: true } },
17
+ autoLogging: true,
18
+ // One id per request; honor an inbound x-request-id and echo it back.
19
+ genReqId: (req: IncomingMessage, res: ServerResponse): string => {
20
+ const header = req.headers["x-request-id"];
21
+ const id = (Array.isArray(header) ? header[0] : header) ?? randomUUID();
22
+ res.setHeader("x-request-id", id);
23
+ return id;
24
+ },
25
+ },
26
+ }),
27
+ ],
28
+ })
29
+ export class LoggingModule {}
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "logging",
3
+ "description": "Structured request logging (nestjs-pino) with a per-request correlation id (x-request-id). Pretty in dev, JSON in production.",
4
+ "requires": [],
5
+ "targetApp": "api",
6
+ "dependencies": {
7
+ "nestjs-pino": "^4.3.0",
8
+ "pino-http": "^10.3.0"
9
+ },
10
+ "devDependencies": {
11
+ "pino-pretty": "^13.0.0"
12
+ },
13
+ "env": [
14
+ "# logging",
15
+ "LOG_LEVEL=info"
16
+ ],
17
+ "inject": [
18
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:imports", "text": "import { LoggingModule } from \"./logging/logging.module\";" },
19
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:module-imports", "text": "LoggingModule," }
20
+ ],
21
+ "instructions": [
22
+ "Every HTTP request is now logged as structured JSON with a correlation id.",
23
+ "Make a request and watch the API logs: curl localhost:3000/health",
24
+ "Set LOG_LEVEL (debug|info|warn|error) in .env. Logs are pretty in dev and JSON when NODE_ENV=production.",
25
+ "To route Nest's own logs through pino too, add to main.ts: NestFactory.create(AppModule, { bufferLogs: true }) then app.useLogger(app.get(Logger))."
26
+ ]
27
+ }
@@ -0,0 +1,26 @@
1
+ import { Module } from "@nestjs/common";
2
+ import { APP_GUARD } from "@nestjs/core";
3
+ import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
4
+ import { ThrottlerStorageRedisService } from "@nest-lab/throttler-storage-redis";
5
+ import Redis from "ioredis";
6
+
7
+ const ttlSeconds = Number(process.env.RATE_LIMIT_TTL ?? 60);
8
+ const limit = Number(process.env.RATE_LIMIT_MAX ?? 100);
9
+
10
+ // Distributed rate limiting: the counter lives in Redis, so the limit holds
11
+ // across API replicas. Registers a global guard (429 when exceeded).
12
+ @Module({
13
+ imports: [
14
+ ThrottlerModule.forRoot({
15
+ throttlers: [{ ttl: ttlSeconds * 1000, limit }],
16
+ storage: new ThrottlerStorageRedisService(
17
+ new Redis({
18
+ host: process.env.REDIS_HOST ?? "localhost",
19
+ port: Number(process.env.REDIS_PORT ?? 6379),
20
+ }),
21
+ ),
22
+ }),
23
+ ],
24
+ providers: [{ provide: APP_GUARD, useClass: ThrottlerGuard }],
25
+ })
26
+ export class RateLimitModule {}
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "rate-limit",
3
+ "description": "Rate limiting with @nestjs/throttler backed by Redis (correct across API replicas). Installs a global throttler guard; configurable via env.",
4
+ "requires": ["redis"],
5
+ "targetApp": "api",
6
+ "dependencies": {
7
+ "@nestjs/throttler": "^6.5.0",
8
+ "@nest-lab/throttler-storage-redis": "^1.2.0"
9
+ },
10
+ "env": [
11
+ "# rate limit (window in seconds, max requests per window per client)",
12
+ "RATE_LIMIT_TTL=60",
13
+ "RATE_LIMIT_MAX=100"
14
+ ],
15
+ "inject": [
16
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:imports", "text": "import { RateLimitModule } from \"./rate-limit/rate-limit.module\";" },
17
+ { "file": "apps/api/src/app.module.ts", "marker": "// podokit:module-imports", "text": "RateLimitModule," }
18
+ ],
19
+ "instructions": [
20
+ "Ensure Redis is running: docker compose -f infra/docker/docker-compose.yml up -d",
21
+ "Tune RATE_LIMIT_TTL / RATE_LIMIT_MAX in .env.",
22
+ "Exceeding the limit returns HTTP 429. Skip a route with @SkipThrottle() or tune it with @Throttle().",
23
+ "The limit is shared across API replicas because it is stored in Redis."
24
+ ]
25
+ }
@@ -14,12 +14,12 @@
14
14
  "migration:generate": "npm run typeorm -- migration:generate"
15
15
  },
16
16
  "dependencies": {
17
- "@nestjs/common": "^10.4.0",
18
- "@nestjs/config": "^3.2.3",
19
- "@nestjs/core": "^10.4.0",
20
- "@nestjs/platform-express": "^10.4.0",
21
- "@nestjs/swagger": "^7.4.0",
22
- "@nestjs/typeorm": "^10.0.2",
17
+ "@nestjs/common": "^11.1.27",
18
+ "@nestjs/config": "^4.0.4",
19
+ "@nestjs/core": "^11.1.27",
20
+ "@nestjs/platform-express": "^11.1.27",
21
+ "@nestjs/swagger": "^11.4.5",
22
+ "@nestjs/typeorm": "^11.0.3",
23
23
  "class-transformer": "^0.5.1",
24
24
  "class-validator": "^0.14.1",
25
25
  "dotenv": "^16.4.5",
@@ -30,9 +30,9 @@
30
30
  "zod": "^3.23.8"
31
31
  },
32
32
  "devDependencies": {
33
- "@nestjs/cli": "^10.4.0",
34
- "@nestjs/testing": "^10.4.0",
35
- "@types/express": "^4.17.21",
33
+ "@nestjs/cli": "^11.0.23",
34
+ "@nestjs/testing": "^11.1.27",
35
+ "@types/express": "^5.0.1",
36
36
  "@types/node": "^20.17.0",
37
37
  "@types/supertest": "^6.0.2",
38
38
  "jest": "^29.7.0",
@@ -15,5 +15,8 @@ import { TodosModule } from "./todos/todos.module";
15
15
  TodosModule,
16
16
  // podokit:module-imports
17
17
  ],
18
+ providers: [
19
+ // podokit:providers
20
+ ],
18
21
  })
19
22
  export class AppModule {}
@@ -11,13 +11,14 @@
11
11
  "test": "echo \"add Playwright tests here\" && exit 0"
12
12
  },
13
13
  "dependencies": {
14
- "mode-watcher": "^0.5.0",
14
+ "@internationalized/date": "^3.12.2",
15
+ "@lucide/svelte": "^1.23.0",
15
16
  "bits-ui": "^2.18.1",
16
17
  "clsx": "^2.1.1",
18
+ "mode-watcher": "^1.1.0",
19
+ "svelte-sonner": "^1.1.1",
17
20
  "tailwind-merge": "^3.6.0",
18
- "tailwind-variants": "^3.2.2",
19
- "@lucide/svelte": "^1.23.0",
20
- "@internationalized/date": "^3.12.2"
21
+ "tailwind-variants": "^3.2.2"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@sveltejs/adapter-node": "^5.2.0",
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="alert-action"
16
+ class={cn("absolute top-2 right-2", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="alert-description"
16
+ class={cn(
17
+ "text-muted-foreground text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3",
18
+ className
19
+ )}
20
+ {...restProps}
21
+ >
22
+ {@render children?.()}
23
+ </div>
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="alert-title"
16
+ class={cn(
17
+ "font-medium group-has-[>svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3",
18
+ className
19
+ )}
20
+ {...restProps}
21
+ >
22
+ {@render children?.()}
23
+ </div>