@podosoft/podokit 0.1.1 → 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 (326) hide show
  1. package/README.md +17 -3
  2. package/dist/add.d.ts +40 -0
  3. package/dist/add.js +114 -0
  4. package/dist/create.d.ts +2 -1
  5. package/dist/create.js +3 -2
  6. package/dist/index.js +39 -1
  7. package/dist/prompt.d.ts +0 -1
  8. package/dist/prompt.js +6 -7
  9. package/dist/templates/fullstack-nest-svelte/README.md +20 -8
  10. package/dist/templates/fullstack-nest-svelte/apps/api/package.json +20 -8
  11. package/dist/templates/fullstack-nest-svelte/apps/api/src/app.module.ts +14 -1
  12. package/dist/templates/fullstack-nest-svelte/apps/api/src/config/env.validation.ts +20 -15
  13. package/dist/templates/fullstack-nest-svelte/apps/api/src/database/data-source.ts +19 -0
  14. package/dist/templates/fullstack-nest-svelte/apps/api/src/health/health.controller.ts +15 -5
  15. package/dist/templates/fullstack-nest-svelte/apps/api/src/main.ts +8 -0
  16. package/dist/templates/fullstack-nest-svelte/apps/web/components.json +1 -1
  17. package/dist/templates/fullstack-nest-svelte/apps/web/package.json +10 -2
  18. package/dist/templates/fullstack-nest-svelte/apps/web/src/app.css +72 -8
  19. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
  20. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
  21. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
  22. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
  23. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/alert/index.ts +17 -0
  24. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  25. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  26. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  27. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
  28. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
  29. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
  30. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
  31. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
  32. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/badge/index.ts +2 -0
  33. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/button/button.svelte +82 -0
  34. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/button/index.ts +17 -0
  35. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-action.svelte +23 -0
  36. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-content.svelte +20 -0
  37. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-description.svelte +20 -0
  38. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-footer.svelte +20 -0
  39. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-header.svelte +23 -0
  40. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card-title.svelte +20 -0
  41. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/card.svelte +22 -0
  42. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/card/index.ts +25 -0
  43. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/checkbox/checkbox.svelte +39 -0
  44. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/checkbox/index.ts +6 -0
  45. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  46. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
  47. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  48. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  49. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  50. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  51. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  52. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  53. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  54. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  55. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
  56. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  57. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  58. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
  59. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  60. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
  61. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
  62. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
  63. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  64. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  65. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  66. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  67. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
  68. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
  69. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  70. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  71. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  72. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  73. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
  74. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/input/index.ts +7 -0
  75. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/input/input.svelte +48 -0
  76. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/label/index.ts +7 -0
  77. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/label/label.svelte +20 -0
  78. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/index.ts +37 -0
  79. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
  80. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  81. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
  82. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
  83. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
  84. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
  85. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  86. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  87. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
  88. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
  89. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/select/select.svelte +11 -0
  90. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/index.ts +7 -0
  91. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
  92. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
  93. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  94. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
  95. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
  96. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/index.ts +28 -0
  97. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
  98. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
  99. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
  100. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
  101. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
  102. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
  103. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
  104. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/table/table.svelte +17 -0
  105. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
  106. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  107. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
  108. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
  109. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
  110. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
  111. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  112. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  113. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  114. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  115. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  116. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/ko.ts +5 -2
  117. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/utils.ts +11 -0
  118. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/+page.svelte +19 -12
  119. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.decorator.ts +9 -0
  120. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.guard.ts +29 -0
  121. package/dist/templates/modules/api-key-auth/files/apps/api/src/api-key/api-key.module.ts +9 -0
  122. package/dist/templates/modules/api-key-auth/files/apps/api/src/machine/machine.controller.ts +14 -0
  123. package/dist/templates/modules/api-key-auth/module.manifest.json +19 -0
  124. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-log.entity.ts +25 -0
  125. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.controller.ts +16 -0
  126. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.interceptor.ts +39 -0
  127. package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +13 -0
  128. package/dist/templates/modules/audit-log/files/apps/api/src/migrations/1720300000000-InitAuditLogs.ts +25 -0
  129. package/dist/templates/modules/audit-log/module.manifest.json +16 -0
  130. package/dist/templates/modules/auth/files/apps/api/src/account/account.controller.ts +13 -0
  131. package/dist/templates/modules/auth/files/apps/api/src/account/account.module.ts +5 -0
  132. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +36 -0
  133. package/dist/templates/modules/auth/files/apps/api/src/health/health.controller.ts +26 -0
  134. package/dist/templates/modules/auth/module.manifest.json +70 -0
  135. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/demo.processor.ts +12 -0
  136. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/dto/create-job.dto.ts +9 -0
  137. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/jobs.controller.ts +29 -0
  138. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/jobs.module.ts +15 -0
  139. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/queue.ts +8 -0
  140. package/dist/templates/modules/bullmq/files/apps/api/src/jobs/worker.module.ts +20 -0
  141. package/dist/templates/modules/bullmq/files/apps/api/src/main-worker.ts +14 -0
  142. package/dist/templates/modules/bullmq/files/infra/docker/worker.compose.example.yml +18 -0
  143. package/dist/templates/modules/bullmq/files/infra/k3s/worker-deployment.yaml +22 -0
  144. package/dist/templates/modules/bullmq/module.manifest.json +36 -0
  145. package/dist/templates/modules/file-upload/files/apps/api/src/files/files.controller.ts +29 -0
  146. package/dist/templates/modules/file-upload/files/apps/api/src/files/files.module.ts +9 -0
  147. package/dist/templates/modules/file-upload/module.manifest.json +19 -0
  148. package/dist/templates/modules/job-progress/files/apps/api/src/progress/dto/start-job.dto.ts +11 -0
  149. package/dist/templates/modules/job-progress/files/apps/api/src/progress/job-progress.module.ts +13 -0
  150. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.bridge.ts +19 -0
  151. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.controller.ts +17 -0
  152. package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.processor.ts +25 -0
  153. package/dist/templates/modules/job-progress/module.manifest.json +23 -0
  154. package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +29 -0
  155. package/dist/templates/modules/logging/module.manifest.json +27 -0
  156. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/dto/put-object.dto.ts +8 -0
  157. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.config.ts +31 -0
  158. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.controller.ts +29 -0
  159. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.module.ts +11 -0
  160. package/dist/templates/modules/object-storage-s3/files/apps/api/src/storage/storage.service.ts +37 -0
  161. package/dist/templates/modules/object-storage-s3/files/infra/docker/minio.compose.yml +33 -0
  162. package/dist/templates/modules/object-storage-s3/module.manifest.json +31 -0
  163. package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.ts +26 -0
  164. package/dist/templates/modules/rate-limit/module.manifest.json +25 -0
  165. package/dist/templates/modules/redis/files/apps/api/src/redis/cache.controller.ts +21 -0
  166. package/dist/templates/modules/redis/files/apps/api/src/redis/dto/set-cache.dto.ts +14 -0
  167. package/dist/templates/modules/redis/files/apps/api/src/redis/redis.module.ts +12 -0
  168. package/dist/templates/modules/redis/files/apps/api/src/redis/redis.service.ts +43 -0
  169. package/dist/templates/modules/redis/module.manifest.json +21 -0
  170. package/dist/templates/modules/sse/files/apps/api/src/events/dto/publish-event.dto.ts +8 -0
  171. package/dist/templates/modules/sse/files/apps/api/src/events/events.controller.ts +25 -0
  172. package/dist/templates/modules/sse/files/apps/api/src/events/events.module.ts +12 -0
  173. package/dist/templates/modules/sse/files/apps/api/src/events/events.service.ts +17 -0
  174. package/dist/templates/modules/sse/module.manifest.json +16 -0
  175. package/dist/templates/todo/README.md +40 -0
  176. package/dist/templates/todo/apps/api/Dockerfile +22 -0
  177. package/dist/templates/todo/apps/api/nest-cli.json +5 -0
  178. package/dist/templates/todo/apps/api/package.json +44 -0
  179. package/dist/templates/todo/apps/api/src/app.module.ts +22 -0
  180. package/dist/templates/todo/apps/api/src/common/all-exceptions.filter.ts +43 -0
  181. package/dist/templates/todo/apps/api/src/common/app-exception.ts +12 -0
  182. package/dist/templates/todo/apps/api/src/config/env.validation.ts +23 -0
  183. package/dist/templates/todo/apps/api/src/database/data-source.ts +19 -0
  184. package/dist/templates/todo/apps/api/src/health/health.controller.ts +23 -0
  185. package/dist/templates/todo/apps/api/src/health/health.module.ts +7 -0
  186. package/dist/templates/todo/apps/api/src/main.ts +29 -0
  187. package/dist/templates/todo/apps/api/src/migrations/1720100000000-InitTodos.ts +22 -0
  188. package/dist/templates/todo/apps/api/src/todos/dto/create-todo.dto.ts +10 -0
  189. package/dist/templates/todo/apps/api/src/todos/dto/update-todo.dto.ts +10 -0
  190. package/dist/templates/todo/apps/api/src/todos/todo.entity.ts +16 -0
  191. package/dist/templates/todo/apps/api/src/todos/todos.controller.ts +38 -0
  192. package/dist/templates/todo/apps/api/src/todos/todos.module.ts +12 -0
  193. package/dist/templates/todo/apps/api/src/todos/todos.service.ts +41 -0
  194. package/dist/templates/todo/apps/api/test/health.e2e-spec.ts +23 -0
  195. package/dist/templates/todo/apps/api/tsconfig.json +21 -0
  196. package/dist/templates/todo/apps/web/Dockerfile +22 -0
  197. package/dist/templates/todo/apps/web/components.json +15 -0
  198. package/dist/templates/todo/apps/web/package.json +36 -0
  199. package/dist/templates/todo/apps/web/src/app.css +81 -0
  200. package/dist/templates/todo/apps/web/src/app.d.ts +11 -0
  201. package/dist/templates/todo/apps/web/src/app.html +11 -0
  202. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-action.svelte +20 -0
  203. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-description.svelte +23 -0
  204. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert-title.svelte +23 -0
  205. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/alert.svelte +43 -0
  206. package/dist/templates/todo/apps/web/src/lib/components/ui/alert/index.ts +17 -0
  207. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-badge.svelte +26 -0
  208. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte +20 -0
  209. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group-count.svelte +23 -0
  210. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-group.svelte +23 -0
  211. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar-image.svelte +17 -0
  212. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/avatar.svelte +26 -0
  213. package/dist/templates/todo/apps/web/src/lib/components/ui/avatar/index.ts +22 -0
  214. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/badge.svelte +49 -0
  215. package/dist/templates/todo/apps/web/src/lib/components/ui/badge/index.ts +2 -0
  216. package/dist/templates/todo/apps/web/src/lib/components/ui/button/button.svelte +82 -0
  217. package/dist/templates/todo/apps/web/src/lib/components/ui/button/index.ts +17 -0
  218. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-action.svelte +23 -0
  219. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-content.svelte +20 -0
  220. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-description.svelte +20 -0
  221. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-footer.svelte +20 -0
  222. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-header.svelte +23 -0
  223. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card-title.svelte +20 -0
  224. package/dist/templates/todo/apps/web/src/lib/components/ui/card/card.svelte +22 -0
  225. package/dist/templates/todo/apps/web/src/lib/components/ui/card/index.ts +25 -0
  226. package/dist/templates/todo/apps/web/src/lib/components/ui/checkbox/checkbox.svelte +39 -0
  227. package/dist/templates/todo/apps/web/src/lib/components/ui/checkbox/index.ts +6 -0
  228. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-close.svelte +11 -0
  229. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-content.svelte +48 -0
  230. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  231. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-footer.svelte +32 -0
  232. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  233. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte +17 -0
  234. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  235. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  236. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog-trigger.svelte +11 -0
  237. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  238. package/dist/templates/todo/apps/web/src/lib/components/ui/dialog/index.ts +34 -0
  239. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
  240. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
  241. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
  242. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
  243. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
  244. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
  245. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +24 -0
  246. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
  247. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
  248. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
  249. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  250. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
  251. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +17 -0
  252. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
  253. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
  254. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
  255. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  256. package/dist/templates/todo/apps/web/src/lib/components/ui/dropdown-menu/index.ts +54 -0
  257. package/dist/templates/todo/apps/web/src/lib/components/ui/input/index.ts +7 -0
  258. package/dist/templates/todo/apps/web/src/lib/components/ui/input/input.svelte +48 -0
  259. package/dist/templates/todo/apps/web/src/lib/components/ui/label/index.ts +7 -0
  260. package/dist/templates/todo/apps/web/src/lib/components/ui/label/label.svelte +20 -0
  261. package/dist/templates/todo/apps/web/src/lib/components/ui/select/index.ts +37 -0
  262. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-content.svelte +45 -0
  263. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  264. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-group.svelte +17 -0
  265. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-item.svelte +40 -0
  266. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-label.svelte +20 -0
  267. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-portal.svelte +7 -0
  268. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  269. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  270. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-separator.svelte +18 -0
  271. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select-trigger.svelte +29 -0
  272. package/dist/templates/todo/apps/web/src/lib/components/ui/select/select.svelte +11 -0
  273. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/index.ts +7 -0
  274. package/dist/templates/todo/apps/web/src/lib/components/ui/separator/separator.svelte +23 -0
  275. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/index.ts +7 -0
  276. package/dist/templates/todo/apps/web/src/lib/components/ui/skeleton/skeleton.svelte +17 -0
  277. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/index.ts +1 -0
  278. package/dist/templates/todo/apps/web/src/lib/components/ui/sonner/sonner.svelte +34 -0
  279. package/dist/templates/todo/apps/web/src/lib/components/ui/table/index.ts +28 -0
  280. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-body.svelte +15 -0
  281. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-caption.svelte +20 -0
  282. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-cell.svelte +15 -0
  283. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-footer.svelte +20 -0
  284. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-head.svelte +15 -0
  285. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-header.svelte +20 -0
  286. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table-row.svelte +15 -0
  287. package/dist/templates/todo/apps/web/src/lib/components/ui/table/table.svelte +17 -0
  288. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/index.ts +18 -0
  289. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  290. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-list.svelte +40 -0
  291. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte +23 -0
  292. package/dist/templates/todo/apps/web/src/lib/components/ui/tabs/tabs.svelte +19 -0
  293. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/index.ts +19 -0
  294. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte +52 -0
  295. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte +7 -0
  296. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte +7 -0
  297. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  298. package/dist/templates/todo/apps/web/src/lib/components/ui/tooltip/tooltip.svelte +7 -0
  299. package/dist/templates/todo/apps/web/src/lib/i18n/README.md +7 -0
  300. package/dist/templates/todo/apps/web/src/lib/i18n/en.ts +10 -0
  301. package/dist/templates/todo/apps/web/src/lib/i18n/ko.ts +11 -0
  302. package/dist/templates/todo/apps/web/src/lib/server/backend-proxy.ts +16 -0
  303. package/dist/templates/todo/apps/web/src/lib/utils.ts +11 -0
  304. package/dist/templates/todo/apps/web/src/routes/+layout.svelte +9 -0
  305. package/dist/templates/todo/apps/web/src/routes/+page.svelte +95 -0
  306. package/dist/templates/todo/apps/web/src/routes/api/health/+server.ts +12 -0
  307. package/dist/templates/todo/apps/web/src/routes/api/todos/+server.ts +24 -0
  308. package/dist/templates/todo/apps/web/src/routes/api/todos/[id]/+server.ts +24 -0
  309. package/dist/templates/todo/apps/web/static/.gitkeep +0 -0
  310. package/dist/templates/todo/apps/web/svelte.config.js +15 -0
  311. package/dist/templates/todo/apps/web/tsconfig.json +9 -0
  312. package/dist/templates/todo/apps/web/vite.config.ts +7 -0
  313. package/dist/templates/todo/dot-env.example +16 -0
  314. package/dist/templates/todo/dot-gitignore +9 -0
  315. package/dist/templates/todo/infra/docker/docker-compose.yml +29 -0
  316. package/dist/templates/todo/infra/k3s/api-deployment.yaml +24 -0
  317. package/dist/templates/todo/infra/k3s/configmap.yaml +10 -0
  318. package/dist/templates/todo/infra/k3s/ingress.yaml +18 -0
  319. package/dist/templates/todo/infra/k3s/namespace.yaml +4 -0
  320. package/dist/templates/todo/infra/k3s/secret.example.yaml +10 -0
  321. package/dist/templates/todo/infra/k3s/services.yaml +21 -0
  322. package/dist/templates/todo/infra/k3s/web-deployment.yaml +20 -0
  323. package/dist/templates/todo/package.json +13 -0
  324. package/dist/templates.d.ts +10 -0
  325. package/dist/templates.js +33 -0
  326. package/package.json +2 -2
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
11
+ </script>
12
+
13
+ <caption
14
+ bind:this={ref}
15
+ data-slot="table-caption"
16
+ class={cn("text-muted-foreground mt-4 text-sm", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </caption>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLTdAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLTdAttributes> = $props();
11
+ </script>
12
+
13
+ <td bind:this={ref} data-slot="table-cell" class={cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0", className)} {...restProps}>
14
+ {@render children?.()}
15
+ </td>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
11
+ </script>
12
+
13
+ <tfoot
14
+ bind:this={ref}
15
+ data-slot="table-footer"
16
+ class={cn("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </tfoot>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLThAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLThAttributes> = $props();
11
+ </script>
12
+
13
+ <th bind:this={ref} data-slot="table-head" class={cn("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0", className)} {...restProps}>
14
+ {@render children?.()}
15
+ </th>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
11
+ </script>
12
+
13
+ <thead
14
+ bind:this={ref}
15
+ data-slot="table-header"
16
+ class={cn("[&_tr]:border-b", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </thead>
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "$lib/utils.js";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLTableRowElement>> = $props();
11
+ </script>
12
+
13
+ <tr bind:this={ref} data-slot="table-row" class={cn("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", className)} {...restProps}>
14
+ {@render children?.()}
15
+ </tr>
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import type { HTMLTableAttributes } 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<HTMLTableAttributes> = $props();
11
+ </script>
12
+
13
+ <div data-slot="table-container" class="relative w-full overflow-x-auto">
14
+ <table bind:this={ref} data-slot="table" class={cn("w-full caption-bottom text-sm", className)} {...restProps}>
15
+ {@render children?.()}
16
+ </table>
17
+ </div>
@@ -0,0 +1,18 @@
1
+ import Root from "./tabs.svelte";
2
+ import Content from "./tabs-content.svelte";
3
+ import List, { tabsListVariants, type TabsListVariant } from "./tabs-list.svelte";
4
+ import Trigger from "./tabs-trigger.svelte";
5
+
6
+ export {
7
+ Root,
8
+ Content,
9
+ List,
10
+ Trigger,
11
+ tabsListVariants,
12
+ type TabsListVariant,
13
+ //
14
+ Root as Tabs,
15
+ Content as TabsContent,
16
+ List as TabsList,
17
+ Trigger as TabsTrigger,
18
+ };
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import { Tabs as TabsPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: TabsPrimitive.ContentProps = $props();
10
+ </script>
11
+
12
+ <TabsPrimitive.Content
13
+ bind:ref
14
+ data-slot="tabs-content"
15
+ class={cn("text-sm flex-1 outline-none", className)}
16
+ {...restProps}
17
+ />
@@ -0,0 +1,40 @@
1
+ <script lang="ts" module>
2
+ import { tv, type VariantProps } from "tailwind-variants";
3
+
4
+ export const tabsListVariants = tv({
5
+ base: "rounded-lg p-[3px] group-data-horizontal/tabs:h-8 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
6
+ variants: {
7
+ variant: {
8
+ default: "cn-tabs-list-variant-default bg-muted",
9
+ line: "cn-tabs-list-variant-line gap-1 bg-transparent",
10
+ },
11
+ },
12
+ defaultVariants: {
13
+ variant: "default",
14
+ },
15
+ });
16
+
17
+ export type TabsListVariant = VariantProps<typeof tabsListVariants>["variant"];
18
+ </script>
19
+
20
+ <script lang="ts">
21
+ import { Tabs as TabsPrimitive } from "bits-ui";
22
+ import { cn } from "$lib/utils.js";
23
+
24
+ let {
25
+ ref = $bindable(null),
26
+ variant = "default",
27
+ class: className,
28
+ ...restProps
29
+ }: TabsPrimitive.ListProps & {
30
+ variant?: TabsListVariant;
31
+ } = $props();
32
+ </script>
33
+
34
+ <TabsPrimitive.List
35
+ bind:ref
36
+ data-slot="tabs-list"
37
+ data-variant={variant}
38
+ class={cn(tabsListVariants({ variant }), className)}
39
+ {...restProps}
40
+ />
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import { Tabs as TabsPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: TabsPrimitive.TriggerProps = $props();
10
+ </script>
11
+
12
+ <TabsPrimitive.Trigger
13
+ bind:ref
14
+ data-slot="tabs-trigger"
15
+ class={cn(
16
+ "gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg:not([class*='size-'])]:size-4 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
17
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
18
+ "data-active:bg-background dark:data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 data-active:text-foreground",
19
+ "after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
20
+ className
21
+ )}
22
+ {...restProps}
23
+ />
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import { Tabs as TabsPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ value = $bindable(""),
8
+ class: className,
9
+ ...restProps
10
+ }: TabsPrimitive.RootProps = $props();
11
+ </script>
12
+
13
+ <TabsPrimitive.Root
14
+ bind:ref
15
+ bind:value
16
+ data-slot="tabs"
17
+ class={cn("gap-2 group/tabs flex data-[orientation=horizontal]:flex-col", className)}
18
+ {...restProps}
19
+ />
@@ -0,0 +1,19 @@
1
+ import Root from "./tooltip.svelte";
2
+ import Trigger from "./tooltip-trigger.svelte";
3
+ import Content from "./tooltip-content.svelte";
4
+ import Provider from "./tooltip-provider.svelte";
5
+ import Portal from "./tooltip-portal.svelte";
6
+
7
+ export {
8
+ Root,
9
+ Trigger,
10
+ Content,
11
+ Provider,
12
+ Portal,
13
+ //
14
+ Root as Tooltip,
15
+ Content as TooltipContent,
16
+ Trigger as TooltipTrigger,
17
+ Provider as TooltipProvider,
18
+ Portal as TooltipPortal,
19
+ };
@@ -0,0 +1,52 @@
1
+ <script lang="ts">
2
+ import { Tooltip as TooltipPrimitive } from "bits-ui";
3
+ import { cn } from "$lib/utils.js";
4
+ import TooltipPortal from "./tooltip-portal.svelte";
5
+ import type { ComponentProps } from "svelte";
6
+ import type { WithoutChildrenOrChild } from "$lib/utils.js";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ sideOffset = 0,
12
+ side = "top",
13
+ children,
14
+ arrowClasses,
15
+ portalProps,
16
+ ...restProps
17
+ }: TooltipPrimitive.ContentProps & {
18
+ arrowClasses?: string;
19
+ portalProps?: WithoutChildrenOrChild<ComponentProps<typeof TooltipPortal>>;
20
+ } = $props();
21
+ </script>
22
+
23
+ <TooltipPortal {...portalProps}>
24
+ <TooltipPrimitive.Content
25
+ bind:ref
26
+ data-slot="tooltip-content"
27
+ {sideOffset}
28
+ {side}
29
+ class={cn(
30
+ "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-data-[slot=kbd]:pr-1.5 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm bg-foreground text-background z-50 w-fit max-w-xs origin-(--bits-tooltip-content-transform-origin)",
31
+ className
32
+ )}
33
+ {...restProps}
34
+ >
35
+ {@render children?.()}
36
+ <TooltipPrimitive.Arrow>
37
+ {#snippet child({ props })}
38
+ <div
39
+ class={cn(
40
+ "size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground z-50",
41
+ "data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50%+2px)]",
42
+ "data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50%+1px)]",
43
+ "data-[side=right]:translate-x-[calc(50%+2px)] data-[side=right]:translate-y-1/2",
44
+ "data-[side=left]:-translate-y-[calc(50%-3px)]",
45
+ arrowClasses
46
+ )}
47
+ {...props}
48
+ ></div>
49
+ {/snippet}
50
+ </TooltipPrimitive.Arrow>
51
+ </TooltipPrimitive.Content>
52
+ </TooltipPortal>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ import { Tooltip as TooltipPrimitive } from "bits-ui";
3
+
4
+ let { ...restProps }: TooltipPrimitive.PortalProps = $props();
5
+ </script>
6
+
7
+ <TooltipPrimitive.Portal {...restProps} />
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ import { Tooltip as TooltipPrimitive } from "bits-ui";
3
+
4
+ let { delayDuration = 0, ...restProps }: TooltipPrimitive.ProviderProps = $props();
5
+ </script>
6
+
7
+ <TooltipPrimitive.Provider {delayDuration} {...restProps} />
@@ -0,0 +1,7 @@
1
+ <script lang="ts" generics="T = never">
2
+ import { Tooltip as TooltipPrimitive } from "bits-ui";
3
+
4
+ let { ref = $bindable(null), ...restProps }: TooltipPrimitive.TriggerProps<T> = $props();
5
+ </script>
6
+
7
+ <TooltipPrimitive.Trigger bind:ref data-slot="tooltip-trigger" {...restProps} />
@@ -0,0 +1,7 @@
1
+ <script lang="ts" generics="T = never">
2
+ import { Tooltip as TooltipPrimitive } from "bits-ui";
3
+
4
+ let { open = $bindable(false), ...restProps }: TooltipPrimitive.RootProps<T> = $props();
5
+ </script>
6
+
7
+ <TooltipPrimitive.Root bind:open {...restProps} />
@@ -1,8 +1,11 @@
1
- import type { Translation } from "typesafe-i18n";
1
+ import type { BaseTranslation } from "typesafe-i18n";
2
2
 
3
+ // Uses BaseTranslation until you generate typed runtimes with `npx typesafe-i18n`.
4
+ // After generating, switch to `import type { Translation } from "../i18n-types"`
5
+ // so this locale is checked against the base locale's keys.
3
6
  const ko = {
4
7
  appTitle: "{{projectName}}",
5
8
  checkHealth: "API 상태 확인",
6
- } satisfies Translation;
9
+ } satisfies BaseTranslation;
7
10
 
8
11
  export default ko;
@@ -0,0 +1,11 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]): string {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+
8
+ export type WithoutChild<T> = T extends { child?: unknown } ? Omit<T, "child"> : T;
9
+ export type WithoutChildren<T> = T extends { children?: unknown } ? Omit<T, "children"> : T;
10
+ export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
11
+ export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
@@ -1,4 +1,7 @@
1
1
  <script lang="ts">
2
+ import { Button } from "$lib/components/ui/button";
3
+ import * as Card from "$lib/components/ui/card";
4
+
2
5
  type Health = { status: string } | { error: string };
3
6
 
4
7
  let health = $state<Health | null>(null);
@@ -10,17 +13,21 @@
10
13
  </script>
11
14
 
12
15
  <main class="mx-auto flex min-h-full max-w-2xl flex-col gap-6 p-8">
13
- <h1 class="text-3xl font-bold">{{projectName}}</h1>
14
- <p class="text-sm opacity-70">Full-stack starter generated with PodoKit.</p>
15
-
16
- <button
17
- class="w-fit rounded-md border border-current/20 px-4 py-2 text-sm font-medium hover:opacity-80"
18
- onclick={check}
19
- >
20
- Check API health
21
- </button>
16
+ <div>
17
+ <h1 class="text-3xl font-bold">{{projectName}}</h1>
18
+ <p class="text-muted-foreground text-sm">Full-stack starter generated with PodoKit.</p>
19
+ </div>
22
20
 
23
- {#if health}
24
- <pre class="rounded-md bg-current/5 p-4 text-sm">{JSON.stringify(health, null, 2)}</pre>
25
- {/if}
21
+ <Card.Root>
22
+ <Card.Header>
23
+ <Card.Title>API health</Card.Title>
24
+ <Card.Description>Check the NestJS API through the SvelteKit server proxy.</Card.Description>
25
+ </Card.Header>
26
+ <Card.Content class="flex flex-col gap-4">
27
+ <Button class="w-fit" onclick={check}>Check API health</Button>
28
+ {#if health}
29
+ <pre class="bg-muted rounded-md p-4 text-sm">{JSON.stringify(health, null, 2)}</pre>
30
+ {/if}
31
+ </Card.Content>
32
+ </Card.Root>
26
33
  </main>
@@ -0,0 +1,9 @@
1
+ import { applyDecorators, UseGuards } from "@nestjs/common";
2
+ import { Public } from "@thallesp/nestjs-better-auth";
3
+ import { ApiKeyGuard } from "./api-key.guard";
4
+
5
+ // Opens a route to API-key holders: skips the user-session guard and
6
+ // requires a valid X-API-Key instead. For machine/service clients.
7
+ export function ApiKeyProtected(): ReturnType<typeof applyDecorators> {
8
+ return applyDecorators(Public(), UseGuards(ApiKeyGuard));
9
+ }
@@ -0,0 +1,29 @@
1
+ import { type CanActivate, type ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
2
+ import { timingSafeEqual } from "node:crypto";
3
+ import type { Request } from "express";
4
+
5
+ // Validates the X-API-Key header against the API_KEYS allowlist.
6
+ @Injectable()
7
+ export class ApiKeyGuard implements CanActivate {
8
+ private readonly keys = (process.env.API_KEYS ?? "")
9
+ .split(",")
10
+ .map((key) => key.trim())
11
+ .filter(Boolean);
12
+
13
+ canActivate(context: ExecutionContext): boolean {
14
+ const request = context.switchToHttp().getRequest<Request>();
15
+ const provided = request.header("x-api-key");
16
+ if (!provided) {
17
+ throw new UnauthorizedException("Missing X-API-Key");
18
+ }
19
+ const supplied = Buffer.from(provided);
20
+ const valid = this.keys.some((key) => {
21
+ const expected = Buffer.from(key);
22
+ return expected.length === supplied.length && timingSafeEqual(expected, supplied);
23
+ });
24
+ if (!valid) {
25
+ throw new UnauthorizedException("Invalid API key");
26
+ }
27
+ return true;
28
+ }
29
+ }
@@ -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
+ }