@hed-hog/core 0.0.387 → 0.0.390

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 (535) hide show
  1. package/README.md +12 -11
  2. package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
  3. package/dist/access-log/access-log.interceptor.js +4 -2
  4. package/dist/access-log/access-log.interceptor.js.map +1 -1
  5. package/dist/ai/ai-attachment.fragments.d.ts +23 -0
  6. package/dist/ai/ai-attachment.fragments.d.ts.map +1 -0
  7. package/dist/ai/ai-attachment.fragments.js +34 -0
  8. package/dist/ai/ai-attachment.fragments.js.map +1 -0
  9. package/dist/ai/ai.controller.d.ts +7 -16
  10. package/dist/ai/ai.controller.d.ts.map +1 -1
  11. package/dist/ai/ai.prompts.d.ts +16 -0
  12. package/dist/ai/ai.prompts.d.ts.map +1 -0
  13. package/dist/ai/ai.prompts.js +37 -0
  14. package/dist/ai/ai.prompts.js.map +1 -0
  15. package/dist/ai/ai.service.d.ts +63 -12
  16. package/dist/ai/ai.service.d.ts.map +1 -1
  17. package/dist/ai/ai.service.js +215 -88
  18. package/dist/ai/ai.service.js.map +1 -1
  19. package/dist/ai/dto/chat.dto.d.ts +4 -1
  20. package/dist/ai/dto/chat.dto.d.ts.map +1 -1
  21. package/dist/ai/dto/chat.dto.js +23 -1
  22. package/dist/ai/dto/chat.dto.js.map +1 -1
  23. package/dist/ai/dto/create-agent.dto.d.ts +1 -1
  24. package/dist/ai/dto/create-agent.dto.d.ts.map +1 -1
  25. package/dist/ai/dto/create-agent.dto.js +1 -1
  26. package/dist/ai/dto/create-agent.dto.js.map +1 -1
  27. package/dist/ai/dto/update-agent.dto.d.ts +1 -1
  28. package/dist/ai/dto/update-agent.dto.d.ts.map +1 -1
  29. package/dist/ai/dto/update-agent.dto.js +1 -1
  30. package/dist/ai/dto/update-agent.dto.js.map +1 -1
  31. package/dist/ai-instruction/ai-instruction.controller.d.ts +61 -7
  32. package/dist/ai-instruction/ai-instruction.controller.d.ts.map +1 -1
  33. package/dist/ai-instruction/ai-instruction.controller.js +63 -20
  34. package/dist/ai-instruction/ai-instruction.controller.js.map +1 -1
  35. package/dist/ai-instruction/ai-instruction.module.d.ts.map +1 -1
  36. package/dist/ai-instruction/ai-instruction.module.js +13 -2
  37. package/dist/ai-instruction/ai-instruction.module.js.map +1 -1
  38. package/dist/ai-instruction/ai-instruction.service.d.ts +131 -6
  39. package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
  40. package/dist/ai-instruction/ai-instruction.service.js +533 -60
  41. package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
  42. package/dist/ai-instruction/ai-prompt-builder.service.d.ts +8 -0
  43. package/dist/ai-instruction/ai-prompt-builder.service.d.ts.map +1 -1
  44. package/dist/ai-instruction/ai-prompt-builder.service.js +10 -1
  45. package/dist/ai-instruction/ai-prompt-builder.service.js.map +1 -1
  46. package/dist/ai-instruction/ai-prompt-registry.d.ts +45 -0
  47. package/dist/ai-instruction/ai-prompt-registry.d.ts.map +1 -0
  48. package/dist/ai-instruction/ai-prompt-registry.js +49 -0
  49. package/dist/ai-instruction/ai-prompt-registry.js.map +1 -0
  50. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +89 -0
  51. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -0
  52. package/dist/ai-instruction/ai-prompt-resolver.service.js +222 -0
  53. package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -0
  54. package/dist/ai-instruction/ai-prompt-template.util.d.ts +70 -0
  55. package/dist/ai-instruction/ai-prompt-template.util.d.ts.map +1 -0
  56. package/dist/ai-instruction/ai-prompt-template.util.js +154 -0
  57. package/dist/ai-instruction/ai-prompt-template.util.js.map +1 -0
  58. package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts +5 -0
  59. package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts.map +1 -1
  60. package/dist/ai-instruction/dto/create-ai-instruction.dto.js +27 -1
  61. package/dist/ai-instruction/dto/create-ai-instruction.dto.js.map +1 -1
  62. package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts +14 -0
  63. package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts.map +1 -0
  64. package/dist/ai-instruction/dto/preview-ai-instruction.dto.js +42 -0
  65. package/dist/ai-instruction/dto/preview-ai-instruction.dto.js.map +1 -0
  66. package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts +11 -0
  67. package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts.map +1 -1
  68. package/dist/ai-instruction/dto/update-ai-instruction.dto.js +34 -0
  69. package/dist/ai-instruction/dto/update-ai-instruction.dto.js.map +1 -1
  70. package/dist/ai-instruction/types/ai-instruction.types.d.ts +13 -1
  71. package/dist/ai-instruction/types/ai-instruction.types.d.ts.map +1 -1
  72. package/dist/ai-instruction/types/ai-instruction.types.js +10 -0
  73. package/dist/ai-instruction/types/ai-instruction.types.js.map +1 -1
  74. package/dist/auth/auth.controller.d.ts +24 -9
  75. package/dist/auth/auth.controller.d.ts.map +1 -1
  76. package/dist/auth/auth.controller.js +49 -21
  77. package/dist/auth/auth.controller.js.map +1 -1
  78. package/dist/auth/auth.service.d.ts +33 -8
  79. package/dist/auth/auth.service.d.ts.map +1 -1
  80. package/dist/auth/auth.service.js +78 -29
  81. package/dist/auth/auth.service.js.map +1 -1
  82. package/dist/captcha/captcha.module.d.ts +3 -0
  83. package/dist/captcha/captcha.module.d.ts.map +1 -0
  84. package/dist/captcha/captcha.module.js +23 -0
  85. package/dist/captcha/captcha.module.js.map +1 -0
  86. package/dist/captcha/captcha.service.d.ts +38 -0
  87. package/dist/captcha/captcha.service.d.ts.map +1 -0
  88. package/dist/captcha/captcha.service.js +144 -0
  89. package/dist/captcha/captcha.service.js.map +1 -0
  90. package/dist/challenge/challenge.service.d.ts +16 -7
  91. package/dist/challenge/challenge.service.d.ts.map +1 -1
  92. package/dist/challenge/challenge.service.js +64 -16
  93. package/dist/challenge/challenge.service.js.map +1 -1
  94. package/dist/core.module.d.ts +3 -1
  95. package/dist/core.module.d.ts.map +1 -1
  96. package/dist/core.module.js +29 -2
  97. package/dist/core.module.js.map +1 -1
  98. package/dist/dashboard/dashboard/dashboard.controller.d.ts +15 -15
  99. package/dist/dashboard/dashboard/dashboard.service.d.ts +15 -15
  100. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +6 -6
  101. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +6 -6
  102. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +20 -20
  103. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +20 -20
  104. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +1 -1
  105. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +1 -1
  106. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +13 -13
  107. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +13 -13
  108. package/dist/file/file.service.d.ts +6 -0
  109. package/dist/file/file.service.d.ts.map +1 -1
  110. package/dist/file/file.service.js +44 -4
  111. package/dist/file/file.service.js.map +1 -1
  112. package/dist/incident/incident-notifier.service.d.ts +36 -0
  113. package/dist/incident/incident-notifier.service.d.ts.map +1 -0
  114. package/dist/incident/incident-notifier.service.js +208 -0
  115. package/dist/incident/incident-notifier.service.js.map +1 -0
  116. package/dist/incident/incident.controller.d.ts +23 -0
  117. package/dist/incident/incident.controller.d.ts.map +1 -0
  118. package/dist/incident/incident.controller.js +75 -0
  119. package/dist/incident/incident.controller.js.map +1 -0
  120. package/dist/incident/incident.module.d.ts +7 -0
  121. package/dist/incident/incident.module.d.ts.map +1 -0
  122. package/dist/incident/incident.module.js +32 -0
  123. package/dist/incident/incident.module.js.map +1 -0
  124. package/dist/incident/incident.service.d.ts +72 -0
  125. package/dist/incident/incident.service.d.ts.map +1 -0
  126. package/dist/incident/incident.service.js +184 -0
  127. package/dist/incident/incident.service.js.map +1 -0
  128. package/dist/index.d.ts +26 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +30 -0
  131. package/dist/index.js.map +1 -1
  132. package/dist/integration-profile/dto/test.dto.d.ts +13 -0
  133. package/dist/integration-profile/dto/test.dto.d.ts.map +1 -0
  134. package/dist/integration-profile/dto/test.dto.js +26 -0
  135. package/dist/integration-profile/dto/test.dto.js.map +1 -0
  136. package/dist/integration-profile/integration-profile.controller.d.ts +12 -1
  137. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
  138. package/dist/integration-profile/integration-profile.controller.js +9 -1
  139. package/dist/integration-profile/integration-profile.controller.js.map +1 -1
  140. package/dist/integration-profile/integration-profile.module.d.ts +6 -1
  141. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
  142. package/dist/integration-profile/integration-profile.module.js +26 -3
  143. package/dist/integration-profile/integration-profile.module.js.map +1 -1
  144. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  145. package/dist/integration-profile/integration-profile.secrets.js +9 -1
  146. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  147. package/dist/integration-profile/integration-profile.service.d.ts +26 -7
  148. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  149. package/dist/integration-profile/integration-profile.service.js +94 -91
  150. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  151. package/dist/integration-profile/integration-profile.utils.d.ts +13 -1
  152. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  153. package/dist/integration-profile/integration-profile.utils.js +20 -5
  154. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  155. package/dist/integration-profile/testers/ai.testers.d.ts +3 -0
  156. package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -0
  157. package/dist/integration-profile/testers/ai.testers.js +125 -0
  158. package/dist/integration-profile/testers/ai.testers.js.map +1 -0
  159. package/dist/integration-profile/testers/captcha.testers.d.ts +3 -0
  160. package/dist/integration-profile/testers/captcha.testers.d.ts.map +1 -0
  161. package/dist/integration-profile/testers/captcha.testers.js +121 -0
  162. package/dist/integration-profile/testers/captcha.testers.js.map +1 -0
  163. package/dist/integration-profile/testers/email.testers.d.ts +3 -0
  164. package/dist/integration-profile/testers/email.testers.d.ts.map +1 -0
  165. package/dist/integration-profile/testers/email.testers.js +128 -0
  166. package/dist/integration-profile/testers/email.testers.js.map +1 -0
  167. package/dist/integration-profile/testers/http-probe.d.ts +57 -0
  168. package/dist/integration-profile/testers/http-probe.d.ts.map +1 -0
  169. package/dist/integration-profile/testers/http-probe.js +140 -0
  170. package/dist/integration-profile/testers/http-probe.js.map +1 -0
  171. package/dist/integration-profile/testers/index.d.ts +12 -0
  172. package/dist/integration-profile/testers/index.d.ts.map +1 -0
  173. package/dist/integration-profile/testers/index.js +45 -0
  174. package/dist/integration-profile/testers/index.js.map +1 -0
  175. package/dist/integration-profile/testers/infrastructure.testers.d.ts +3 -0
  176. package/dist/integration-profile/testers/infrastructure.testers.d.ts.map +1 -0
  177. package/dist/integration-profile/testers/infrastructure.testers.js +105 -0
  178. package/dist/integration-profile/testers/infrastructure.testers.js.map +1 -0
  179. package/dist/integration-profile/testers/integration-tester.registry.d.ts +17 -0
  180. package/dist/integration-profile/testers/integration-tester.registry.d.ts.map +1 -0
  181. package/dist/integration-profile/testers/integration-tester.registry.js +52 -0
  182. package/dist/integration-profile/testers/integration-tester.registry.js.map +1 -0
  183. package/dist/integration-profile/testers/integration-tester.types.d.ts +55 -0
  184. package/dist/integration-profile/testers/integration-tester.types.d.ts.map +1 -0
  185. package/dist/integration-profile/testers/integration-tester.types.js +16 -0
  186. package/dist/integration-profile/testers/integration-tester.types.js.map +1 -0
  187. package/dist/integration-profile/testers/messaging.testers.d.ts +3 -0
  188. package/dist/integration-profile/testers/messaging.testers.d.ts.map +1 -0
  189. package/dist/integration-profile/testers/messaging.testers.js +70 -0
  190. package/dist/integration-profile/testers/messaging.testers.js.map +1 -0
  191. package/dist/integration-profile/testers/oauth.testers.d.ts +3 -0
  192. package/dist/integration-profile/testers/oauth.testers.d.ts.map +1 -0
  193. package/dist/integration-profile/testers/oauth.testers.js +285 -0
  194. package/dist/integration-profile/testers/oauth.testers.js.map +1 -0
  195. package/dist/integration-profile/testers/payment.testers.d.ts +3 -0
  196. package/dist/integration-profile/testers/payment.testers.d.ts.map +1 -0
  197. package/dist/integration-profile/testers/payment.testers.js +169 -0
  198. package/dist/integration-profile/testers/payment.testers.js.map +1 -0
  199. package/dist/integration-profile/testers/storage.testers.d.ts +3 -0
  200. package/dist/integration-profile/testers/storage.testers.d.ts.map +1 -0
  201. package/dist/integration-profile/testers/storage.testers.js +208 -0
  202. package/dist/integration-profile/testers/storage.testers.js.map +1 -0
  203. package/dist/language/en.json +4 -2
  204. package/dist/language/pt.json +4 -2
  205. package/dist/leaked-password/leaked-password.controller.d.ts +24 -0
  206. package/dist/leaked-password/leaked-password.controller.d.ts.map +1 -0
  207. package/dist/leaked-password/leaked-password.controller.js +78 -0
  208. package/dist/leaked-password/leaked-password.controller.js.map +1 -0
  209. package/dist/leaked-password/leaked-password.module.d.ts +8 -0
  210. package/dist/leaked-password/leaked-password.module.d.ts.map +1 -0
  211. package/dist/leaked-password/leaked-password.module.js +31 -0
  212. package/dist/leaked-password/leaked-password.module.js.map +1 -0
  213. package/dist/leaked-password/leaked-password.service.d.ts +64 -0
  214. package/dist/leaked-password/leaked-password.service.d.ts.map +1 -0
  215. package/dist/leaked-password/leaked-password.service.js +218 -0
  216. package/dist/leaked-password/leaked-password.service.js.map +1 -0
  217. package/dist/locale/locale.controller.d.ts +1 -1
  218. package/dist/locale/locale.service.d.ts +1 -1
  219. package/dist/mail/dto/preview.dto.d.ts +18 -0
  220. package/dist/mail/dto/preview.dto.d.ts.map +1 -0
  221. package/dist/mail/dto/preview.dto.js +66 -0
  222. package/dist/mail/dto/preview.dto.js.map +1 -0
  223. package/dist/mail/dto/send.dto.d.ts +7 -0
  224. package/dist/mail/dto/send.dto.d.ts.map +1 -1
  225. package/dist/mail/dto/send.dto.js +10 -0
  226. package/dist/mail/dto/send.dto.js.map +1 -1
  227. package/dist/mail/mail.controller.d.ts +4 -0
  228. package/dist/mail/mail.controller.d.ts.map +1 -1
  229. package/dist/mail/mail.controller.js +16 -2
  230. package/dist/mail/mail.controller.js.map +1 -1
  231. package/dist/mail/mail.service.d.ts +23 -2
  232. package/dist/mail/mail.service.d.ts.map +1 -1
  233. package/dist/mail/mail.service.js +102 -13
  234. package/dist/mail/mail.service.js.map +1 -1
  235. package/dist/mail-layout/dto/update.dto.d.ts +17 -0
  236. package/dist/mail-layout/dto/update.dto.d.ts.map +1 -0
  237. package/dist/mail-layout/dto/update.dto.js +27 -0
  238. package/dist/mail-layout/dto/update.dto.js.map +1 -0
  239. package/dist/mail-layout/mail-layout.controller.d.ts +15 -0
  240. package/dist/mail-layout/mail-layout.controller.d.ts.map +1 -0
  241. package/dist/mail-layout/mail-layout.controller.js +71 -0
  242. package/dist/mail-layout/mail-layout.controller.js.map +1 -0
  243. package/dist/mail-layout/mail-layout.module.d.ts +3 -0
  244. package/dist/mail-layout/mail-layout.module.d.ts.map +1 -0
  245. package/dist/mail-layout/mail-layout.module.js +35 -0
  246. package/dist/mail-layout/mail-layout.module.js.map +1 -0
  247. package/dist/mail-layout/mail-layout.service.d.ts +27 -0
  248. package/dist/mail-layout/mail-layout.service.d.ts.map +1 -0
  249. package/dist/mail-layout/mail-layout.service.js +80 -0
  250. package/dist/mail-layout/mail-layout.service.js.map +1 -0
  251. package/dist/mcp-chat/mcp-chat.controller.d.ts +2 -2
  252. package/dist/mcp-chat/mcp-chat.service.d.ts +24 -2
  253. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  254. package/dist/mcp-chat/mcp-chat.service.js +80 -24
  255. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  256. package/dist/menu/menu.controller.d.ts +3 -3
  257. package/dist/menu/menu.service.d.ts +3 -3
  258. package/dist/notification/notification.controller.d.ts +12 -12
  259. package/dist/notification/notification.service.d.ts +12 -12
  260. package/dist/oauth/oauth-token-broker.service.d.ts +72 -0
  261. package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -0
  262. package/dist/oauth/oauth-token-broker.service.js +258 -0
  263. package/dist/oauth/oauth-token-broker.service.js.map +1 -0
  264. package/dist/oauth/oauth.module.d.ts.map +1 -1
  265. package/dist/oauth/oauth.module.js +3 -1
  266. package/dist/oauth/oauth.module.js.map +1 -1
  267. package/dist/oauth/oauth.service.d.ts +2 -0
  268. package/dist/oauth/oauth.service.d.ts.map +1 -1
  269. package/dist/oauth/oauth.service.js +6 -3
  270. package/dist/oauth/oauth.service.js.map +1 -1
  271. package/dist/pdf/pdf.service.d.ts +8 -0
  272. package/dist/pdf/pdf.service.d.ts.map +1 -1
  273. package/dist/pdf/pdf.service.js +52 -0
  274. package/dist/pdf/pdf.service.js.map +1 -1
  275. package/dist/presence/presence.controller.d.ts +16 -0
  276. package/dist/presence/presence.controller.d.ts.map +1 -0
  277. package/dist/presence/presence.controller.js +60 -0
  278. package/dist/presence/presence.controller.js.map +1 -0
  279. package/dist/presence/presence.listener.d.ts +29 -0
  280. package/dist/presence/presence.listener.d.ts.map +1 -0
  281. package/dist/presence/presence.listener.js +82 -0
  282. package/dist/presence/presence.listener.js.map +1 -0
  283. package/dist/presence/presence.module.d.ts +3 -0
  284. package/dist/presence/presence.module.d.ts.map +1 -0
  285. package/dist/presence/presence.module.js +32 -0
  286. package/dist/presence/presence.module.js.map +1 -0
  287. package/dist/presence/presence.service.d.ts +42 -0
  288. package/dist/presence/presence.service.d.ts.map +1 -0
  289. package/dist/presence/presence.service.js +147 -0
  290. package/dist/presence/presence.service.js.map +1 -0
  291. package/dist/profile/dto/delete-account.dto.d.ts +8 -0
  292. package/dist/profile/dto/delete-account.dto.d.ts.map +1 -0
  293. package/dist/profile/dto/delete-account.dto.js +22 -0
  294. package/dist/profile/dto/delete-account.dto.js.map +1 -0
  295. package/dist/profile/events/profile-account-deleted.event.d.ts +12 -0
  296. package/dist/profile/events/profile-account-deleted.event.d.ts.map +1 -0
  297. package/dist/profile/events/profile-account-deleted.event.js +17 -0
  298. package/dist/profile/events/profile-account-deleted.event.js.map +1 -0
  299. package/dist/profile/profile.controller.d.ts +21 -15
  300. package/dist/profile/profile.controller.d.ts.map +1 -1
  301. package/dist/profile/profile.controller.js +75 -46
  302. package/dist/profile/profile.controller.js.map +1 -1
  303. package/dist/profile/profile.service.d.ts +30 -18
  304. package/dist/profile/profile.service.d.ts.map +1 -1
  305. package/dist/profile/profile.service.js +113 -37
  306. package/dist/profile/profile.service.js.map +1 -1
  307. package/dist/realtime/realtime.gateway.d.ts +48 -0
  308. package/dist/realtime/realtime.gateway.d.ts.map +1 -0
  309. package/dist/realtime/realtime.gateway.js +156 -0
  310. package/dist/realtime/realtime.gateway.js.map +1 -0
  311. package/dist/realtime/realtime.module.d.ts +8 -0
  312. package/dist/realtime/realtime.module.d.ts.map +1 -0
  313. package/dist/realtime/realtime.module.js +29 -0
  314. package/dist/realtime/realtime.module.js.map +1 -0
  315. package/dist/realtime/realtime.service.d.ts +51 -0
  316. package/dist/realtime/realtime.service.d.ts.map +1 -0
  317. package/dist/realtime/realtime.service.js +177 -0
  318. package/dist/realtime/realtime.service.js.map +1 -0
  319. package/dist/redis/redis-pubsub.d.ts +27 -0
  320. package/dist/redis/redis-pubsub.d.ts.map +1 -0
  321. package/dist/redis/redis-pubsub.js +140 -0
  322. package/dist/redis/redis-pubsub.js.map +1 -0
  323. package/dist/role/role.controller.d.ts +3 -3
  324. package/dist/role/role.service.d.ts +3 -3
  325. package/dist/setting/dto/create.dto.d.ts.map +1 -1
  326. package/dist/setting/dto/create.dto.js +9 -2
  327. package/dist/setting/dto/create.dto.js.map +1 -1
  328. package/dist/setting/setting.controller.d.ts +5 -5
  329. package/dist/setting/setting.service.d.ts +8 -5
  330. package/dist/setting/setting.service.d.ts.map +1 -1
  331. package/dist/setting/setting.service.js +25 -1
  332. package/dist/setting/setting.service.js.map +1 -1
  333. package/dist/user/dto/create-with-email-and-password.dto.d.ts +2 -0
  334. package/dist/user/dto/create-with-email-and-password.dto.d.ts.map +1 -1
  335. package/dist/user/dto/create-with-email-and-password.dto.js +5 -0
  336. package/dist/user/dto/create-with-email-and-password.dto.js.map +1 -1
  337. package/dist/user/dto/query-user-mail-list.dto.d.ts +5 -0
  338. package/dist/user/dto/query-user-mail-list.dto.d.ts.map +1 -0
  339. package/dist/user/dto/query-user-mail-list.dto.js +25 -0
  340. package/dist/user/dto/query-user-mail-list.dto.js.map +1 -0
  341. package/dist/user/user-credential.util.d.ts +19 -0
  342. package/dist/user/user-credential.util.d.ts.map +1 -0
  343. package/dist/user/user-credential.util.js +32 -0
  344. package/dist/user/user-credential.util.js.map +1 -0
  345. package/dist/user/user.controller.d.ts +17 -5
  346. package/dist/user/user.controller.d.ts.map +1 -1
  347. package/dist/user/user.controller.js +18 -3
  348. package/dist/user/user.controller.js.map +1 -1
  349. package/dist/user/user.service.d.ts +28 -6
  350. package/dist/user/user.service.d.ts.map +1 -1
  351. package/dist/user/user.service.js +204 -13
  352. package/dist/user/user.service.js.map +1 -1
  353. package/dist/validators/is-strong-password-with-settings.validator.d.ts.map +1 -1
  354. package/dist/validators/is-strong-password-with-settings.validator.js +11 -0
  355. package/dist/validators/is-strong-password-with-settings.validator.js.map +1 -1
  356. package/dist/validators/service-locator.d.ts +9 -0
  357. package/dist/validators/service-locator.d.ts.map +1 -1
  358. package/dist/validators/service-locator.js +12 -0
  359. package/dist/validators/service-locator.js.map +1 -1
  360. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts +3 -0
  361. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts.map +1 -0
  362. package/dist/whatsapp-sender/whatsapp-sender.module.js +23 -0
  363. package/dist/whatsapp-sender/whatsapp-sender.module.js.map +1 -0
  364. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +50 -0
  365. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -0
  366. package/dist/whatsapp-sender/whatsapp-sender.service.js +224 -0
  367. package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -0
  368. package/hedhog/data/integration_provider.yaml +16 -0
  369. package/hedhog/data/mail.yaml +88 -61
  370. package/hedhog/data/mail_layout.yaml +188 -0
  371. package/hedhog/data/menu.yaml +67 -3
  372. package/hedhog/data/route.yaml +135 -0
  373. package/hedhog/data/setting_group.yaml +139 -1
  374. package/hedhog/frontend/app/account/components/mfa-setup-dialog.tsx.ejs +36 -0
  375. package/hedhog/frontend/app/account/components/two-factor-auth.tsx.ejs +2 -0
  376. package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +10 -7
  377. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +7 -4
  378. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +580 -0
  379. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-preview.tsx.ejs +150 -0
  380. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +199 -0
  381. package/hedhog/frontend/app/ai_instruction/_components/prompt-diff.tsx.ejs +63 -0
  382. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.spec.ts.ejs +59 -0
  383. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.ts.ejs +72 -0
  384. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.spec.ts.ejs +170 -0
  385. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.ts.ejs +167 -0
  386. package/hedhog/frontend/app/ai_instruction/_lib/types.ts.ejs +99 -0
  387. package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +422 -0
  388. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +51 -4
  389. package/hedhog/frontend/app/incidents/page.tsx.ejs +400 -0
  390. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +153 -84
  391. package/hedhog/frontend/app/mail/layout/page.tsx.ejs +344 -0
  392. package/hedhog/frontend/app/mail/template/page.tsx.ejs +155 -121
  393. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +129 -17
  394. package/hedhog/frontend/app/pages/_components/page-delete-dialog.tsx.ejs +343 -0
  395. package/hedhog/frontend/app/pages/_components/page-detail-sheet.tsx.ejs +438 -0
  396. package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1009 -0
  397. package/hedhog/frontend/app/pages/_components/system-page-types.ts.ejs +56 -0
  398. package/hedhog/frontend/app/pages/_components/use-system-pages.ts.ejs +171 -0
  399. package/hedhog/frontend/app/pages/page.tsx.ejs +514 -0
  400. package/hedhog/frontend/app/users/page.tsx.ejs +119 -13
  401. package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +231 -0
  402. package/hedhog/frontend/app/users/user-mails.tsx.ejs +399 -0
  403. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +60 -75
  404. package/hedhog/frontend/messages/en.json +499 -3
  405. package/hedhog/frontend/messages/pt.json +499 -3
  406. package/hedhog/table/ai_agent.yaml +1 -0
  407. package/hedhog/table/ai_instruction.yaml +15 -0
  408. package/hedhog/table/leaked_password.yaml +18 -0
  409. package/hedhog/table/mail_layout.yaml +35 -0
  410. package/hedhog/table/mail_var.yaml +4 -0
  411. package/hedhog/table/setting.yaml +1 -0
  412. package/hedhog/table/system_incident.yaml +59 -0
  413. package/hedhog/table/user_presence.yaml +36 -0
  414. package/package.json +8 -4
  415. package/src/access-log/access-log.interceptor.ts +4 -2
  416. package/src/ai/ai-attachment.fragments.spec.ts +319 -0
  417. package/src/ai/ai-attachment.fragments.ts +35 -0
  418. package/src/ai/ai.prompts.ts +38 -0
  419. package/src/ai/ai.service.spec.ts +280 -0
  420. package/src/ai/ai.service.ts +338 -82
  421. package/src/ai/dto/chat.dto.ts +33 -3
  422. package/src/ai/dto/create-agent.dto.ts +2 -2
  423. package/src/ai/dto/update-agent.dto.ts +2 -2
  424. package/src/ai-instruction/ai-instruction.controller.ts +40 -9
  425. package/src/ai-instruction/ai-instruction.module.ts +13 -2
  426. package/src/ai-instruction/ai-instruction.service.spec.ts +658 -0
  427. package/src/ai-instruction/ai-instruction.service.ts +661 -62
  428. package/src/ai-instruction/ai-prompt-builder.service.ts +10 -1
  429. package/src/ai-instruction/ai-prompt-registry.ts +87 -0
  430. package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +375 -0
  431. package/src/ai-instruction/ai-prompt-resolver.service.ts +295 -0
  432. package/src/ai-instruction/ai-prompt-template.util.spec.ts +162 -0
  433. package/src/ai-instruction/ai-prompt-template.util.ts +199 -0
  434. package/src/ai-instruction/dto/create-ai-instruction.dto.ts +39 -3
  435. package/src/ai-instruction/dto/preview-ai-instruction.dto.ts +26 -0
  436. package/src/ai-instruction/dto/update-ai-instruction.dto.ts +42 -1
  437. package/src/ai-instruction/types/ai-instruction.types.ts +24 -1
  438. package/src/auth/auth.controller.ts +31 -5
  439. package/src/auth/auth.service.spec.ts +3 -1
  440. package/src/auth/auth.service.ts +101 -36
  441. package/src/captcha/captcha.module.ts +10 -0
  442. package/src/captcha/captcha.service.spec.ts +210 -0
  443. package/src/captcha/captcha.service.ts +191 -0
  444. package/src/challenge/challenge.service.spec.ts +39 -4
  445. package/src/challenge/challenge.service.ts +72 -17
  446. package/src/core.module.ts +27 -1
  447. package/src/file/file.service.spec.ts +105 -0
  448. package/src/file/file.service.ts +60 -3
  449. package/src/incident/incident-notifier.service.spec.ts +205 -0
  450. package/src/incident/incident-notifier.service.ts +241 -0
  451. package/src/incident/incident.controller.ts +38 -0
  452. package/src/incident/incident.module.ts +19 -0
  453. package/src/incident/incident.service.spec.ts +150 -0
  454. package/src/incident/incident.service.ts +209 -0
  455. package/src/index.ts +37 -0
  456. package/src/integration-profile/dto/test.dto.ts +19 -0
  457. package/src/integration-profile/integration-profile.controller.ts +10 -1
  458. package/src/integration-profile/integration-profile.module.spec.ts +51 -0
  459. package/src/integration-profile/integration-profile.module.ts +23 -4
  460. package/src/integration-profile/integration-profile.secrets.ts +9 -1
  461. package/src/integration-profile/integration-profile.service.spec.ts +279 -0
  462. package/src/integration-profile/integration-profile.service.ts +120 -124
  463. package/src/integration-profile/integration-profile.utils.spec.ts +22 -0
  464. package/src/integration-profile/integration-profile.utils.ts +40 -3
  465. package/src/integration-profile/testers/ai.testers.ts +165 -0
  466. package/src/integration-profile/testers/captcha.testers.spec.ts +92 -0
  467. package/src/integration-profile/testers/captcha.testers.ts +139 -0
  468. package/src/integration-profile/testers/email.testers.ts +161 -0
  469. package/src/integration-profile/testers/http-probe.spec.ts +153 -0
  470. package/src/integration-profile/testers/http-probe.ts +171 -0
  471. package/src/integration-profile/testers/index.ts +30 -0
  472. package/src/integration-profile/testers/infrastructure.testers.ts +122 -0
  473. package/src/integration-profile/testers/integration-tester.registry.spec.ts +75 -0
  474. package/src/integration-profile/testers/integration-tester.registry.ts +43 -0
  475. package/src/integration-profile/testers/integration-tester.types.ts +61 -0
  476. package/src/integration-profile/testers/messaging.testers.ts +102 -0
  477. package/src/integration-profile/testers/oauth.testers.spec.ts +220 -0
  478. package/src/integration-profile/testers/oauth.testers.ts +305 -0
  479. package/src/integration-profile/testers/payment.testers.ts +185 -0
  480. package/src/integration-profile/testers/remaining.testers.spec.ts +401 -0
  481. package/src/integration-profile/testers/storage.testers.spec.ts +185 -0
  482. package/src/integration-profile/testers/storage.testers.ts +226 -0
  483. package/src/integration-profile/testers/tester-coverage.spec.ts +58 -0
  484. package/src/language/en.json +4 -2
  485. package/src/language/pt.json +4 -2
  486. package/src/leaked-password/README.md +83 -0
  487. package/src/leaked-password/leaked-password.controller.ts +52 -0
  488. package/src/leaked-password/leaked-password.module.ts +18 -0
  489. package/src/leaked-password/leaked-password.service.ts +242 -0
  490. package/src/leaked-password/seed/build-seed-sql.mjs +180 -0
  491. package/src/leaked-password/seed/common-passwords.txt +335 -0
  492. package/src/mail/dto/preview.dto.ts +50 -0
  493. package/src/mail/dto/send.dto.ts +14 -1
  494. package/src/mail/mail-template.spec.ts +197 -0
  495. package/src/mail/mail.controller.ts +9 -2
  496. package/src/mail/mail.service.spec.ts +116 -1
  497. package/src/mail/mail.service.ts +118 -12
  498. package/src/mail-layout/dto/update.dto.ts +19 -0
  499. package/src/mail-layout/mail-layout.controller.ts +47 -0
  500. package/src/mail-layout/mail-layout.module.ts +22 -0
  501. package/src/mail-layout/mail-layout.service.ts +94 -0
  502. package/src/mcp-chat/mcp-chat.service.spec.ts +236 -0
  503. package/src/mcp-chat/mcp-chat.service.ts +122 -26
  504. package/src/oauth/oauth-token-broker.service.spec.ts +172 -0
  505. package/src/oauth/oauth-token-broker.service.ts +363 -0
  506. package/src/oauth/oauth.module.ts +3 -1
  507. package/src/oauth/oauth.service.ts +8 -2
  508. package/src/pdf/pdf.service.ts +75 -0
  509. package/src/presence/presence.controller.ts +29 -0
  510. package/src/presence/presence.listener.ts +53 -0
  511. package/src/presence/presence.module.ts +19 -0
  512. package/src/presence/presence.service.spec.ts +97 -0
  513. package/src/presence/presence.service.ts +160 -0
  514. package/src/profile/dto/delete-account.dto.ts +11 -0
  515. package/src/profile/events/profile-account-deleted.event.ts +13 -0
  516. package/src/profile/profile.controller.ts +46 -34
  517. package/src/profile/profile.service.ts +138 -38
  518. package/src/realtime/realtime.gateway.ts +138 -0
  519. package/src/realtime/realtime.module.ts +16 -0
  520. package/src/realtime/realtime.service.spec.ts +50 -0
  521. package/src/realtime/realtime.service.ts +187 -0
  522. package/src/redis/redis-pubsub.ts +179 -0
  523. package/src/setting/dto/create.dto.ts +13 -2
  524. package/src/setting/setting.service.spec.ts +56 -0
  525. package/src/setting/setting.service.ts +29 -1
  526. package/src/user/dto/create-with-email-and-password.dto.ts +6 -1
  527. package/src/user/dto/query-user-mail-list.dto.ts +10 -0
  528. package/src/user/user-credential.util.ts +35 -0
  529. package/src/user/user.controller.ts +17 -2
  530. package/src/user/user.service.spec.ts +153 -0
  531. package/src/user/user.service.ts +255 -12
  532. package/src/validators/is-strong-password-with-settings.validator.ts +12 -0
  533. package/src/validators/service-locator.ts +15 -0
  534. package/src/whatsapp-sender/whatsapp-sender.module.ts +10 -0
  535. package/src/whatsapp-sender/whatsapp-sender.service.ts +313 -0
