@hed-hog/core 0.0.356 → 0.0.359
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.
- package/dist/auth/guards/auth.guard.d.ts +6 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +33 -2
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/file/file.controller.d.ts +4 -2
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +44 -38
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +2 -2
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +25 -42
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +10 -15
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +8 -9
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +11 -10
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +16 -6
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +4 -20
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts.map +1 -1
- package/dist/file/provider/spaces.provider.js +4 -19
- package/dist/file/provider/spaces.provider.js.map +1 -1
- package/dist/integration-profile/integration-profile.controller.d.ts +1 -1
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.controller.js +4 -3
- package/dist/integration-profile/integration-profile.controller.js.map +1 -1
- package/dist/integration-profile/integration-profile.service.d.ts +1 -1
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +7 -4
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.d.ts +6 -0
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +9 -0
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/mail/mail.module.d.ts.map +1 -1
- package/dist/mail/mail.module.js +9 -4
- package/dist/mail/mail.module.js.map +1 -1
- package/dist/mail/mail.service.d.ts +2 -1
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +11 -7
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +2 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.controller.js +1 -1
- package/dist/mcp/mcp-api-key.controller.js.map +1 -1
- package/dist/mcp/mcp-api-key.service.d.ts +2 -1
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.service.js +6 -2
- package/dist/mcp/mcp-api-key.service.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +1 -3
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.d.ts +4 -1
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +31 -5
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +12 -1
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +125 -23
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.d.ts +5 -2
- package/dist/oauth/providers/facebook.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.js +34 -19
- package/dist/oauth/providers/facebook.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.d.ts +6 -2
- package/dist/oauth/providers/github.provider.d.ts.map +1 -1
- package/dist/oauth/providers/github.provider.js +43 -20
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/google.provider.d.ts +5 -2
- package/dist/oauth/providers/google.provider.d.ts.map +1 -1
- package/dist/oauth/providers/google.provider.js +34 -19
- package/dist/oauth/providers/google.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +43 -40
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft.provider.js +34 -19
- package/dist/oauth/providers/microsoft.provider.js.map +1 -1
- package/dist/profile/profile.controller.js +1 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/security/security.service.d.ts +2 -0
- package/dist/security/security.service.d.ts.map +1 -1
- package/dist/security/security.service.js +21 -0
- package/dist/security/security.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +26 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +240 -5
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +2 -1
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +5 -4
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +4 -2
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +19 -4
- package/dist/user/user.service.js.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +17 -2
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.js +93 -2
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -1
- package/dist/webhook-integration/webhook-command.registry.d.ts +15 -0
- package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -0
- package/dist/webhook-integration/webhook-command.registry.js +36 -0
- package/dist/webhook-integration/webhook-command.registry.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +19 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +38 -0
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.js +5 -0
- package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +25 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +332 -23
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/integration_provider.yaml +16 -0
- package/hedhog/data/menu.yaml +0 -16
- package/hedhog/data/route.yaml +32 -383
- package/hedhog/data/setting_group.yaml +179 -174
- package/hedhog/data/setting_subgroup.yaml +16 -0
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +421 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +6 -3
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/account/tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +414 -76
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +3 -1
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +186 -18
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +597 -21
- package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +229 -395
- package/hedhog/frontend/messages/en.json +67 -3
- package/hedhog/frontend/messages/pt.json +67 -3
- package/hedhog/table/file.yaml +1 -1
- package/hedhog/table/mcp_api_key.yaml +4 -0
- package/hedhog/table/webhook_action.yaml +57 -1
- package/package.json +5 -4
- package/src/auth/guards/auth.guard.ts +32 -0
- package/src/file/file.controller.ts +51 -42
- package/src/file/file.service.ts +31 -52
- package/src/file/provider/azure.provider.ts +14 -28
- package/src/file/provider/gcs.provider.ts +9 -9
- package/src/file/provider/local.provider.ts +10 -13
- package/src/file/provider/provider.factory.ts +19 -7
- package/src/file/provider/s3.provider.ts +4 -20
- package/src/file/provider/spaces.provider.ts +4 -19
- package/src/integration-profile/integration-profile.controller.ts +2 -0
- package/src/integration-profile/integration-profile.service.ts +7 -2
- package/src/integration-profile/integration-profile.utils.ts +17 -0
- package/src/mail/mail.module.ts +14 -4
- package/src/mail/mail.service.ts +12 -7
- package/src/mcp/guards/mcp-auth.guard.ts +1 -1
- package/src/mcp/mcp-api-key.controller.ts +2 -2
- package/src/mcp/mcp-api-key.service.ts +6 -2
- package/src/mcp/mcp.module.ts +1 -3
- package/src/oauth/interfaces/OAuthProvider.ts +1 -1
- package/src/oauth/oauth.controller.ts +30 -2
- package/src/oauth/oauth.service.ts +194 -35
- package/src/oauth/providers/abstract.provider.ts +1 -1
- package/src/oauth/providers/facebook.provider.ts +36 -20
- package/src/oauth/providers/github.provider.ts +46 -23
- package/src/oauth/providers/google.provider.ts +36 -20
- package/src/oauth/providers/microsoft-entra-id.provider.ts +42 -46
- package/src/oauth/providers/microsoft.provider.ts +36 -21
- package/src/profile/profile.controller.ts +2 -2
- package/src/security/security.service.ts +34 -1
- package/src/setting/setting.service.ts +307 -7
- package/src/user/user.controller.ts +4 -1
- package/src/user/user.service.ts +20 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +85 -4
- package/src/webhook-integration/webhook-command.registry.ts +42 -0
- package/src/webhook-integration/webhook-integration.controller.ts +20 -0
- package/src/webhook-integration/webhook-integration.module.ts +50 -45
- package/src/webhook-integration/webhook-integration.service.ts +374 -11
- package/dist/mail-profile/dto/create.dto.d.ts +0 -23
- package/dist/mail-profile/dto/create.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/create.dto.js +0 -139
- package/dist/mail-profile/dto/create.dto.js.map +0 -1
- package/dist/mail-profile/dto/update.dto.d.ts +0 -6
- package/dist/mail-profile/dto/update.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/update.dto.js +0 -9
- package/dist/mail-profile/dto/update.dto.js.map +0 -1
- package/dist/mail-profile/mail-profile.controller.d.ts +0 -94
- package/dist/mail-profile/mail-profile.controller.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.controller.js +0 -95
- package/dist/mail-profile/mail-profile.controller.js.map +0 -1
- package/dist/mail-profile/mail-profile.module.d.ts +0 -3
- package/dist/mail-profile/mail-profile.module.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.module.js +0 -31
- package/dist/mail-profile/mail-profile.module.js.map +0 -1
- package/dist/mail-profile/mail-profile.service.d.ts +0 -109
- package/dist/mail-profile/mail-profile.service.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.service.js +0 -278
- package/dist/mail-profile/mail-profile.service.js.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +0 -20
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +0 -96
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +0 -1
- package/dist/whatsapp-profile/dto/create.dto.d.ts +0 -11
- package/dist/whatsapp-profile/dto/create.dto.d.ts.map +0 -1
- package/dist/whatsapp-profile/dto/create.dto.js +0 -55
- package/dist/whatsapp-profile/dto/create.dto.js.map +0 -1
- package/dist/whatsapp-profile/dto/update.dto.d.ts +0 -6
- package/dist/whatsapp-profile/dto/update.dto.d.ts.map +0 -1
- package/dist/whatsapp-profile/dto/update.dto.js +0 -9
- package/dist/whatsapp-profile/dto/update.dto.js.map +0 -1
- package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts +0 -54
- package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts.map +0 -1
- package/dist/whatsapp-profile/whatsapp-profile.controller.js +0 -85
- package/dist/whatsapp-profile/whatsapp-profile.controller.js.map +0 -1
- package/dist/whatsapp-profile/whatsapp-profile.module.d.ts +0 -3
- package/dist/whatsapp-profile/whatsapp-profile.module.d.ts.map +0 -1
- package/dist/whatsapp-profile/whatsapp-profile.module.js +0 -26
- package/dist/whatsapp-profile/whatsapp-profile.module.js.map +0 -1
- package/dist/whatsapp-profile/whatsapp-profile.service.d.ts +0 -63
- package/dist/whatsapp-profile/whatsapp-profile.service.d.ts.map +0 -1
- package/dist/whatsapp-profile/whatsapp-profile.service.js +0 -138
- package/dist/whatsapp-profile/whatsapp-profile.service.js.map +0 -1
- package/hedhog/data/mail_profile.yaml +0 -18
- package/hedhog/data/whatsapp_profile.yaml +0 -6
- package/hedhog/table/mail_profile.yaml +0 -75
- package/hedhog/table/whatsapp_profile.yaml +0 -26
- package/src/mail-profile/dto/create.dto.ts +0 -145
- package/src/mail-profile/dto/update.dto.ts +0 -4
- package/src/mail-profile/mail-profile.controller.ts +0 -56
- package/src/mail-profile/mail-profile.module.ts +0 -18
- package/src/mail-profile/mail-profile.service.ts +0 -308
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +0 -69
- package/src/whatsapp-profile/dto/create.dto.ts +0 -36
- package/src/whatsapp-profile/dto/update.dto.ts +0 -4
- package/src/whatsapp-profile/whatsapp-profile.controller.ts +0 -51
- package/src/whatsapp-profile/whatsapp-profile.module.ts +0 -13
- package/src/whatsapp-profile/whatsapp-profile.service.ts +0 -160
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
"tabAccounts": "Accounts",
|
|
77
77
|
"tabSessions": "Sessions",
|
|
78
78
|
"tabMcpTokens": "MCP Tokens",
|
|
79
|
+
"tabTokens": "Tokens",
|
|
79
80
|
"breadcrumbLabel": "Account",
|
|
80
81
|
"home": "Home",
|
|
81
82
|
"title": "Account",
|
|
@@ -139,12 +140,12 @@
|
|
|
139
140
|
"home": "Home",
|
|
140
141
|
"core": "Core"
|
|
141
142
|
},
|
|
142
|
-
"title": "
|
|
143
|
-
"description": "Manage
|
|
143
|
+
"title": "Setting Lists",
|
|
144
|
+
"description": "Manage items for list-type settings (combobox and checkbox).",
|
|
144
145
|
"searchPlaceholder": "Search by name, slug, description or option...",
|
|
145
146
|
"loading": "Loading settings...",
|
|
146
147
|
"emptyTitle": "No list settings found",
|
|
147
|
-
"emptyDescriptionNoSettings": "
|
|
148
|
+
"emptyDescriptionNoSettings": "There are no list-type settings (combobox/checkbox) configured.",
|
|
148
149
|
"emptyDescriptionFiltered": "No setting matched the current filter.",
|
|
149
150
|
"itemCount": "{count, plural, one {# item} other {# items}}",
|
|
150
151
|
"emptyOptions": "No options configured.",
|
|
@@ -153,7 +154,18 @@
|
|
|
153
154
|
"optionsSavedError": "Could not update options.",
|
|
154
155
|
"optionsClearedSuccess": "List cleared successfully.",
|
|
155
156
|
"optionsClearedError": "Could not clear the list.",
|
|
157
|
+
"viewMode": {
|
|
158
|
+
"list": "List",
|
|
159
|
+
"cards": "Cards"
|
|
160
|
+
},
|
|
161
|
+
"columns": {
|
|
162
|
+
"group": "Group",
|
|
163
|
+
"name": "Name",
|
|
164
|
+
"type": "Type",
|
|
165
|
+
"items": "Items"
|
|
166
|
+
},
|
|
156
167
|
"actions": {
|
|
168
|
+
"refresh": "Refresh",
|
|
157
169
|
"editOptions": "Edit list",
|
|
158
170
|
"clearOptions": "Clear list",
|
|
159
171
|
"addOption": "Add option",
|
|
@@ -1221,6 +1233,10 @@
|
|
|
1221
1233
|
"selectWhatsAppProfile": "Select a WhatsApp profile",
|
|
1222
1234
|
"selectStorageProfile": "Select a storage profile",
|
|
1223
1235
|
"storageProfileEmptyState": "No storage profiles found.",
|
|
1236
|
+
"selectAiProfile": "Select an AI profile",
|
|
1237
|
+
"aiProfileEmptyState": "No AI profiles found.",
|
|
1238
|
+
"selectOAuthProfile": "Select an OAuth profile",
|
|
1239
|
+
"oauthProfileEmptyState": "No OAuth profiles found.",
|
|
1224
1240
|
"mailProfile": {
|
|
1225
1241
|
"nameLabel": "Name *",
|
|
1226
1242
|
"namePlaceholder": "My Mail Profile",
|
|
@@ -2056,6 +2072,49 @@
|
|
|
2056
2072
|
"revokeSuccess": "API key revoked",
|
|
2057
2073
|
"revokeFailure": "Failed to revoke API key"
|
|
2058
2074
|
},
|
|
2075
|
+
"Tokens": {
|
|
2076
|
+
"title": "Access Tokens",
|
|
2077
|
+
"description": "Create and manage tokens for MCP server and REST API access",
|
|
2078
|
+
"createToken": "Create Token",
|
|
2079
|
+
"createTokenTitle": "Create Token",
|
|
2080
|
+
"createTokenDescription": "Choose the token type and give it a name to identify it later",
|
|
2081
|
+
"tokenTypeLabel": "Token Type",
|
|
2082
|
+
"typeMcp": "MCP",
|
|
2083
|
+
"typeApi": "API",
|
|
2084
|
+
"tokenNameLabel": "Token Name",
|
|
2085
|
+
"tokenNamePlaceholder": "e.g. My Application",
|
|
2086
|
+
"tokenCreatedTitle": "Token Created",
|
|
2087
|
+
"tokenCreatedWarning": "This token is shown only once. Copy it now and store it safely.",
|
|
2088
|
+
"tokenCreatedLabel": "Your new token",
|
|
2089
|
+
"closeDialog": "Close",
|
|
2090
|
+
"mcpUrlLabel": "MCP Server URL",
|
|
2091
|
+
"name": "Name",
|
|
2092
|
+
"type": "Type",
|
|
2093
|
+
"tokenPrefix": "Token Prefix",
|
|
2094
|
+
"lastUsed": "Last Used",
|
|
2095
|
+
"createdAt": "Created At",
|
|
2096
|
+
"never": "Never",
|
|
2097
|
+
"today": "Today",
|
|
2098
|
+
"daysAgo": "{days} days ago",
|
|
2099
|
+
"noTokens": "No tokens yet. Create one to get started.",
|
|
2100
|
+
"revokeTokenTitle": "Revoke Token",
|
|
2101
|
+
"revokeTokenDescription": "This token will stop working immediately. This action cannot be undone.",
|
|
2102
|
+
"cancel": "Cancel",
|
|
2103
|
+
"revokeConfirm": "Revoke",
|
|
2104
|
+
"closeSheet": "Done",
|
|
2105
|
+
"createFailure": "Failed to create token",
|
|
2106
|
+
"revokeSuccess": "Token revoked",
|
|
2107
|
+
"revokeFailure": "Failed to revoke token",
|
|
2108
|
+
"usageTitle": "Usage Instructions",
|
|
2109
|
+
"serverUrlLabel": "Server URL",
|
|
2110
|
+
"yourToken": "your-token",
|
|
2111
|
+
"mcpUsageDesc": "Configure your MCP client with the server URL below and pass the token as an Authorization header.",
|
|
2112
|
+
"mcpUsageHeader": "Add this header to your MCP client configuration:",
|
|
2113
|
+
"mcpUsageExampleLabel": "Example (Claude Desktop / Cursor):",
|
|
2114
|
+
"apiUsageDesc": "Use this token to authenticate REST API requests by passing it as a Bearer token in the Authorization header.",
|
|
2115
|
+
"apiUsageHeader": "Add this header to every request:",
|
|
2116
|
+
"apiUsageExampleLabel": "Example (curl):"
|
|
2117
|
+
},
|
|
2059
2118
|
"McpFloatingChat": {
|
|
2060
2119
|
"title": "MCP Chat",
|
|
2061
2120
|
"openFullPage": "Open full view",
|
|
@@ -2280,6 +2339,11 @@
|
|
|
2280
2339
|
"fieldOrganization": "Organization ID",
|
|
2281
2340
|
"fieldRedirectUri": "Redirect URI",
|
|
2282
2341
|
"fieldTenantId": "Tenant ID",
|
|
2342
|
+
"callbackUrlsSectionTitle": "Callback URLs",
|
|
2343
|
+
"callbackUrlsDescription": "Register these URLs in your OAuth application settings.",
|
|
2344
|
+
"addCallbackUrl": "Add URL",
|
|
2345
|
+
"noCallbackUrls": "No callback URLs configured.",
|
|
2346
|
+
"callbackUrlPlaceholder": "https://yourdomain.com/callback/...",
|
|
2283
2347
|
"showPassword": "Show value",
|
|
2284
2348
|
"hidePassword": "Hide value"
|
|
2285
2349
|
}
|
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
"tabAccounts": "Contas",
|
|
77
77
|
"tabSessions": "Sessões",
|
|
78
78
|
"tabMcpTokens": "Tokens MCP",
|
|
79
|
+
"tabTokens": "Tokens",
|
|
79
80
|
"breadcrumbLabel": "Conta",
|
|
80
81
|
"home": "Home",
|
|
81
82
|
"title": "Conta",
|
|
@@ -139,12 +140,12 @@
|
|
|
139
140
|
"home": "Home",
|
|
140
141
|
"core": "Core"
|
|
141
142
|
},
|
|
142
|
-
"title": "
|
|
143
|
-
"description": "Gerencie
|
|
143
|
+
"title": "Listas de Configuração",
|
|
144
|
+
"description": "Gerencie os itens das configurações do tipo lista (combobox e checkbox).",
|
|
144
145
|
"searchPlaceholder": "Pesquisar por nome, slug, descrição ou opção...",
|
|
145
146
|
"loading": "Carregando configurações...",
|
|
146
147
|
"emptyTitle": "Nenhuma setting de lista encontrada",
|
|
147
|
-
"emptyDescriptionNoSettings": "
|
|
148
|
+
"emptyDescriptionNoSettings": "Não há configurações do tipo lista (combobox/checkbox) cadastradas.",
|
|
148
149
|
"emptyDescriptionFiltered": "Nenhuma setting encontrada para o filtro informado.",
|
|
149
150
|
"itemCount": "{count, plural, one {# item} other {# itens}}",
|
|
150
151
|
"emptyOptions": "Nenhuma opção cadastrada.",
|
|
@@ -153,7 +154,18 @@
|
|
|
153
154
|
"optionsSavedError": "Não foi possível atualizar as opções.",
|
|
154
155
|
"optionsClearedSuccess": "Lista limpa com sucesso.",
|
|
155
156
|
"optionsClearedError": "Não foi possível limpar a lista.",
|
|
157
|
+
"viewMode": {
|
|
158
|
+
"list": "Lista",
|
|
159
|
+
"cards": "Cards"
|
|
160
|
+
},
|
|
161
|
+
"columns": {
|
|
162
|
+
"group": "Grupo",
|
|
163
|
+
"name": "Nome",
|
|
164
|
+
"type": "Tipo",
|
|
165
|
+
"items": "Itens"
|
|
166
|
+
},
|
|
156
167
|
"actions": {
|
|
168
|
+
"refresh": "Atualizar",
|
|
157
169
|
"editOptions": "Editar lista",
|
|
158
170
|
"clearOptions": "Limpar lista",
|
|
159
171
|
"addOption": "Adicionar opção",
|
|
@@ -1224,6 +1236,10 @@
|
|
|
1224
1236
|
"selectWhatsAppProfile": "Selecione um perfil de WhatsApp",
|
|
1225
1237
|
"selectStorageProfile": "Selecione um perfil de armazenamento",
|
|
1226
1238
|
"storageProfileEmptyState": "Nenhum perfil de armazenamento encontrado.",
|
|
1239
|
+
"selectAiProfile": "Selecione um perfil de IA",
|
|
1240
|
+
"aiProfileEmptyState": "Nenhum perfil de IA encontrado.",
|
|
1241
|
+
"selectOAuthProfile": "Selecione um perfil OAuth",
|
|
1242
|
+
"oauthProfileEmptyState": "Nenhum perfil OAuth encontrado.",
|
|
1227
1243
|
"mailProfile": {
|
|
1228
1244
|
"nameLabel": "Nome *",
|
|
1229
1245
|
"namePlaceholder": "Meu Perfil de Email",
|
|
@@ -2111,6 +2127,49 @@
|
|
|
2111
2127
|
"revokeSuccess": "Chave de API revogada",
|
|
2112
2128
|
"revokeFailure": "Falha ao revogar a chave de API"
|
|
2113
2129
|
},
|
|
2130
|
+
"Tokens": {
|
|
2131
|
+
"title": "Tokens de Acesso",
|
|
2132
|
+
"description": "Crie e gerencie tokens para acesso ao servidor MCP e à API REST",
|
|
2133
|
+
"createToken": "Criar Token",
|
|
2134
|
+
"createTokenTitle": "Criar Token",
|
|
2135
|
+
"createTokenDescription": "Escolha o tipo do token e dê um nome para identificá-lo depois",
|
|
2136
|
+
"tokenTypeLabel": "Tipo de Token",
|
|
2137
|
+
"typeMcp": "MCP",
|
|
2138
|
+
"typeApi": "API",
|
|
2139
|
+
"tokenNameLabel": "Nome do Token",
|
|
2140
|
+
"tokenNamePlaceholder": "ex.: Minha Aplicação",
|
|
2141
|
+
"tokenCreatedTitle": "Token Criado",
|
|
2142
|
+
"tokenCreatedWarning": "Este token é exibido apenas uma vez. Copie-o agora e guarde em local seguro.",
|
|
2143
|
+
"tokenCreatedLabel": "Seu novo token",
|
|
2144
|
+
"closeDialog": "Fechar",
|
|
2145
|
+
"mcpUrlLabel": "URL do Servidor MCP",
|
|
2146
|
+
"name": "Nome",
|
|
2147
|
+
"type": "Tipo",
|
|
2148
|
+
"tokenPrefix": "Prefixo do Token",
|
|
2149
|
+
"lastUsed": "Último Uso",
|
|
2150
|
+
"createdAt": "Criado Em",
|
|
2151
|
+
"never": "Nunca",
|
|
2152
|
+
"today": "Hoje",
|
|
2153
|
+
"daysAgo": "há {days} dias",
|
|
2154
|
+
"noTokens": "Nenhum token ainda. Crie um para começar.",
|
|
2155
|
+
"revokeTokenTitle": "Revogar Token",
|
|
2156
|
+
"revokeTokenDescription": "Este token deixará de funcionar imediatamente. Esta ação não pode ser desfeita.",
|
|
2157
|
+
"cancel": "Cancelar",
|
|
2158
|
+
"revokeConfirm": "Revogar",
|
|
2159
|
+
"closeSheet": "Concluir",
|
|
2160
|
+
"createFailure": "Falha ao criar o token",
|
|
2161
|
+
"revokeSuccess": "Token revogado",
|
|
2162
|
+
"revokeFailure": "Falha ao revogar o token",
|
|
2163
|
+
"usageTitle": "Instruções de Uso",
|
|
2164
|
+
"serverUrlLabel": "URL do Servidor",
|
|
2165
|
+
"yourToken": "seu-token",
|
|
2166
|
+
"mcpUsageDesc": "Configure seu cliente MCP com a URL do servidor abaixo e passe o token como header de autorização.",
|
|
2167
|
+
"mcpUsageHeader": "Adicione este header na configuração do seu cliente MCP:",
|
|
2168
|
+
"mcpUsageExampleLabel": "Exemplo (Claude Desktop / Cursor):",
|
|
2169
|
+
"apiUsageDesc": "Use este token para autenticar requisições à API REST passando-o como Bearer token no header Authorization.",
|
|
2170
|
+
"apiUsageHeader": "Adicione este header em cada requisição:",
|
|
2171
|
+
"apiUsageExampleLabel": "Exemplo (curl):"
|
|
2172
|
+
},
|
|
2114
2173
|
"McpFloatingChat": {
|
|
2115
2174
|
"title": "Chat MCP",
|
|
2116
2175
|
"openFullPage": "Abrir visão completa",
|
|
@@ -2335,6 +2394,11 @@
|
|
|
2335
2394
|
"fieldOrganization": "ID da Organização",
|
|
2336
2395
|
"fieldRedirectUri": "URI de Redirecionamento",
|
|
2337
2396
|
"fieldTenantId": "Tenant ID",
|
|
2397
|
+
"callbackUrlsSectionTitle": "URLs de Callback",
|
|
2398
|
+
"callbackUrlsDescription": "Registre estas URLs nas configurações do seu aplicativo OAuth.",
|
|
2399
|
+
"addCallbackUrl": "Adicionar URL",
|
|
2400
|
+
"noCallbackUrls": "Nenhuma URL de callback configurada.",
|
|
2401
|
+
"callbackUrlPlaceholder": "https://seudominio.com/callback/...",
|
|
2338
2402
|
"showPassword": "Mostrar valor",
|
|
2339
2403
|
"hidePassword": "Ocultar valor"
|
|
2340
2404
|
}
|
package/hedhog/table/file.yaml
CHANGED
|
@@ -12,6 +12,9 @@ columns:
|
|
|
12
12
|
enum:
|
|
13
13
|
- email
|
|
14
14
|
- whatsapp_evolution
|
|
15
|
+
- http_request
|
|
16
|
+
- internal_api
|
|
17
|
+
- app_command
|
|
15
18
|
- name: name
|
|
16
19
|
type: varchar
|
|
17
20
|
length: 127
|
|
@@ -25,7 +28,7 @@ columns:
|
|
|
25
28
|
- inactive
|
|
26
29
|
default: active
|
|
27
30
|
- type: fk
|
|
28
|
-
name:
|
|
31
|
+
name: integration_profile_id
|
|
29
32
|
isNullable: true
|
|
30
33
|
references:
|
|
31
34
|
table: integration_profile
|
|
@@ -73,6 +76,59 @@ columns:
|
|
|
73
76
|
- name: whatsapp_token
|
|
74
77
|
type: text
|
|
75
78
|
isNullable: true
|
|
79
|
+
- name: http_url
|
|
80
|
+
type: text
|
|
81
|
+
isNullable: true
|
|
82
|
+
- name: http_method
|
|
83
|
+
type: varchar
|
|
84
|
+
length: 16
|
|
85
|
+
isNullable: true
|
|
86
|
+
- name: http_headers
|
|
87
|
+
type: json
|
|
88
|
+
isNullable: true
|
|
89
|
+
- name: http_query
|
|
90
|
+
type: json
|
|
91
|
+
isNullable: true
|
|
92
|
+
- name: http_body
|
|
93
|
+
type: text
|
|
94
|
+
isNullable: true
|
|
95
|
+
- name: http_timeout_ms
|
|
96
|
+
type: int
|
|
97
|
+
isNullable: true
|
|
98
|
+
- name: http_retry_count
|
|
99
|
+
type: int
|
|
100
|
+
isNullable: true
|
|
101
|
+
- name: internal_api_path
|
|
102
|
+
type: text
|
|
103
|
+
isNullable: true
|
|
104
|
+
- name: internal_api_method
|
|
105
|
+
type: varchar
|
|
106
|
+
length: 16
|
|
107
|
+
isNullable: true
|
|
108
|
+
- name: internal_api_query
|
|
109
|
+
type: json
|
|
110
|
+
isNullable: true
|
|
111
|
+
- name: internal_api_body
|
|
112
|
+
type: json
|
|
113
|
+
isNullable: true
|
|
114
|
+
- name: internal_api_token
|
|
115
|
+
type: text
|
|
116
|
+
isNullable: true
|
|
117
|
+
- type: fk
|
|
118
|
+
name: internal_api_user_id
|
|
119
|
+
isNullable: true
|
|
120
|
+
references:
|
|
121
|
+
table: user
|
|
122
|
+
column: id
|
|
123
|
+
onDelete: set null
|
|
124
|
+
onUpdate: cascade
|
|
125
|
+
- name: app_command_slug
|
|
126
|
+
type: varchar
|
|
127
|
+
length: 127
|
|
128
|
+
isNullable: true
|
|
129
|
+
- name: app_command_params
|
|
130
|
+
type: json
|
|
131
|
+
isNullable: true
|
|
76
132
|
- type: created_at
|
|
77
133
|
- type: updated_at
|
|
78
134
|
indices:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.359",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -27,17 +27,18 @@
|
|
|
27
27
|
"playwright": "^1.49.0",
|
|
28
28
|
"png-to-ico": "^2.1.8",
|
|
29
29
|
"qrcode": "^1.5.4",
|
|
30
|
+
"redis": "4.7.1",
|
|
30
31
|
"rxjs": "^7.8.2",
|
|
31
32
|
"sharp": "^0.34.2",
|
|
32
33
|
"speakeasy": "^2.0.0",
|
|
33
34
|
"uuid": "^11.1.0",
|
|
34
35
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
35
36
|
"@hed-hog/api-locale": "0.0.14",
|
|
37
|
+
"@hed-hog/api-pagination": "0.0.7",
|
|
36
38
|
"@hed-hog/api-mail": "0.0.9",
|
|
39
|
+
"@hed-hog/api-prisma": "0.0.6",
|
|
37
40
|
"@hed-hog/api-types": "0.0.1",
|
|
38
|
-
"@hed-hog/api
|
|
39
|
-
"@hed-hog/api": "0.0.8",
|
|
40
|
-
"@hed-hog/api-prisma": "0.0.6"
|
|
41
|
+
"@hed-hog/api": "0.0.8"
|
|
41
42
|
},
|
|
42
43
|
"exports": {
|
|
43
44
|
".": {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IS_PUBLIC_KEY, WITH_NO_ROLE, WITH_ROLE } from '@hed-hog/api';
|
|
2
2
|
import { getLocaleText } from '@hed-hog/api-locale';
|
|
3
|
+
import { PrismaService } from '@hed-hog/api-prisma';
|
|
3
4
|
import {
|
|
4
5
|
CanActivate,
|
|
5
6
|
ExecutionContext,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
} from '@nestjs/common';
|
|
9
10
|
import { Reflector } from '@nestjs/core';
|
|
10
11
|
import { Request } from 'express';
|
|
12
|
+
import { SecurityService } from '../../security/security.service';
|
|
11
13
|
import { TokenService } from '../../token/token.service';
|
|
12
14
|
|
|
13
15
|
@Injectable()
|
|
@@ -15,6 +17,8 @@ export class AuthGuard implements CanActivate {
|
|
|
15
17
|
constructor(
|
|
16
18
|
private token: TokenService,
|
|
17
19
|
private reflector: Reflector,
|
|
20
|
+
private prisma: PrismaService,
|
|
21
|
+
private security: SecurityService,
|
|
18
22
|
) { }
|
|
19
23
|
|
|
20
24
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
@@ -37,6 +41,10 @@ export class AuthGuard implements CanActivate {
|
|
|
37
41
|
const token = this.extractTokenFromHeader(request);
|
|
38
42
|
const locale = request.headers['locale'] || request.headers['accept-language'] || 'en';
|
|
39
43
|
|
|
44
|
+
if (token?.startsWith('hedhog_api_')) {
|
|
45
|
+
return this.verifyApiKey(request, token, isPublic);
|
|
46
|
+
}
|
|
47
|
+
|
|
40
48
|
// If endpoint requires role/authentication and no token provided
|
|
41
49
|
if (!token) {
|
|
42
50
|
if (isPublic) {
|
|
@@ -76,6 +84,30 @@ export class AuthGuard implements CanActivate {
|
|
|
76
84
|
return true;
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
private async verifyApiKey(request: Request, token: string, isPublic: boolean): Promise<boolean> {
|
|
88
|
+
const hash = this.security.hashWithPepper(token);
|
|
89
|
+
const apiKey = await this.prisma.mcp_api_key.findFirst({
|
|
90
|
+
where: { token_hash: hash, type: 'api', revoked_at: null },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (!apiKey) {
|
|
94
|
+
if (isPublic) return true;
|
|
95
|
+
throw new UnauthorizedException('Invalid API key');
|
|
96
|
+
}
|
|
97
|
+
if (apiKey.expires_at && apiKey.expires_at <= new Date()) {
|
|
98
|
+
if (isPublic) return true;
|
|
99
|
+
throw new UnauthorizedException('API key expired');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.prisma.mcp_api_key.update({
|
|
103
|
+
where: { id: apiKey.id },
|
|
104
|
+
data: { last_used_at: new Date() },
|
|
105
|
+
}).catch(() => {});
|
|
106
|
+
|
|
107
|
+
request['auth'] = { sub: apiKey.user_id, sessionId: null };
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
79
111
|
private extractTokenFromHeader(request: Request): string | undefined {
|
|
80
112
|
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
|
81
113
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
forwardRef,
|
|
9
9
|
Get,
|
|
10
10
|
Inject,
|
|
11
|
+
Logger,
|
|
11
12
|
Param,
|
|
12
13
|
ParseIntPipe,
|
|
13
14
|
Post,
|
|
@@ -29,11 +30,50 @@ import { FileService } from './file.service';
|
|
|
29
30
|
@Role()
|
|
30
31
|
@Controller('file')
|
|
31
32
|
export class FileController {
|
|
33
|
+
private readonly logger = new Logger(FileController.name);
|
|
34
|
+
|
|
32
35
|
constructor(
|
|
33
36
|
@Inject(forwardRef(() => FileService))
|
|
34
37
|
private readonly fileService: FileService,
|
|
35
38
|
) {}
|
|
36
39
|
|
|
40
|
+
private renderDownloadErrorHtml(locale: string, error: any): string {
|
|
41
|
+
const errorTitle = getLocaleText('file.download.error_title', locale);
|
|
42
|
+
const errorMessage = getLocaleText('file.download.error_message', locale);
|
|
43
|
+
const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
|
|
44
|
+
const goBackText = getLocaleText('file.download.go_back', locale);
|
|
45
|
+
|
|
46
|
+
const templateData = {
|
|
47
|
+
locale: locale || 'en',
|
|
48
|
+
errorTitle,
|
|
49
|
+
errorMessage,
|
|
50
|
+
errorDetailsLabel,
|
|
51
|
+
errorDetails: error?.message || 'Unknown error occurred',
|
|
52
|
+
goBackText,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const templatePath = join(__dirname, 'templates', 'download-error.html');
|
|
57
|
+
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
58
|
+
const template = Handlebars.compile(templateSource);
|
|
59
|
+
return template(templateData);
|
|
60
|
+
} catch (templateError) {
|
|
61
|
+
this.logger.warn(
|
|
62
|
+
`Download error template missing or unreadable: ${templateError instanceof Error ? templateError.message : String(templateError)}`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const safe = {
|
|
66
|
+
errorTitle: Handlebars.escapeExpression(String(errorTitle)),
|
|
67
|
+
errorMessage: Handlebars.escapeExpression(String(errorMessage)),
|
|
68
|
+
errorDetailsLabel: Handlebars.escapeExpression(String(errorDetailsLabel)),
|
|
69
|
+
errorDetails: Handlebars.escapeExpression(String(templateData.errorDetails)),
|
|
70
|
+
goBackText: Handlebars.escapeExpression(String(goBackText)),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return `<!doctype html><html lang="${Handlebars.escapeExpression(locale || 'en')}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${safe.errorTitle}</title></head><body><h1>${safe.errorTitle}</h1><p>${safe.errorMessage}</p><p><strong>${safe.errorDetailsLabel}</strong> ${safe.errorDetails}</p><button type="button" onclick="history.back()">${safe.goBackText}</button></body></html>`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
37
77
|
@Get()
|
|
38
78
|
async list(@Pagination() paginationParams) {
|
|
39
79
|
return this.fileService.getFiles(paginationParams);
|
|
@@ -45,11 +85,16 @@ export class FileController {
|
|
|
45
85
|
}
|
|
46
86
|
|
|
47
87
|
@Put('open/:id')
|
|
48
|
-
async getTempOpenURL(
|
|
88
|
+
async getTempOpenURL(
|
|
89
|
+
@Param('id', ParseIntPipe) id: number,
|
|
90
|
+
@Req() req: Request,
|
|
91
|
+
) {
|
|
92
|
+
const file = await this.fileService.get(id);
|
|
93
|
+
const token = this.fileService.createDownloadToken(file.path, 3600);
|
|
94
|
+
const origin = `${req.protocol}://${req.get('host')}`;
|
|
95
|
+
|
|
49
96
|
return {
|
|
50
|
-
url:
|
|
51
|
-
(await this.fileService.get(id)).path,
|
|
52
|
-
),
|
|
97
|
+
url: `${origin}/file/open/${encodeURIComponent(token)}`,
|
|
53
98
|
};
|
|
54
99
|
}
|
|
55
100
|
|
|
@@ -96,27 +141,7 @@ export class FileController {
|
|
|
96
141
|
return;
|
|
97
142
|
|
|
98
143
|
} catch (error:any) {
|
|
99
|
-
|
|
100
|
-
const errorTitle = getLocaleText('file.download.error_title', locale);
|
|
101
|
-
const errorMessage = getLocaleText('file.download.error_message', locale);
|
|
102
|
-
const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
|
|
103
|
-
const goBackText = getLocaleText('file.download.go_back', locale);
|
|
104
|
-
|
|
105
|
-
// Ler e compilar template
|
|
106
|
-
const templatePath = join(__dirname, 'templates', 'download-error.html');
|
|
107
|
-
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
108
|
-
const template = Handlebars.compile(templateSource);
|
|
109
|
-
|
|
110
|
-
// Renderizar template com dados
|
|
111
|
-
const html = template({
|
|
112
|
-
locale: locale || 'en',
|
|
113
|
-
errorTitle,
|
|
114
|
-
errorMessage,
|
|
115
|
-
errorDetailsLabel,
|
|
116
|
-
errorDetails: error?.message || 'Unknown error occurred',
|
|
117
|
-
goBackText,
|
|
118
|
-
});
|
|
119
|
-
|
|
144
|
+
const html = this.renderDownloadErrorHtml(locale, error);
|
|
120
145
|
res.status(400).set('Content-Type', 'text/html').send(html);
|
|
121
146
|
return;
|
|
122
147
|
}
|
|
@@ -176,23 +201,7 @@ export class FileController {
|
|
|
176
201
|
return;
|
|
177
202
|
|
|
178
203
|
} catch (error:any) {
|
|
179
|
-
const
|
|
180
|
-
const errorMessage = getLocaleText('file.download.error_message', locale);
|
|
181
|
-
const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
|
|
182
|
-
const goBackText = getLocaleText('file.download.go_back', locale);
|
|
183
|
-
|
|
184
|
-
const templatePath = join(__dirname, 'templates', 'download-error.html');
|
|
185
|
-
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
186
|
-
const template = Handlebars.compile(templateSource);
|
|
187
|
-
|
|
188
|
-
const html = template({
|
|
189
|
-
locale: locale || 'en',
|
|
190
|
-
errorTitle,
|
|
191
|
-
errorMessage,
|
|
192
|
-
errorDetailsLabel,
|
|
193
|
-
errorDetails: error?.message || 'Unknown error occurred',
|
|
194
|
-
goBackText,
|
|
195
|
-
});
|
|
204
|
+
const html = this.renderDownloadErrorHtml(locale, error);
|
|
196
205
|
|
|
197
206
|
res.status(400).set('Content-Type', 'text/html').send(html);
|
|
198
207
|
return;
|