@hed-hog/core 0.0.328 → 0.0.330

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 (206) hide show
  1. package/dist/ai/ai.service.d.ts +1 -1
  2. package/dist/auth/auth.controller.d.ts +23 -23
  3. package/dist/auth/auth.service.d.ts +41 -41
  4. package/dist/challenge/challenge.service.d.ts +14 -14
  5. package/dist/core/system.controller.d.ts +1 -1
  6. package/dist/core/system.service.d.ts +1 -1
  7. package/dist/core.module.d.ts.map +1 -1
  8. package/dist/core.module.js +9 -2
  9. package/dist/core.module.js.map +1 -1
  10. package/dist/dashboard/dashboard/dashboard.controller.d.ts +84 -84
  11. package/dist/dashboard/dashboard/dashboard.service.d.ts +84 -84
  12. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +29 -29
  13. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +29 -29
  14. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +42 -42
  15. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +42 -42
  16. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +11 -11
  17. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +11 -11
  18. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +6 -6
  19. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +6 -6
  20. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +33 -33
  21. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +33 -33
  22. package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
  23. package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
  24. package/dist/file/file.controller.d.ts +10 -10
  25. package/dist/file/file.service.d.ts +22 -22
  26. package/dist/index.d.ts +11 -4
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +12 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/mail/mail.controller.d.ts +15 -15
  31. package/dist/mail/mail.service.d.ts +15 -15
  32. package/dist/mail-profile/mail-profile.controller.d.ts +9 -9
  33. package/dist/mail-profile/mail-profile.service.d.ts +9 -9
  34. package/dist/mail-sent/mail-sent.controller.d.ts +17 -17
  35. package/dist/mail-sent/mail-sent.service.d.ts +17 -17
  36. package/dist/mcp/decorators/mcp-tool.decorator.d.ts +4 -0
  37. package/dist/mcp/decorators/mcp-tool.decorator.d.ts.map +1 -0
  38. package/dist/mcp/decorators/mcp-tool.decorator.js +8 -0
  39. package/dist/mcp/decorators/mcp-tool.decorator.js.map +1 -0
  40. package/dist/mcp/guards/mcp-auth.guard.d.ts +9 -0
  41. package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -0
  42. package/dist/mcp/guards/mcp-auth.guard.js +41 -0
  43. package/dist/mcp/guards/mcp-auth.guard.js.map +1 -0
  44. package/dist/mcp/guards/mcp-permission.guard.d.ts +8 -0
  45. package/dist/mcp/guards/mcp-permission.guard.d.ts.map +1 -0
  46. package/dist/mcp/guards/mcp-permission.guard.js +57 -0
  47. package/dist/mcp/guards/mcp-permission.guard.js.map +1 -0
  48. package/dist/mcp/interfaces/mcp-tool-definition.interface.d.ts +7 -0
  49. package/dist/mcp/interfaces/mcp-tool-definition.interface.d.ts.map +1 -0
  50. package/dist/mcp/interfaces/mcp-tool-definition.interface.js +3 -0
  51. package/dist/mcp/interfaces/mcp-tool-definition.interface.js.map +1 -0
  52. package/dist/mcp/mcp-audit.service.d.ts +17 -0
  53. package/dist/mcp/mcp-audit.service.d.ts.map +1 -0
  54. package/dist/mcp/mcp-audit.service.js +46 -0
  55. package/dist/mcp/mcp-audit.service.js.map +1 -0
  56. package/dist/mcp/mcp-registry.service.d.ts +21 -0
  57. package/dist/mcp/mcp-registry.service.d.ts.map +1 -0
  58. package/dist/mcp/mcp-registry.service.js +69 -0
  59. package/dist/mcp/mcp-registry.service.js.map +1 -0
  60. package/dist/mcp/mcp-server.service.d.ts +12 -0
  61. package/dist/mcp/mcp-server.service.d.ts.map +1 -0
  62. package/dist/mcp/mcp-server.service.js +94 -0
  63. package/dist/mcp/mcp-server.service.js.map +1 -0
  64. package/dist/mcp/mcp.controller.d.ts +8 -0
  65. package/dist/mcp/mcp.controller.d.ts.map +1 -0
  66. package/dist/mcp/mcp.controller.js +54 -0
  67. package/dist/mcp/mcp.controller.js.map +1 -0
  68. package/dist/mcp/mcp.module.d.ts +3 -0
  69. package/dist/mcp/mcp.module.d.ts.map +1 -0
  70. package/dist/mcp/mcp.module.js +49 -0
  71. package/dist/mcp/mcp.module.js.map +1 -0
  72. package/dist/mcp/tools/core-settings.mcp-tools.d.ts +12 -0
  73. package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -0
  74. package/dist/mcp/tools/core-settings.mcp-tools.js +66 -0
  75. package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -0
  76. package/dist/mcp/tools/core-users.mcp-tools.d.ts +55 -0
  77. package/dist/mcp/tools/core-users.mcp-tools.d.ts.map +1 -0
  78. package/dist/mcp/tools/core-users.mcp-tools.js +295 -0
  79. package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -0
  80. package/dist/mcp/types/mcp-context.type.d.ts +7 -0
  81. package/dist/mcp/types/mcp-context.type.d.ts.map +1 -0
  82. package/dist/mcp/types/mcp-context.type.js +3 -0
  83. package/dist/mcp/types/mcp-context.type.js.map +1 -0
  84. package/dist/mcp-chat/dto/create-conversation.dto.d.ts +4 -0
  85. package/dist/mcp-chat/dto/create-conversation.dto.d.ts.map +1 -0
  86. package/dist/mcp-chat/dto/create-conversation.dto.js +22 -0
  87. package/dist/mcp-chat/dto/create-conversation.dto.js.map +1 -0
  88. package/dist/mcp-chat/dto/send-message.dto.d.ts +4 -0
  89. package/dist/mcp-chat/dto/send-message.dto.d.ts.map +1 -0
  90. package/dist/mcp-chat/dto/send-message.dto.js +22 -0
  91. package/dist/mcp-chat/dto/send-message.dto.js.map +1 -0
  92. package/dist/mcp-chat/mcp-chat.controller.d.ts +55 -0
  93. package/dist/mcp-chat/mcp-chat.controller.d.ts.map +1 -0
  94. package/dist/mcp-chat/mcp-chat.controller.js +90 -0
  95. package/dist/mcp-chat/mcp-chat.controller.js.map +1 -0
  96. package/dist/mcp-chat/mcp-chat.module.d.ts +3 -0
  97. package/dist/mcp-chat/mcp-chat.module.d.ts.map +1 -0
  98. package/dist/mcp-chat/mcp-chat.module.js +30 -0
  99. package/dist/mcp-chat/mcp-chat.module.js.map +1 -0
  100. package/dist/mcp-chat/mcp-chat.service.d.ts +50 -0
  101. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -0
  102. package/dist/mcp-chat/mcp-chat.service.js +290 -0
  103. package/dist/mcp-chat/mcp-chat.service.js.map +1 -0
  104. package/dist/menu/menu.controller.d.ts +8 -8
  105. package/dist/menu/menu.service.d.ts +8 -8
  106. package/dist/oauth/oauth.service.js +1 -1
  107. package/dist/oauth/oauth.service.js.map +1 -1
  108. package/dist/pdf/components/index.d.ts +57 -0
  109. package/dist/pdf/components/index.d.ts.map +1 -0
  110. package/dist/pdf/components/index.js +258 -0
  111. package/dist/pdf/components/index.js.map +1 -0
  112. package/dist/pdf/dto/generate-pdf.dto.d.ts +5 -0
  113. package/dist/pdf/dto/generate-pdf.dto.d.ts.map +1 -0
  114. package/dist/pdf/dto/generate-pdf.dto.js +27 -0
  115. package/dist/pdf/dto/generate-pdf.dto.js.map +1 -0
  116. package/dist/pdf/interfaces/pdf-theme-config.interface.d.ts +10 -0
  117. package/dist/pdf/interfaces/pdf-theme-config.interface.d.ts.map +1 -0
  118. package/dist/pdf/interfaces/pdf-theme-config.interface.js +3 -0
  119. package/dist/pdf/interfaces/pdf-theme-config.interface.js.map +1 -0
  120. package/dist/pdf/pdf.controller.d.ts +16 -0
  121. package/dist/pdf/pdf.controller.d.ts.map +1 -0
  122. package/dist/pdf/pdf.controller.js +100 -0
  123. package/dist/pdf/pdf.controller.js.map +1 -0
  124. package/dist/pdf/pdf.module.d.ts +3 -0
  125. package/dist/pdf/pdf.module.d.ts.map +1 -0
  126. package/dist/pdf/pdf.module.js +29 -0
  127. package/dist/pdf/pdf.module.js.map +1 -0
  128. package/dist/pdf/pdf.service.d.ts +44 -0
  129. package/dist/pdf/pdf.service.d.ts.map +1 -0
  130. package/dist/pdf/pdf.service.js +185 -0
  131. package/dist/pdf/pdf.service.js.map +1 -0
  132. package/dist/pdf/templates/hcode-institutional.template.d.ts +36 -0
  133. package/dist/pdf/templates/hcode-institutional.template.d.ts.map +1 -0
  134. package/dist/pdf/templates/hcode-institutional.template.js +67 -0
  135. package/dist/pdf/templates/hcode-institutional.template.js.map +1 -0
  136. package/dist/pdf/themes/hcode.theme.d.ts +25 -0
  137. package/dist/pdf/themes/hcode.theme.d.ts.map +1 -0
  138. package/dist/pdf/themes/hcode.theme.js +504 -0
  139. package/dist/pdf/themes/hcode.theme.js.map +1 -0
  140. package/dist/profile/profile.controller.d.ts +16 -16
  141. package/dist/profile/profile.service.d.ts +16 -16
  142. package/dist/role/role.controller.d.ts +12 -12
  143. package/dist/role/role.service.d.ts +12 -12
  144. package/dist/route/dto/create.dto.d.ts +6 -2
  145. package/dist/route/dto/create.dto.d.ts.map +1 -1
  146. package/dist/route/dto/create.dto.js +19 -1
  147. package/dist/route/dto/create.dto.js.map +1 -1
  148. package/dist/route/dto/update.dto.d.ts +4 -0
  149. package/dist/route/dto/update.dto.d.ts.map +1 -1
  150. package/dist/route/dto/update.dto.js +19 -3
  151. package/dist/route/dto/update.dto.js.map +1 -1
  152. package/dist/route/route.service.d.ts +1 -1
  153. package/dist/route/route.service.d.ts.map +1 -1
  154. package/dist/route/route.service.js +18 -11
  155. package/dist/route/route.service.js.map +1 -1
  156. package/dist/screen/screen.controller.d.ts +3 -3
  157. package/dist/screen/screen.service.d.ts +3 -3
  158. package/dist/session/session.controller.d.ts +4 -4
  159. package/dist/session/session.service.d.ts +12 -12
  160. package/dist/setting/setting.controller.d.ts +13 -13
  161. package/dist/setting/setting.service.d.ts +13 -13
  162. package/dist/user/user.controller.d.ts +24 -24
  163. package/dist/user/user.service.d.ts +55 -55
  164. package/hedhog/data/menu.yaml +40 -26
  165. package/hedhog/data/route.yaml +583 -152
  166. package/hedhog/data/setting_group.yaml +60 -0
  167. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +574 -0
  168. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +5 -9
  169. package/hedhog/frontend/messages/en.json +19 -0
  170. package/hedhog/frontend/messages/pt.json +19 -0
  171. package/hedhog/table/mcp_conversation.yaml +12 -0
  172. package/hedhog/table/mcp_conversation_message.yaml +23 -0
  173. package/hedhog/table/mcp_tool_call_log.yaml +22 -0
  174. package/hedhog/table/route.yaml +33 -22
  175. package/package.json +7 -6
  176. package/src/core.module.ts +18 -11
  177. package/src/index.ts +22 -12
  178. package/src/mcp/decorators/mcp-tool.decorator.ts +7 -0
  179. package/src/mcp/guards/mcp-auth.guard.ts +32 -0
  180. package/src/mcp/guards/mcp-permission.guard.ts +51 -0
  181. package/src/mcp/interfaces/mcp-tool-definition.interface.ts +6 -0
  182. package/src/mcp/mcp-audit.service.ts +36 -0
  183. package/src/mcp/mcp-registry.service.ts +69 -0
  184. package/src/mcp/mcp-server.service.ts +87 -0
  185. package/src/mcp/mcp.controller.ts +30 -0
  186. package/src/mcp/mcp.module.ts +36 -0
  187. package/src/mcp/tools/core-settings.mcp-tools.ts +53 -0
  188. package/src/mcp/tools/core-users.mcp-tools.ts +267 -0
  189. package/src/mcp/types/mcp-context.type.ts +6 -0
  190. package/src/mcp-chat/dto/create-conversation.dto.ts +7 -0
  191. package/src/mcp-chat/dto/send-message.dto.ts +7 -0
  192. package/src/mcp-chat/mcp-chat.controller.ts +60 -0
  193. package/src/mcp-chat/mcp-chat.module.ts +17 -0
  194. package/src/mcp-chat/mcp-chat.service.ts +332 -0
  195. package/src/oauth/oauth.service.ts +12 -12
  196. package/src/pdf/components/index.ts +316 -0
  197. package/src/pdf/dto/generate-pdf.dto.ts +11 -0
  198. package/src/pdf/interfaces/pdf-theme-config.interface.ts +10 -0
  199. package/src/pdf/pdf.controller.ts +86 -0
  200. package/src/pdf/pdf.module.ts +17 -0
  201. package/src/pdf/pdf.service.ts +229 -0
  202. package/src/pdf/templates/hcode-institutional.template.ts +122 -0
  203. package/src/pdf/themes/hcode.theme.ts +515 -0
  204. package/src/route/dto/create.dto.ts +32 -14
  205. package/src/route/dto/update.dto.ts +31 -16
  206. package/src/route/route.service.ts +23 -12