@@ -0,0 +1,1009 @@
1
+ 'use client';
2
+
3
+ import { CopyButton } from '@/components/copy-button';
4
+ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
5
+ import { Badge } from '@/components/ui/badge';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Card, CardContent } from '@/components/ui/card';
8
+ import { Input } from '@/components/ui/input';
9
+ import { Label } from '@/components/ui/label';
10
+ import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
11
+ import { ScrollArea } from '@/components/ui/scroll-area';
12
+ import {
13
+ Select,
14
+ SelectContent,
15
+ SelectItem,
16
+ SelectTrigger,
17
+ SelectValue,
18
+ } from '@/components/ui/select';
19
+ import {
20
+ Sheet,
21
+ SheetDescription,
22
+ SheetHeader,
23
+ SheetTitle,
24
+ } from '@/components/ui/sheet';
25
+ import { Switch } from '@/components/ui/switch';
26
+ import { toKebabCase, toTitleCase } from '@/lib/scaffold/naming';
27
+ import {
28
+ SCAFFOLD_COLUMN_TYPES,
29
+ type ScaffoldColumn,
30
+ type ScaffoldColumnType,
31
+ type ScaffoldContext,
32
+ type ScaffoldFile,
33
+ type ScaffoldPlan,
34
+ type ScaffoldTemplate,
35
+ } from '@/lib/scaffold/types';
36
+ import { cn } from '@/lib/utils';
37
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
38
+ import { Check, Loader2, Plus, Trash2 } from 'lucide-react';
39
+ import { useTranslations } from 'next-intl';
40
+ import { useCallback, useEffect, useMemo, useState } from 'react';
41
+ import { toast } from 'sonner';
42
+ import type { MenuNode, PaginatedResponse, RoleSummary } from './system-page-types';
43
+ import { getMenuLabel, getRoleLabel } from './use-system-pages';
44
+
45
+ const STEP_KEYS = [
46
+ 'target',
47
+ 'template',
48
+ 'columns',
49
+ 'backend',
50
+ 'menu',
51
+ 'review',
52
+ ] as const;
53
+
54
+ const TEMPLATES: ScaffoldTemplate[] = [
55
+ 'list-kpi',
56
+ 'list-simple',
57
+ 'detail-form',
58
+ 'dashboard',
59
+ ];
60
+
61
+ type PreviewResponse = {
62
+ files: ScaffoldFile[];
63
+ conflicts: string[];
64
+ steps: string[];
65
+ };
66
+
67
+ type ValidationIssue = { field: string; message: string };
68
+
69
+ function emptyColumn(): ScaffoldColumn {
70
+ return {
71
+ name: '',
72
+ type: 'varchar',
73
+ nullable: false,
74
+ labelEn: '',
75
+ labelPt: '',
76
+ inList: true,
77
+ inFilters: false,
78
+ };
79
+ }
80
+
81
+ function createEmptyPlan(): ScaffoldPlan {
82
+ return {
83
+ library: '',
84
+ entity: '',
85
+ route: '',
86
+ labelEn: '',
87
+ labelPt: '',
88
+ descriptionEn: '',
89
+ descriptionPt: '',
90
+ template: 'list-kpi',
91
+ columns: [
92
+ {
93
+ name: 'name',
94
+ type: 'varchar',
95
+ nullable: false,
96
+ length: 255,
97
+ labelEn: 'Name',
98
+ labelPt: 'Nome',
99
+ inList: true,
100
+ inFilters: false,
101
+ },
102
+ {
103
+ name: 'status',
104
+ type: 'enum',
105
+ nullable: false,
106
+ defaultValue: 'active',
107
+ enumValues: ['active', 'inactive'],
108
+ labelEn: 'Status',
109
+ labelPt: 'Situação',
110
+ inList: true,
111
+ inFilters: true,
112
+ },
113
+ ],
114
+ apiBasePath: '',
115
+ endpoints: {
116
+ list: true,
117
+ stats: true,
118
+ get: true,
119
+ create: true,
120
+ update: true,
121
+ remove: true,
122
+ },
123
+ generateBackend: true,
124
+ menu: { parentSlug: null, icon: 'file-text', order: 0 },
125
+ roles: ['admin'],
126
+ newRole: null,
127
+ overwrite: false,
128
+ };
129
+ }
130
+
131
+ type PageWizardSheetProps = {
132
+ open: boolean;
133
+ onOpenChange: (open: boolean) => void;
134
+ };
135
+
136
+ export function PageWizardSheet({ open, onOpenChange }: PageWizardSheetProps) {
137
+ const t = useTranslations('core.PageWizard');
138
+ const { request, currentLocaleCode } = useApp();
139
+
140
+ const [step, setStep] = useState(0);
141
+ const [plan, setPlan] = useState<ScaffoldPlan>(createEmptyPlan);
142
+ const [preview, setPreview] = useState<PreviewResponse | null>(null);
143
+ const [issues, setIssues] = useState<ValidationIssue[]>([]);
144
+ const [isWorking, setIsWorking] = useState(false);
145
+ const [applied, setApplied] = useState<{ written: string[]; steps: string[] } | null>(
146
+ null
147
+ );
148
+ const [expandedFile, setExpandedFile] = useState<string | null>(null);
149
+
150
+ const { data: context } = useQuery<ScaffoldContext | null>({
151
+ queryKey: ['scaffold-context'],
152
+ queryFn: async () => {
153
+ const response = await fetch('/api/dev/scaffold/context');
154
+
155
+ if (!response.ok) {
156
+ return null;
157
+ }
158
+
159
+ return (await response.json()) as ScaffoldContext;
160
+ },
161
+ enabled: open,
162
+ });
163
+
164
+ const { data: menus = [] } = useQuery<MenuNode[]>({
165
+ queryKey: ['scaffold-menus', currentLocaleCode],
166
+ queryFn: async () => {
167
+ const response = await request<MenuNode[]>({
168
+ url: '/menu/all',
169
+ method: 'GET',
170
+ });
171
+
172
+ return Array.isArray(response.data) ? response.data : [];
173
+ },
174
+ enabled: open,
175
+ placeholderData: (previous) => previous ?? [],
176
+ });
177
+
178
+ const { data: roles = [] } = useQuery<RoleSummary[]>({
179
+ queryKey: ['scaffold-roles', currentLocaleCode],
180
+ queryFn: async () => {
181
+ const response = await request<PaginatedResponse<RoleSummary>>({
182
+ url: '/role?pageSize=10000',
183
+ method: 'GET',
184
+ });
185
+
186
+ return response.data?.data ?? [];
187
+ },
188
+ enabled: open,
189
+ placeholderData: (previous) => previous ?? [],
190
+ });
191
+
192
+ useEffect(() => {
193
+ if (!open) {
194
+ setStep(0);
195
+ setPreview(null);
196
+ setIssues([]);
197
+ setApplied(null);
198
+ setPlan(createEmptyPlan());
199
+ }
200
+ }, [open]);
201
+
202
+ const updatePlan = useCallback((patch: Partial<ScaffoldPlan>) => {
203
+ setPlan((previous) => ({ ...previous, ...patch }));
204
+ setPreview(null);
205
+ setIssues([]);
206
+ }, []);
207
+
208
+ const updateColumn = useCallback(
209
+ (index: number, patch: Partial<ScaffoldColumn>) => {
210
+ setPlan((previous) => ({
211
+ ...previous,
212
+ columns: previous.columns.map((column, columnIndex) =>
213
+ columnIndex === index ? { ...column, ...patch } : column
214
+ ),
215
+ }));
216
+ setPreview(null);
217
+ },
218
+ []
219
+ );
220
+
221
+ /** Entity e rota derivam um do outro até o usuário editar a rota manualmente. */
222
+ const handleEntityChange = (value: string) => {
223
+ const entity = value.trim().toLowerCase().replace(/[^a-z0-9_]/g, '');
224
+ const kebab = toKebabCase(entity);
225
+
226
+ setPlan((previous) => ({
227
+ ...previous,
228
+ entity,
229
+ route: previous.library && kebab ? `/${previous.library}/${kebab}` : previous.route,
230
+ apiBasePath: kebab ? `/${kebab}` : previous.apiBasePath,
231
+ labelEn: previous.labelEn || toTitleCase(entity),
232
+ labelPt: previous.labelPt || toTitleCase(entity),
233
+ }));
234
+ setPreview(null);
235
+ setIssues([]);
236
+ };
237
+
238
+ const parentMenus = useMemo(
239
+ () =>
240
+ menus
241
+ .filter((menu) => menu.slug)
242
+ .sort((left, right) => getMenuLabel(left).localeCompare(getMenuLabel(right))),
243
+ [menus]
244
+ );
245
+
246
+ const canAdvance = useMemo(() => {
247
+ if (step === 0) {
248
+ return Boolean(plan.library && plan.entity && plan.route && plan.labelPt);
249
+ }
250
+
251
+ if (step === 2 && plan.generateBackend) {
252
+ return plan.columns.length > 0 && plan.columns.every((column) => column.name);
253
+ }
254
+
255
+ return true;
256
+ }, [plan, step]);
257
+
258
+ const runPreview = async () => {
259
+ setIsWorking(true);
260
+ setIssues([]);
261
+
262
+ try {
263
+ const response = await fetch('/api/dev/scaffold', {
264
+ method: 'POST',
265
+ headers: { 'Content-Type': 'application/json' },
266
+ body: JSON.stringify({ mode: 'preview', plan }),
267
+ });
268
+
269
+ if (response.status === 422) {
270
+ const data = (await response.json()) as { issues: ValidationIssue[] };
271
+ setIssues(data.issues);
272
+ setPreview(null);
273
+ return;
274
+ }
275
+
276
+ if (!response.ok) {
277
+ toast.error(t('previewError'));
278
+ return;
279
+ }
280
+
281
+ setPreview((await response.json()) as PreviewResponse);
282
+ } catch {
283
+ toast.error(t('previewError'));
284
+ } finally {
285
+ setIsWorking(false);
286
+ }
287
+ };
288
+
289
+ const runApply = async () => {
290
+ setIsWorking(true);
291
+
292
+ try {
293
+ const response = await fetch('/api/dev/scaffold', {
294
+ method: 'POST',
295
+ headers: { 'Content-Type': 'application/json' },
296
+ body: JSON.stringify({ mode: 'apply', plan }),
297
+ });
298
+
299
+ if (!response.ok) {
300
+ const data = (await response.json().catch(() => null)) as {
301
+ message?: string;
302
+ } | null;
303
+
304
+ toast.error(data?.message ?? t('applyError'));
305
+ return;
306
+ }
307
+
308
+ const data = (await response.json()) as {
309
+ written: string[];
310
+ manual: ScaffoldFile[];
311
+ steps: string[];
312
+ };
313
+
314
+ setApplied({ written: data.written, steps: data.steps });
315
+ setStep(STEP_KEYS.length);
316
+ toast.success(t('applySuccess', { count: data.written.length }));
317
+ } catch {
318
+ toast.error(t('applyError'));
319
+ } finally {
320
+ setIsWorking(false);
321
+ }
322
+ };
323
+
324
+ const goNext = async () => {
325
+ if (step === STEP_KEYS.length - 2) {
326
+ setStep(STEP_KEYS.length - 1);
327
+ await runPreview();
328
+ return;
329
+ }
330
+
331
+ setStep((current) => Math.min(STEP_KEYS.length - 1, current + 1));
332
+ };
333
+
334
+ const isDone = step === STEP_KEYS.length;
335
+
336
+ return (
337
+ <Sheet open={open} onOpenChange={onOpenChange}>
338
+ <ResizableSheetContent
339
+ sheetId="core-page-wizard"
340
+ defaultWidth={860}
341
+ className="flex flex-col gap-0 p-0"
342
+ >
343
+ <SheetHeader className="border-b">
344
+ <SheetTitle>{t('title')}</SheetTitle>
345
+ <SheetDescription>{t('description')}</SheetDescription>
346
+ </SheetHeader>
347
+
348
+ {!isDone ? (
349
+ <div className="flex flex-wrap items-center gap-2 border-b px-4 py-3">
350
+ {STEP_KEYS.map((key, index) => (
351
+ <div key={key} className="flex items-center gap-1.5">
352
+ <span
353
+ className={cn(
354
+ 'flex h-6 w-6 items-center justify-center rounded-full border text-[11px]',
355
+ index < step
356
+ ? 'border-primary bg-primary text-primary-foreground'
357
+ : index === step
358
+ ? 'border-primary text-primary'
359
+ : 'border-border text-muted-foreground'
360
+ )}
361
+ >
362
+ {index < step ? <Check className="size-3.5" /> : index + 1}
363
+ </span>
364
+ <span
365
+ className={cn(
366
+ 'text-xs',
367
+ index === step
368
+ ? 'font-medium text-foreground'
369
+ : 'text-muted-foreground'
370
+ )}
371
+ >
372
+ {t(`steps.${key}` as never)}
373
+ </span>
374
+ </div>
375
+ ))}
376
+ </div>
377
+ ) : null}
378
+
379
+ <ScrollArea className="min-h-0 flex-1">
380
+ <div className="space-y-4 p-4">
381
+ {isDone && applied ? (
382
+ <div className="space-y-4">
383
+ <Alert>
384
+ <AlertTitle>{t('doneTitle')}</AlertTitle>
385
+ <AlertDescription>
386
+ {t('doneDescription', { count: applied.written.length })}
387
+ </AlertDescription>
388
+ </Alert>
389
+
390
+ <div>
391
+ <h4 className="text-sm font-semibold">{t('doneFiles')}</h4>
392
+ <div className="mt-2 space-y-1">
393
+ {applied.written.map((file) => (
394
+ <div
395
+ key={file}
396
+ className="rounded-lg border bg-background/80 p-2 font-mono text-xs"
397
+ >
398
+ {file}
399
+ </div>
400
+ ))}
401
+ </div>
402
+ </div>
403
+
404
+ <div>
405
+ <h4 className="text-sm font-semibold">{t('doneSteps')}</h4>
406
+ <p className="mt-0.5 text-xs text-muted-foreground">
407
+ {t('doneStepsHint')}
408
+ </p>
409
+ <div className="mt-2 space-y-1">
410
+ {applied.steps.map((command) => (
411
+ <div
412
+ key={command}
413
+ className="flex items-center gap-2 rounded-lg border bg-muted/30 p-2"
414
+ >
415
+ <code className="min-w-0 flex-1 truncate text-xs">
416
+ {command}
417
+ </code>
418
+ <CopyButton value={command} />
419
+ </div>
420
+ ))}
421
+ </div>
422
+ </div>
423
+ </div>
424
+ ) : null}
425
+
426
+ {!isDone && step === 0 ? (
427
+ <div className="grid gap-3 sm:grid-cols-2">
428
+ <div className="space-y-1.5">
429
+ <Label>{t('fieldLibrary')}</Label>
430
+ <Select
431
+ value={plan.library || undefined}
432
+ onValueChange={(value) =>
433
+ updatePlan({
434
+ library: value,
435
+ route: plan.entity
436
+ ? `/${value}/${toKebabCase(plan.entity)}`
437
+ : `/${value}`,
438
+ })
439
+ }
440
+ >
441
+ <SelectTrigger className="w-full">
442
+ <SelectValue placeholder={t('fieldLibraryPlaceholder')} />
443
+ </SelectTrigger>
444
+ <SelectContent>
445
+ {(context?.libraries ?? []).map((library) => (
446
+ <SelectItem key={library} value={library}>
447
+ {library}
448
+ </SelectItem>
449
+ ))}
450
+ </SelectContent>
451
+ </Select>
452
+ </div>
453
+
454
+ <div className="space-y-1.5">
455
+ <Label>{t('fieldEntity')}</Label>
456
+ <Input
457
+ value={plan.entity}
458
+ onChange={(event) => handleEntityChange(event.target.value)}
459
+ placeholder="service_order"
460
+ />
461
+ <p className="text-xs text-muted-foreground">
462
+ {t('fieldEntityHint')}
463
+ </p>
464
+ </div>
465
+
466
+ <div className="space-y-1.5">
467
+ <Label>{t('fieldRoute')}</Label>
468
+ <Input
469
+ value={plan.route}
470
+ onChange={(event) => updatePlan({ route: event.target.value })}
471
+ placeholder="/crm/contracts"
472
+ />
473
+ </div>
474
+
475
+ <div className="space-y-1.5">
476
+ <Label>{t('fieldApiBasePath')}</Label>
477
+ <Input
478
+ value={plan.apiBasePath}
479
+ onChange={(event) =>
480
+ updatePlan({ apiBasePath: event.target.value })
481
+ }
482
+ placeholder="/contract"
483
+ />
484
+ </div>
485
+
486
+ <div className="space-y-1.5">
487
+ <Label>{t('fieldLabelPt')}</Label>
488
+ <Input
489
+ value={plan.labelPt}
490
+ onChange={(event) => updatePlan({ labelPt: event.target.value })}
491
+ />
492
+ </div>
493
+
494
+ <div className="space-y-1.5">
495
+ <Label>{t('fieldLabelEn')}</Label>
496
+ <Input
497
+ value={plan.labelEn}
498
+ onChange={(event) => updatePlan({ labelEn: event.target.value })}
499
+ />
500
+ </div>
501
+
502
+ <div className="space-y-1.5">
503
+ <Label>{t('fieldDescriptionPt')}</Label>
504
+ <Input
505
+ value={plan.descriptionPt}
506
+ onChange={(event) =>
507
+ updatePlan({ descriptionPt: event.target.value })
508
+ }
509
+ />
510
+ </div>
511
+
512
+ <div className="space-y-1.5">
513
+ <Label>{t('fieldDescriptionEn')}</Label>
514
+ <Input
515
+ value={plan.descriptionEn}
516
+ onChange={(event) =>
517
+ updatePlan({ descriptionEn: event.target.value })
518
+ }
519
+ />
520
+ </div>
521
+ </div>
522
+ ) : null}
523
+
524
+ {!isDone && step === 1 ? (
525
+ <div className="grid gap-3 sm:grid-cols-2">
526
+ {TEMPLATES.map((template) => (
527
+ <Card
528
+ key={template}
529
+ className={cn(
530
+ 'cursor-pointer border-border/70 py-0 transition-colors',
531
+ plan.template === template
532
+ ? 'border-primary ring-1 ring-primary/20'
533
+ : 'hover:border-border'
534
+ )}
535
+ onClick={() => updatePlan({ template })}
536
+ >
537
+ <CardContent className="space-y-1 p-4">
538
+ <h4 className="text-sm font-semibold">
539
+ {t(`template_${template}` as never)}
540
+ </h4>
541
+ <p className="text-xs text-muted-foreground">
542
+ {t(`templateHint_${template}` as never)}
543
+ </p>
544
+ </CardContent>
545
+ </Card>
546
+ ))}
547
+ </div>
548
+ ) : null}
549
+
550
+ {!isDone && step === 2 ? (
551
+ <div className="space-y-3">
552
+ <p className="text-xs text-muted-foreground">
553
+ {t('columnsHint')}
554
+ </p>
555
+
556
+ {plan.columns.map((column, index) => (
557
+ <Card key={index} className="border-border/70 py-0">
558
+ <CardContent className="space-y-3 p-3">
559
+ <div className="grid gap-2 sm:grid-cols-4">
560
+ <Input
561
+ value={column.name}
562
+ onChange={(event) =>
563
+ updateColumn(index, {
564
+ name: event.target.value
565
+ .toLowerCase()
566
+ .replace(/[^a-z0-9_]/g, ''),
567
+ })
568
+ }
569
+ placeholder={t('columnName')}
570
+ />
571
+
572
+ <Select
573
+ value={column.type}
574
+ onValueChange={(value) =>
575
+ updateColumn(index, {
576
+ type: value as ScaffoldColumnType,
577
+ })
578
+ }
579
+ >
580
+ <SelectTrigger className="w-full">
581
+ <SelectValue />
582
+ </SelectTrigger>
583
+ <SelectContent>
584
+ {SCAFFOLD_COLUMN_TYPES.map((type) => (
585
+ <SelectItem key={type} value={type}>
586
+ {type}
587
+ </SelectItem>
588
+ ))}
589
+ </SelectContent>
590
+ </Select>
591
+
592
+ <Input
593
+ value={column.labelPt}
594
+ onChange={(event) =>
595
+ updateColumn(index, { labelPt: event.target.value })
596
+ }
597
+ placeholder={t('columnLabelPt')}
598
+ />
599
+
600
+ <Input
601
+ value={column.labelEn}
602
+ onChange={(event) =>
603
+ updateColumn(index, { labelEn: event.target.value })
604
+ }
605
+ placeholder={t('columnLabelEn')}
606
+ />
607
+ </div>
608
+
609
+ {column.type === 'enum' ? (
610
+ <Input
611
+ value={(column.enumValues ?? []).join(', ')}
612
+ onChange={(event) =>
613
+ updateColumn(index, {
614
+ enumValues: event.target.value
615
+ .split(',')
616
+ .map((value) => value.trim())
617
+ .filter(Boolean),
618
+ })
619
+ }
620
+ placeholder={t('columnEnumValues')}
621
+ />
622
+ ) : null}
623
+
624
+ {column.type === 'fk' ? (
625
+ <Select
626
+ value={column.referencesTable}
627
+ onValueChange={(value) =>
628
+ updateColumn(index, { referencesTable: value })
629
+ }
630
+ >
631
+ <SelectTrigger className="w-full">
632
+ <SelectValue placeholder={t('columnReferences')} />
633
+ </SelectTrigger>
634
+ <SelectContent>
635
+ {(context?.entitiesByLibrary[plan.library] ?? []).map(
636
+ (table) => (
637
+ <SelectItem key={table} value={table}>
638
+ {table}
639
+ </SelectItem>
640
+ )
641
+ )}
642
+ </SelectContent>
643
+ </Select>
644
+ ) : null}
645
+
646
+ <div className="flex flex-wrap items-center gap-4">
647
+ <label className="flex items-center gap-2 text-xs">
648
+ <Switch
649
+ checked={column.nullable}
650
+ onCheckedChange={(checked) =>
651
+ updateColumn(index, { nullable: checked })
652
+ }
653
+ />
654
+ {t('columnNullable')}
655
+ </label>
656
+
657
+ <label className="flex items-center gap-2 text-xs">
658
+ <Switch
659
+ checked={column.inList}
660
+ onCheckedChange={(checked) =>
661
+ updateColumn(index, { inList: checked })
662
+ }
663
+ />
664
+ {t('columnInList')}
665
+ </label>
666
+
667
+ <label className="flex items-center gap-2 text-xs">
668
+ <Switch
669
+ checked={column.inFilters}
670
+ onCheckedChange={(checked) =>
671
+ updateColumn(index, { inFilters: checked })
672
+ }
673
+ />
674
+ {t('columnInFilters')}
675
+ </label>
676
+
677
+ <Button
678
+ type="button"
679
+ variant="ghost"
680
+ size="icon"
681
+ className="ml-auto h-8 w-8 text-red-600"
682
+ onClick={() =>
683
+ setPlan((previous) => ({
684
+ ...previous,
685
+ columns: previous.columns.filter(
686
+ (_, columnIndex) => columnIndex !== index
687
+ ),
688
+ }))
689
+ }
690
+ >
691
+ <Trash2 className="h-4 w-4" />
692
+ </Button>
693
+ </div>
694
+ </CardContent>
695
+ </Card>
696
+ ))}
697
+
698
+ <Button
699
+ type="button"
700
+ variant="outline"
701
+ size="sm"
702
+ onClick={() =>
703
+ setPlan((previous) => ({
704
+ ...previous,
705
+ columns: [...previous.columns, emptyColumn()],
706
+ }))
707
+ }
708
+ >
709
+ <Plus className="h-4 w-4" />
710
+ {t('addColumn')}
711
+ </Button>
712
+ </div>
713
+ ) : null}
714
+
715
+ {!isDone && step === 3 ? (
716
+ <div className="space-y-4">
717
+ <label className="flex items-center justify-between rounded-lg border p-3">
718
+ <div>
719
+ <div className="text-sm font-medium">{t('generateBackend')}</div>
720
+ <p className="text-xs text-muted-foreground">
721
+ {t('generateBackendHint')}
722
+ </p>
723
+ </div>
724
+ <Switch
725
+ checked={plan.generateBackend}
726
+ onCheckedChange={(checked) =>
727
+ updatePlan({ generateBackend: checked })
728
+ }
729
+ />
730
+ </label>
731
+
732
+ <div className="grid gap-2 sm:grid-cols-2">
733
+ {(
734
+ [
735
+ ['list', 'GET ' + plan.apiBasePath],
736
+ ['stats', 'GET ' + plan.apiBasePath + '/stats'],
737
+ ['get', 'GET ' + plan.apiBasePath + '/:id'],
738
+ ['create', 'POST ' + plan.apiBasePath],
739
+ ['update', 'PATCH ' + plan.apiBasePath + '/:id'],
740
+ ['remove', 'DELETE ' + plan.apiBasePath + '/:id'],
741
+ ] as const
742
+ ).map(([key, label]) => (
743
+ <label
744
+ key={key}
745
+ className="flex items-center justify-between rounded-lg border p-2.5"
746
+ >
747
+ <code className="text-xs">{label}</code>
748
+ <Switch
749
+ checked={plan.endpoints[key]}
750
+ disabled={!plan.generateBackend}
751
+ onCheckedChange={(checked) =>
752
+ updatePlan({
753
+ endpoints: { ...plan.endpoints, [key]: checked },
754
+ })
755
+ }
756
+ />
757
+ </label>
758
+ ))}
759
+ </div>
760
+ </div>
761
+ ) : null}
762
+
763
+ {!isDone && step === 4 ? (
764
+ <div className="space-y-4">
765
+ <div className="grid gap-3 sm:grid-cols-3">
766
+ <div className="space-y-1.5">
767
+ <Label>{t('menuParent')}</Label>
768
+ <Select
769
+ value={plan.menu.parentSlug ?? '__root__'}
770
+ onValueChange={(value) =>
771
+ updatePlan({
772
+ menu: {
773
+ ...plan.menu,
774
+ parentSlug: value === '__root__' ? null : value,
775
+ },
776
+ })
777
+ }
778
+ >
779
+ <SelectTrigger className="w-full">
780
+ <SelectValue />
781
+ </SelectTrigger>
782
+ <SelectContent>
783
+ <SelectItem value="__root__">{t('menuRoot')}</SelectItem>
784
+ {parentMenus.map((menu) => (
785
+ <SelectItem key={menu.id} value={menu.slug}>
786
+ {getMenuLabel(menu)}
787
+ </SelectItem>
788
+ ))}
789
+ </SelectContent>
790
+ </Select>
791
+ </div>
792
+
793
+ <div className="space-y-1.5">
794
+ <Label>{t('menuIcon')}</Label>
795
+ <Input
796
+ value={plan.menu.icon}
797
+ onChange={(event) =>
798
+ updatePlan({
799
+ menu: { ...plan.menu, icon: event.target.value },
800
+ })
801
+ }
802
+ placeholder="file-text"
803
+ />
804
+ </div>
805
+
806
+ <div className="space-y-1.5">
807
+ <Label>{t('menuOrder')}</Label>
808
+ <Input
809
+ type="number"
810
+ value={plan.menu.order}
811
+ onChange={(event) =>
812
+ updatePlan({
813
+ menu: {
814
+ ...plan.menu,
815
+ order: Number(event.target.value) || 0,
816
+ },
817
+ })
818
+ }
819
+ />
820
+ </div>
821
+ </div>
822
+
823
+ <div>
824
+ <Label>{t('rolesTitle')}</Label>
825
+ <p className="mt-0.5 text-xs text-muted-foreground">
826
+ {t('rolesHint')}
827
+ </p>
828
+
829
+ <div className="mt-2 flex flex-wrap gap-1.5">
830
+ {roles.map((role) => {
831
+ const slug = role.slug ?? '';
832
+ const selected = plan.roles.includes(slug);
833
+
834
+ return (
835
+ <Badge
836
+ key={role.id}
837
+ variant="outline"
838
+ className={cn(
839
+ 'cursor-pointer rounded-full px-2.5 py-1',
840
+ selected
841
+ ? 'border-primary/40 bg-primary/10 text-primary'
842
+ : 'text-muted-foreground'
843
+ )}
844
+ onClick={() => {
845
+ if (slug === 'admin') {
846
+ return;
847
+ }
848
+
849
+ updatePlan({
850
+ roles: selected
851
+ ? plan.roles.filter((item) => item !== slug)
852
+ : [...plan.roles, slug],
853
+ });
854
+ }}
855
+ >
856
+ {getRoleLabel(role)}
857
+ </Badge>
858
+ );
859
+ })}
860
+ </div>
861
+ </div>
862
+ </div>
863
+ ) : null}
864
+
865
+ {!isDone && step === 5 ? (
866
+ <div className="space-y-3">
867
+ {issues.length > 0 ? (
868
+ <Alert variant="destructive">
869
+ <AlertTitle>{t('issuesTitle')}</AlertTitle>
870
+ <AlertDescription>
871
+ <ul className="list-disc pl-4">
872
+ {issues.map((issue) => (
873
+ <li key={`${issue.field}-${issue.message}`}>
874
+ {issue.message}
875
+ </li>
876
+ ))}
877
+ </ul>
878
+ </AlertDescription>
879
+ </Alert>
880
+ ) : null}
881
+
882
+ {preview?.conflicts.length ? (
883
+ <Alert>
884
+ <AlertTitle>{t('conflictsTitle')}</AlertTitle>
885
+ <AlertDescription>
886
+ <ul className="list-disc pl-4">
887
+ {preview.conflicts.map((file) => (
888
+ <li key={file} className="font-mono text-xs">
889
+ {file}
890
+ </li>
891
+ ))}
892
+ </ul>
893
+ <label className="mt-2 flex items-center gap-2 text-xs">
894
+ <Switch
895
+ checked={plan.overwrite}
896
+ onCheckedChange={(checked) =>
897
+ setPlan((previous) => ({
898
+ ...previous,
899
+ overwrite: checked,
900
+ }))
901
+ }
902
+ />
903
+ {t('overwrite')}
904
+ </label>
905
+ </AlertDescription>
906
+ </Alert>
907
+ ) : null}
908
+
909
+ {isWorking && !preview ? (
910
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
911
+ <Loader2 className="h-4 w-4 animate-spin" />
912
+ {t('previewLoading')}
913
+ </div>
914
+ ) : null}
915
+
916
+ {preview?.files.map((file) => (
917
+ <Card key={file.path} className="border-border/70 py-0">
918
+ <CardContent className="p-3">
919
+ <button
920
+ type="button"
921
+ className="flex w-full cursor-pointer items-center gap-2 text-left"
922
+ onClick={() =>
923
+ setExpandedFile((current) =>
924
+ current === file.path ? null : file.path
925
+ )
926
+ }
927
+ >
928
+ <Badge
929
+ variant="outline"
930
+ className={cn(
931
+ 'rounded-full px-2 py-0 text-[10px]',
932
+ file.action === 'create'
933
+ ? 'border-emerald-500/30 bg-emerald-500/10 text-emerald-600'
934
+ : file.action === 'manual'
935
+ ? 'border-amber-500/30 bg-amber-500/10 text-amber-600'
936
+ : 'border-blue-500/30 bg-blue-500/10 text-blue-600'
937
+ )}
938
+ >
939
+ {t(`action_${file.action}` as never)}
940
+ </Badge>
941
+ <span className="min-w-0 flex-1 truncate font-mono text-xs">
942
+ {file.path}
943
+ </span>
944
+ </button>
945
+
946
+ {file.instruction ? (
947
+ <p className="mt-2 text-xs text-amber-600">
948
+ {file.instruction}
949
+ </p>
950
+ ) : null}
951
+
952
+ {expandedFile === file.path && file.preview ? (
953
+ <pre className="mt-2 max-h-80 overflow-auto rounded-lg bg-muted/40 p-2 text-[11px] leading-4">
954
+ {file.preview}
955
+ </pre>
956
+ ) : null}
957
+ </CardContent>
958
+ </Card>
959
+ ))}
960
+ </div>
961
+ ) : null}
962
+ </div>
963
+ </ScrollArea>
964
+
965
+ <div className="flex items-center justify-between gap-2 border-t p-4">
966
+ <Button
967
+ type="button"
968
+ variant="outline"
969
+ disabled={step === 0 || isWorking || isDone}
970
+ onClick={() => setStep((current) => Math.max(0, current - 1))}
971
+ >
972
+ {t('back')}
973
+ </Button>
974
+
975
+ {isDone ? (
976
+ <Button type="button" onClick={() => onOpenChange(false)}>
977
+ {t('close')}
978
+ </Button>
979
+ ) : step < STEP_KEYS.length - 1 ? (
980
+ <Button type="button" disabled={!canAdvance} onClick={goNext}>
981
+ {t('next')}
982
+ </Button>
983
+ ) : (
984
+ <div className="flex gap-2">
985
+ <Button
986
+ type="button"
987
+ variant="outline"
988
+ disabled={isWorking}
989
+ onClick={runPreview}
990
+ >
991
+ {t('refreshPreview')}
992
+ </Button>
993
+ <Button
994
+ type="button"
995
+ disabled={isWorking || !preview || issues.length > 0}
996
+ onClick={runApply}
997
+ >
998
+ {isWorking ? (
999
+ <Loader2 className="h-4 w-4 animate-spin" />
1000
+ ) : null}
1001
+ {t('generate')}
1002
+ </Button>
1003
+ </div>
1004
+ )}
1005
+ </div>
1006
+ </ResizableSheetContent>
1007
+ </Sheet>
1008
+ );
1009
+ }