@@ -0,0 +1,515 @@
1
+ import { PdfAreaType, PdfThemeConfig } from '../interfaces/pdf-theme-config.interface';
2
+
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+ // Design System v1.0 – April 2026 – hardcoded defaults
5
+ // Overrides loaded from SettingService at runtime (see PdfService.loadThemeConfig)
6
+ // ─────────────────────────────────────────────────────────────────────────────
7
+
8
+ export interface AreaDefaults {
9
+ primary: string;
10
+ dark: string;
11
+ light: string;
12
+ }
13
+
14
+ /** Per-area color tokens — Design System v1.0 */
15
+ export const HCODE_DEFAULTS: Record<PdfAreaType, AreaDefaults> = {
16
+ // Blue 600 / Blue 800 / Blue 50
17
+ consulting: { primary: '#2D669E', dark: '#1F4A75', light: '#EAF1F8' },
18
+ // Orange 500 / Orange 700 / Orange 50
19
+ training: { primary: '#FF760C', dark: '#C45400', light: '#FFF0E2' },
20
+ // Violet 600 / Violet 800 / Violet 50
21
+ research: { primary: '#9400B5', dark: '#6A0083', light: '#F6E6FB' },
22
+ };
23
+
24
+ /** Neutral tokens — shared across all areas */
25
+ export const HCODE_NEUTRALS = {
26
+ ink1: '#101010', // body text
27
+ ink2: '#5D5D5D',
28
+ ink3: '#79756C',
29
+ line: '#ECECEC',
30
+ surface: '#FFFFFF',
31
+ surface2: '#F8F8F8',
32
+ } as const;
33
+
34
+ // ─────────────────────────────────────────────────────────────────────────────
35
+ // CSS builders
36
+ // ─────────────────────────────────────────────────────────────────────────────
37
+
38
+ /** Google Fonts import for Inter, Roboto and JetBrains Mono */
39
+ export function buildFontImport(): string {
40
+ return `<link rel="preconnect" href="https://fonts.googleapis.com">
41
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
42
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;600;700&family=Roboto:wght@400;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">`;
43
+ }
44
+
45
+ /**
46
+ * Generates the <style> block with all Design System CSS variables and rules.
47
+ * Typography scale is calibrated for A4 PDF (794 px viewport).
48
+ */
49
+ export function buildThemeCss(config: PdfThemeConfig): string {
50
+ return `<style>
51
+ /* ── CSS Variables ─────────────────────────────────────── */
52
+ :root {
53
+ /* Area accent */
54
+ --primary: ${config.primaryColor};
55
+ --dark: ${config.darkColor};
56
+ --light: ${config.lightColor};
57
+
58
+ /* Neutrals */
59
+ --ink-1: ${HCODE_NEUTRALS.ink1};
60
+ --ink-2: ${HCODE_NEUTRALS.ink2};
61
+ --ink-3: ${HCODE_NEUTRALS.ink3};
62
+ --line: ${HCODE_NEUTRALS.line};
63
+ --surface: ${HCODE_NEUTRALS.surface};
64
+ --surface-2:${HCODE_NEUTRALS.surface2};
65
+
66
+ /* Fonts */
67
+ --font-main: 'Inter', sans-serif;
68
+ --font-micro: 'Roboto', sans-serif;
69
+ --font-meta: 'JetBrains Mono', monospace;
70
+ }
71
+
72
+ /* ── Reset ─────────────────────────────────────────────── */
73
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
74
+
75
+ html, body {
76
+ font-family: var(--font-main);
77
+ font-size: 13px;
78
+ color: var(--ink-1);
79
+ background: var(--surface);
80
+ -webkit-print-color-adjust: exact;
81
+ print-color-adjust: exact;
82
+ }
83
+
84
+ /* ── Type Scale (A4-calibrated, DS v1.0 proportions) ───── */
85
+ /* Display / 80 → Inter 200, tracking -0.03em */
86
+ .t-display {
87
+ font-family: var(--font-main);
88
+ font-weight: 200;
89
+ font-size: 52px;
90
+ line-height: 1.05;
91
+ letter-spacing: -0.03em;
92
+ color: var(--ink-1);
93
+ }
94
+ /* H1 / 56 → Inter 300, tracking -0.02em */
95
+ .t-h1 {
96
+ font-family: var(--font-main);
97
+ font-weight: 300;
98
+ font-size: 36px;
99
+ line-height: 1.1;
100
+ letter-spacing: -0.02em;
101
+ color: var(--ink-1);
102
+ }
103
+ /* H2 / 36 → Inter 400 */
104
+ .t-h2 {
105
+ font-family: var(--font-main);
106
+ font-weight: 400;
107
+ font-size: 24px;
108
+ line-height: 1.15;
109
+ color: var(--ink-1);
110
+ }
111
+ /* H3 / 26 → Inter 600 */
112
+ .t-h3 {
113
+ font-family: var(--font-main);
114
+ font-weight: 600;
115
+ font-size: 17px;
116
+ line-height: 1.2;
117
+ color: var(--ink-1);
118
+ }
119
+ /* Eyebrow / 22 → Inter 400, tracking 0.36em, uppercase */
120
+ .t-eyebrow {
121
+ font-family: var(--font-main);
122
+ font-weight: 400;
123
+ font-size: 9px;
124
+ line-height: 1.4;
125
+ letter-spacing: 0.36em;
126
+ text-transform: uppercase;
127
+ color: var(--ink-3);
128
+ }
129
+ /* Body / 22 → Inter 300 */
130
+ .t-body {
131
+ font-family: var(--font-main);
132
+ font-weight: 300;
133
+ font-size: 13px;
134
+ line-height: 1.65;
135
+ color: var(--ink-2);
136
+ }
137
+ /* Meta / 14 → JetBrains Mono 500, tracking 0.18em */
138
+ .t-meta {
139
+ font-family: var(--font-meta);
140
+ font-weight: 500;
141
+ font-size: 8px;
142
+ line-height: 1.4;
143
+ letter-spacing: 0.18em;
144
+ text-transform: uppercase;
145
+ color: var(--ink-3);
146
+ }
147
+ /* Micro → Roboto 400 (rodapés, créditos) */
148
+ .t-micro {
149
+ font-family: var(--font-micro);
150
+ font-weight: 400;
151
+ font-size: 8px;
152
+ line-height: 1.4;
153
+ color: var(--ink-3);
154
+ }
155
+
156
+ /* ── Color utilities ────────────────────────────────────── */
157
+ .color-primary { color: var(--primary) !important; }
158
+ .bg-primary { background-color: var(--primary) !important; }
159
+ .bg-light { background-color: var(--light) !important; }
160
+ .bg-surface2 { background-color: var(--surface-2) !important; }
161
+
162
+ /* ── Page layout ────────────────────────────────────────── */
163
+ @page { size: A4; margin: 0; }
164
+
165
+ .page-content {
166
+ padding: 32px 48px 80px;
167
+ }
168
+
169
+ /* Page break utilities */
170
+ .break-before { page-break-before: always; break-before: page; }
171
+ .break-after { page-break-after: always; break-after: page; }
172
+ .no-break { page-break-inside: avoid; break-inside: avoid; }
173
+
174
+ /* ── Cover page ─────────────────────────────────────────── */
175
+ /* Two-column grid: left=white 55%, right=primary 45% */
176
+ .cover {
177
+ display: grid;
178
+ grid-template-columns: 55% 45%;
179
+ min-height: 297mm;
180
+ page-break-after: always;
181
+ break-after: page;
182
+ }
183
+ .cover-left {
184
+ background: var(--surface);
185
+ padding: 56px 40px 40px;
186
+ display: flex;
187
+ flex-direction: column;
188
+ justify-content: space-between;
189
+ }
190
+ .cover-right {
191
+ background: var(--primary);
192
+ padding: 40px 32px;
193
+ display: flex;
194
+ flex-direction: column;
195
+ align-items: flex-start;
196
+ justify-content: flex-end;
197
+ position: relative;
198
+ overflow: hidden;
199
+ }
200
+ .cover-right-glyph {
201
+ position: absolute;
202
+ top: -40px;
203
+ right: -20px;
204
+ font-family: var(--font-main);
205
+ font-weight: 300;
206
+ font-size: 280px;
207
+ color: rgba(255,255,255,0.10);
208
+ line-height: 1;
209
+ letter-spacing: -0.01em;
210
+ user-select: none;
211
+ pointer-events: none;
212
+ }
213
+ .cover-right-areas {
214
+ list-style: none;
215
+ width: 100%;
216
+ border-top: 1px solid rgba(255,255,255,0.25);
217
+ position: relative;
218
+ z-index: 1;
219
+ }
220
+ .cover-right-areas li {
221
+ font-family: var(--font-main);
222
+ font-weight: 400;
223
+ font-size: 9px;
224
+ letter-spacing: 0.30em;
225
+ text-transform: uppercase;
226
+ color: rgba(255,255,255,0.90);
227
+ padding: 10px 0;
228
+ border-bottom: 1px solid rgba(255,255,255,0.15);
229
+ display: flex;
230
+ align-items: center;
231
+ gap: 10px;
232
+ }
233
+ .cover-right-areas li .num {
234
+ font-family: var(--font-meta);
235
+ font-size: 7px;
236
+ opacity: 0.55;
237
+ }
238
+ .cover-system-label {
239
+ font-family: var(--font-meta);
240
+ font-size: 7px;
241
+ letter-spacing: 0.18em;
242
+ color: rgba(255,255,255,0.55);
243
+ position: absolute;
244
+ top: 16px;
245
+ left: 32px;
246
+ }
247
+ .cover-release-label {
248
+ font-family: var(--font-meta);
249
+ font-size: 7px;
250
+ letter-spacing: 0.18em;
251
+ color: rgba(255,255,255,0.55);
252
+ position: absolute;
253
+ top: 16px;
254
+ right: 32px;
255
+ display: flex;
256
+ align-items: center;
257
+ gap: 6px;
258
+ }
259
+ .cover-release-label::before {
260
+ content: '';
261
+ width: 6px;
262
+ height: 6px;
263
+ border-radius: 50%;
264
+ background: rgba(255,255,255,0.70);
265
+ }
266
+
267
+ /* ── Wordmark lockup ────────────────────────────────────── */
268
+ .lockup { display: flex; flex-direction: column; gap: 3px; }
269
+ .lockup-wordmark {
270
+ font-family: var(--font-main);
271
+ font-weight: 300;
272
+ font-size: 32px;
273
+ letter-spacing: -0.01em;
274
+ line-height: 1;
275
+ }
276
+ .lockup-wordmark .glyph { color: var(--primary); }
277
+ .lockup-wordmark .wordmark { color: var(--ink-3); }
278
+ .lockup-area {
279
+ font-family: var(--font-main);
280
+ font-weight: 400;
281
+ font-size: 9px;
282
+ letter-spacing: 0.30em;
283
+ text-transform: uppercase;
284
+ color: var(--primary);
285
+ }
286
+
287
+ /* ── Accent bar — fixed at top of EVERY page (cover included) ── */
288
+ .page-accent-bar {
289
+ position: fixed;
290
+ top: 0;
291
+ left: 0;
292
+ right: 0;
293
+ height: 6px;
294
+ background: var(--primary);
295
+ z-index: 999;
296
+ }
297
+
298
+ /* ── Page header (logo + page title) ───────────────────── */
299
+ .page-header {
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: space-between;
303
+ padding: 18px 48px 14px;
304
+ border-bottom: 1px solid var(--line);
305
+ }
306
+
307
+ /* ── Section header: eyebrow + title + left accent bar ─── */
308
+ .section-header {
309
+ display: flex;
310
+ flex-direction: column;
311
+ gap: 6px;
312
+ margin-bottom: 24px;
313
+ padding-left: 14px;
314
+ border-left: 3.5px solid var(--primary);
315
+ }
316
+
317
+ /* ── Purpose block (colored background) ─────────────────── */
318
+ .purpose-block {
319
+ background: var(--primary);
320
+ border-radius: 14px;
321
+ padding: 28px 32px;
322
+ margin-bottom: 28px;
323
+ page-break-inside: avoid;
324
+ break-inside: avoid;
325
+ }
326
+ .purpose-block .t-eyebrow { color: rgba(255,255,255,0.65); margin-bottom: 8px; }
327
+ .purpose-block .t-h3 { color: #ffffff; margin-bottom: 12px; font-size: 18px; font-weight: 600; }
328
+ .purpose-block .t-body { color: rgba(255,255,255,0.85); font-size: 12px; }
329
+
330
+ /* ── Feature cards (3-column grid) ─────────────────────── */
331
+ .feature-cards {
332
+ display: grid;
333
+ grid-template-columns: repeat(3, 1fr);
334
+ gap: 14px;
335
+ margin-bottom: 28px;
336
+ }
337
+ .feature-card {
338
+ border: 1px solid var(--line);
339
+ border-radius: 12px;
340
+ padding: 18px 14px;
341
+ background: var(--surface);
342
+ page-break-inside: avoid;
343
+ break-inside: avoid;
344
+ }
345
+ .feature-card-icon {
346
+ width: 38px;
347
+ height: 32px;
348
+ border: 1.5px solid var(--line);
349
+ border-radius: 8px;
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: center;
353
+ margin-bottom: 10px;
354
+ color: var(--primary);
355
+ }
356
+ .feature-card-title {
357
+ font-family: var(--font-main);
358
+ font-weight: 600;
359
+ font-size: 12px;
360
+ color: var(--primary);
361
+ margin-bottom: 5px;
362
+ letter-spacing: -0.01em;
363
+ }
364
+ .feature-card-desc {
365
+ font-family: var(--font-main);
366
+ font-weight: 300;
367
+ font-size: 10px;
368
+ line-height: 1.55;
369
+ color: var(--ink-2);
370
+ }
371
+
372
+ /* ── Chip ─────────────────────────────────────────────── */
373
+ .chip {
374
+ display: inline-flex;
375
+ align-items: center;
376
+ gap: 5px;
377
+ padding: 3px 10px;
378
+ border-radius: 999px;
379
+ background: var(--light);
380
+ font-family: var(--font-main);
381
+ font-weight: 400;
382
+ font-size: 9px;
383
+ color: var(--primary);
384
+ letter-spacing: 0.01em;
385
+ }
386
+ .chip::before {
387
+ content: '';
388
+ width: 5px;
389
+ height: 5px;
390
+ border-radius: 50%;
391
+ background: var(--primary);
392
+ flex-shrink: 0;
393
+ }
394
+
395
+ /* ── Data table ──────────────────────────────────────── */
396
+ .data-table {
397
+ width: 100%;
398
+ border-collapse: collapse;
399
+ margin-bottom: 28px;
400
+ }
401
+ .data-table thead tr { background: var(--light); }
402
+ .data-table th {
403
+ font-family: var(--font-meta);
404
+ font-weight: 500;
405
+ font-size: 8px;
406
+ letter-spacing: 0.18em;
407
+ text-transform: uppercase;
408
+ color: var(--primary);
409
+ padding: 9px 13px;
410
+ text-align: left;
411
+ border-bottom: 1.5px solid var(--primary);
412
+ }
413
+ .data-table td {
414
+ font-family: var(--font-main);
415
+ font-weight: 300;
416
+ font-size: 10px;
417
+ color: var(--ink-2);
418
+ padding: 9px 13px;
419
+ border-bottom: 1px solid var(--line);
420
+ }
421
+ .data-table tbody tr { page-break-inside: avoid; break-inside: avoid; }
422
+ .data-table tbody tr:nth-child(even) td { background: var(--surface-2); }
423
+
424
+ /* ── Metadata block ──────────────────────────────────── */
425
+ .metadata-block {
426
+ display: grid;
427
+ grid-template-columns: repeat(4, 1fr);
428
+ gap: 0;
429
+ border: 1px solid var(--line);
430
+ border-radius: 12px;
431
+ overflow: hidden;
432
+ margin-bottom: 28px;
433
+ page-break-inside: avoid;
434
+ break-inside: avoid;
435
+ }
436
+ .metadata-item {
437
+ padding: 14px 16px;
438
+ border-right: 1px solid var(--line);
439
+ background: var(--surface);
440
+ }
441
+ .metadata-item:nth-child(4n) { border-right: none; }
442
+ .metadata-item:nth-child(4n+4) { border-right: none; }
443
+ .metadata-item:nth-child(n+5) { border-top: 1px solid var(--line); }
444
+ .metadata-label {
445
+ font-family: var(--font-meta);
446
+ font-weight: 500;
447
+ font-size: 7px;
448
+ letter-spacing: 0.18em;
449
+ text-transform: uppercase;
450
+ color: var(--ink-3);
451
+ margin-bottom: 4px;
452
+ }
453
+ .metadata-value {
454
+ font-family: var(--font-main);
455
+ font-weight: 400;
456
+ font-size: 11px;
457
+ color: var(--ink-1);
458
+ }
459
+
460
+ /* ── Signature area ──────────────────────────────────── */
461
+ .signature-area {
462
+ display: grid;
463
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
464
+ gap: 24px;
465
+ margin-top: 28px;
466
+ page-break-inside: avoid;
467
+ break-inside: avoid;
468
+ }
469
+ .signature-item { display: flex; flex-direction: column; gap: 6px; }
470
+ .signature-line {
471
+ width: 100%;
472
+ height: 1px;
473
+ background: var(--ink-1);
474
+ margin-bottom: 5px;
475
+ }
476
+ .signature-label {
477
+ font-family: var(--font-micro);
478
+ font-size: 8px;
479
+ color: var(--ink-3);
480
+ }
481
+ .signature-name {
482
+ font-family: var(--font-main);
483
+ font-weight: 400;
484
+ font-size: 10px;
485
+ color: var(--ink-2);
486
+ }
487
+
488
+ /* ── Fixed footer (repeats on every page) ───────────── */
489
+ .pdf-footer {
490
+ position: fixed;
491
+ bottom: 0;
492
+ left: 0;
493
+ right: 0;
494
+ height: 40px;
495
+ display: flex;
496
+ align-items: center;
497
+ justify-content: space-between;
498
+ padding: 0 48px;
499
+ border-top: 1px solid var(--line);
500
+ background: var(--surface);
501
+ }
502
+ /* CSS counter for page numbering */
503
+ @page { counter-increment: page; }
504
+ .pdf-footer-page::after {
505
+ content: counter(page);
506
+ font-family: var(--font-meta);
507
+ font-size: 8px;
508
+ letter-spacing: 0.18em;
509
+ color: var(--ink-3);
510
+ }
511
+
512
+ /* Padding to avoid content overlapping the fixed header bar and footer */
513
+ body { padding-top: 6px; padding-bottom: 48px; }
514
+ </style>`;
515
+ }
@@ -1,14 +1,32 @@
1
- import { getLocaleText } from '@hed-hog/api-locale';
2
- import { IsIn, IsString } from 'class-validator';
3
- import { HttpMethod } from '../../types/http-method';
4
-
5
- export class CreateDTO {
6
- @IsString({ message: (args) => getLocaleText('validation.urlMustBeString', args.value) })
7
- url: string;
8
-
9
- @IsString({ message: (args) => getLocaleText('validation.methodMustBeString', args.value) })
10
- @IsIn(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'], {
11
- message: (args) => getLocaleText('validation.methodMustBeValid', args.value),
12
- })
13
- method: HttpMethod;
14
- }
1
+ import { getLocaleText } from '@hed-hog/api-locale';
2
+ import { IsIn, IsOptional, IsString } from 'class-validator';
3
+ import { HttpMethod } from '../../types/http-method';
4
+
5
+ export type RouteType = 'HTTP' | 'MCP';
6
+
7
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'];
8
+
9
+ export class CreateDTO {
10
+ @IsOptional()
11
+ @IsString({ message: (args) => getLocaleText('validation.urlMustBeString', args.value) })
12
+ url?: string;
13
+
14
+ @IsOptional()
15
+ @IsString({ message: (args) => getLocaleText('validation.methodMustBeString', args.value) })
16
+ @IsIn(HTTP_METHODS, {
17
+ message: (args) => getLocaleText('validation.methodMustBeValid', args.value),
18
+ })
19
+ method?: HttpMethod;
20
+
21
+ @IsOptional()
22
+ @IsIn(['HTTP', 'MCP'])
23
+ type?: RouteType;
24
+
25
+ @IsOptional()
26
+ @IsString()
27
+ tool_name?: string;
28
+
29
+ @IsOptional()
30
+ @IsString()
31
+ name?: string;
32
+ }
@@ -1,16 +1,31 @@
1
- import { getLocaleText } from '@hed-hog/api-locale';
2
- import { IsIn, IsOptional, IsString } from 'class-validator';
3
- import { HttpMethod } from '../../types/http-method';
4
-
5
- export class UpdateDTO {
6
- @IsString({ message: (args) => getLocaleText('validation.urlMustBeString', args.value) })
7
- @IsOptional()
8
- url?: string;
9
-
10
- @IsString({ message: (args) => getLocaleText('validation.methodMustBeString', args.value) })
11
- @IsOptional()
12
- @IsIn(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'], {
13
- message: (args) => getLocaleText('validation.methodMustBeValid', args.value),
14
- })
15
- method?: HttpMethod;
16
- }
1
+ import { getLocaleText } from '@hed-hog/api-locale';
2
+ import { IsIn, IsOptional, IsString } from 'class-validator';
3
+ import { HttpMethod } from '../../types/http-method';
4
+ import { RouteType } from './create.dto';
5
+
6
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'];
7
+
8
+ export class UpdateDTO {
9
+ @IsOptional()
10
+ @IsString({ message: (args) => getLocaleText('validation.urlMustBeString', args.value) })
11
+ url?: string;
12
+
13
+ @IsOptional()
14
+ @IsString({ message: (args) => getLocaleText('validation.methodMustBeString', args.value) })
15
+ @IsIn(HTTP_METHODS, {
16
+ message: (args) => getLocaleText('validation.methodMustBeValid', args.value),
17
+ })
18
+ method?: HttpMethod;
19
+
20
+ @IsOptional()
21
+ @IsIn(['HTTP', 'MCP'])
22
+ type?: RouteType;
23
+
24
+ @IsOptional()
25
+ @IsString()
26
+ tool_name?: string;
27
+
28
+ @IsOptional()
29
+ @IsString()
30
+ name?: string;
31
+ }
@@ -17,7 +17,7 @@ export class RouteService {
17
17
  ) {}
18
18
 
19
19
  async list(paginationParams: PaginationDTO) {
20
- const fields = ['url', 'method'];
20
+ const fields = ['url', 'method', 'tool_name', 'name'];
21
21
 
22
22
  const OR: any[] = this.prismaService.createInsensitiveSearch(
23
23
  fields,
@@ -45,20 +45,31 @@ export class RouteService {
45
45
  return route;
46
46
  }
47
47
 
48
- async create({ url, method }: CreateDTO, locale: string): Promise<any> {
49
-
50
- const existingRoute = await this.prismaService.route.findFirst({
51
- where: {
52
- url,
53
- method,
54
- },
55
- });
48
+ async create({ url, method, type = 'HTTP', tool_name, name }: CreateDTO, locale: string): Promise<any> {
49
+
50
+ if (type === 'HTTP' && url && method) {
51
+ const existingRoute = await this.prismaService.route.findFirst({
52
+ where: { url, method },
53
+ });
54
+ if (existingRoute) {
55
+ throw new BadRequestException(
56
+ getLocaleText('itemAlreadyExists', locale, `Route with URL ${url} and method ${method} already exists`).replace('{{item}}', 'Route'),
57
+ );
58
+ }
59
+ }
56
60
 
57
- if (existingRoute) {
58
- throw new BadRequestException(getLocaleText('itemAlreadyExists', locale, `Route with URL ${url} and method ${method} already exists`).replace('{{item}}', 'Route'));
61
+ if (type === 'MCP' && tool_name) {
62
+ const existingTool = await this.prismaService.route.findFirst({
63
+ where: { tool_name },
64
+ });
65
+ if (existingTool) {
66
+ throw new BadRequestException(
67
+ getLocaleText('itemAlreadyExists', locale, `MCP tool '${tool_name}' already exists`).replace('{{item}}', 'MCP tool'),
68
+ );
69
+ }
59
70
  }
60
71
 
61
- return this.prismaService.route.create({ data: { url, method } });
72
+ return this.prismaService.route.create({ data: { url, method, type: type as any, tool_name, name } });
62
73
  }
63
74
 
64
75
  async update({ id, data }: { id: number; data: UpdateDTO }, locale: string): Promise<any> {