@hed-hog/core 0.0.349 → 0.0.351
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/access-log/access-log.controller.d.ts +16 -0
- package/dist/access-log/access-log.controller.d.ts.map +1 -0
- package/dist/access-log/access-log.controller.js +44 -0
- package/dist/access-log/access-log.controller.js.map +1 -0
- package/dist/access-log/access-log.interceptor.d.ts +9 -0
- package/dist/access-log/access-log.interceptor.d.ts.map +1 -0
- package/dist/access-log/access-log.interceptor.js +46 -0
- package/dist/access-log/access-log.interceptor.js.map +1 -0
- package/dist/access-log/access-log.module.d.ts +3 -0
- package/dist/access-log/access-log.module.d.ts.map +1 -0
- package/dist/access-log/access-log.module.js +29 -0
- package/dist/access-log/access-log.module.js.map +1 -0
- package/dist/access-log/access-log.service.d.ts +47 -0
- package/dist/access-log/access-log.service.d.ts.map +1 -0
- package/dist/access-log/access-log.service.js +113 -0
- package/dist/access-log/access-log.service.js.map +1 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts +8 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts.map +1 -0
- package/dist/access-log/dto/query-access-log.dto.js +42 -0
- package/dist/access-log/dto/query-access-log.dto.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +12 -12
- package/dist/auth/auth.service.d.ts +27 -27
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +0 -4
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +0 -1
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/core/system.module.d.ts.map +1 -1
- package/dist/core/system.module.js +1 -0
- package/dist/core/system.module.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +15 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
- package/dist/dashboard/dashboard.module.d.ts.map +1 -1
- package/dist/dashboard/dashboard.module.js +4 -1
- package/dist/dashboard/dashboard.module.js.map +1 -1
- package/dist/file/file.controller.js +0 -1
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +65 -0
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +151 -3
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/abstract.provider.d.ts +8 -0
- package/dist/file/provider/abstract.provider.d.ts.map +1 -1
- package/dist/file/provider/abstract.provider.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts +4 -0
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +14 -0
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts +4 -0
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +14 -0
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts +4 -0
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +19 -0
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +3 -0
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts +4 -0
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +17 -0
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts +6 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +29 -2
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +32 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -0
- package/dist/mcp/mcp-api-key.controller.js +64 -0
- package/dist/mcp/mcp-api-key.controller.js.map +1 -0
- package/dist/mcp/mcp-api-key.service.d.ts +27 -0
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -0
- package/dist/mcp/mcp-api-key.service.js +74 -0
- package/dist/mcp/mcp-api-key.service.js.map +1 -0
- package/dist/mcp/mcp-audit.service.d.ts +3 -1
- package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
- package/dist/mcp/mcp-audit.service.js +14 -2
- package/dist/mcp/mcp-audit.service.js.map +1 -1
- package/dist/mcp/mcp-registry.service.d.ts +1 -2
- package/dist/mcp/mcp-registry.service.d.ts.map +1 -1
- package/dist/mcp/mcp-registry.service.js +6 -2
- package/dist/mcp/mcp-registry.service.js.map +1 -1
- package/dist/mcp/mcp.controller.d.ts +3 -1
- package/dist/mcp/mcp.controller.d.ts.map +1 -1
- package/dist/mcp/mcp.controller.js +10 -2
- package/dist/mcp/mcp.controller.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +80 -1
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp/tools/core-ai.mcp-tools.d.ts +45 -0
- package/dist/mcp/tools/core-ai.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js +214 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts +21 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +89 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts +29 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.js +149 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts +30 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +185 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-files.mcp-tools.d.ts +26 -0
- package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-files.mcp-tools.js +140 -0
- package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts +26 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.js +168 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +32 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +178 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts +14 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js +106 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail.mcp-tools.d.ts +36 -0
- package/dist/mcp/tools/core-mail.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail.mcp-tools.js +184 -0
- package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts +21 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.js +118 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts +40 -0
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-menus.mcp-tools.js +268 -0
- package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts +31 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.js +178 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-profile.mcp-tools.d.ts +20 -0
- package/dist/mcp/tools/core-profile.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-profile.mcp-tools.js +111 -0
- package/dist/mcp/tools/core-profile.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts +70 -0
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-roles.mcp-tools.js +355 -0
- package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts +52 -0
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-routes.mcp-tools.js +254 -0
- package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts +47 -0
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-screens.mcp-tools.js +250 -0
- package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts +20 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.js +128 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts +25 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.js +138 -0
- package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-system.mcp-tools.d.ts +8 -0
- package/dist/mcp/tools/core-system.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-system.mcp-tools.js +40 -0
- package/dist/mcp/tools/core-system.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts +46 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.js +266 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts +5 -1
- package/dist/mcp-chat/mcp-chat.controller.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.controller.js +46 -0
- package/dist/mcp-chat/mcp-chat.controller.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts +31 -3
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +776 -38
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/notification/dto/create-notification.dto.d.ts +26 -0
- package/dist/notification/dto/create-notification.dto.d.ts.map +1 -0
- package/dist/notification/dto/create-notification.dto.js +86 -0
- package/dist/notification/dto/create-notification.dto.js.map +1 -0
- package/dist/notification/dto/update-progress.dto.d.ts +6 -0
- package/dist/notification/dto/update-progress.dto.d.ts.map +1 -0
- package/dist/notification/dto/update-progress.dto.js +33 -0
- package/dist/notification/dto/update-progress.dto.js.map +1 -0
- package/dist/notification/notification.controller.d.ts +112 -0
- package/dist/notification/notification.controller.d.ts.map +1 -0
- package/dist/notification/notification.controller.js +130 -0
- package/dist/notification/notification.controller.js.map +1 -0
- package/dist/notification/notification.module.d.ts +3 -0
- package/dist/notification/notification.module.d.ts.map +1 -0
- package/dist/notification/notification.module.js +29 -0
- package/dist/notification/notification.module.js.map +1 -0
- package/dist/notification/notification.service.d.ts +112 -0
- package/dist/notification/notification.service.d.ts.map +1 -0
- package/dist/notification/notification.service.js +269 -0
- package/dist/notification/notification.service.js.map +1 -0
- package/dist/pdf/pdf.service.js +1 -1
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +4 -4
- package/dist/profile/profile.controller.js +0 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/profile/profile.module.d.ts.map +1 -1
- package/dist/profile/profile.module.js +1 -0
- package/dist/profile/profile.module.js.map +1 -1
- package/dist/profile/profile.service.d.ts +4 -4
- package/dist/session/session.controller.d.ts +3 -3
- package/dist/session/session.service.d.ts +9 -9
- package/dist/setting/dto/update-setting-list.dto.d.ts +9 -0
- package/dist/setting/dto/update-setting-list.dto.d.ts.map +1 -0
- package/dist/setting/dto/update-setting-list.dto.js +44 -0
- package/dist/setting/dto/update-setting-list.dto.js.map +1 -0
- package/dist/setting/setting.controller.d.ts +20 -1
- package/dist/setting/setting.controller.d.ts.map +1 -1
- package/dist/setting/setting.controller.js +12 -0
- package/dist/setting/setting.controller.js.map +1 -1
- package/dist/setting/setting.service.d.ts +20 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +80 -4
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +13 -0
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +85 -0
- package/dist/task/task.service.js.map +1 -1
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +0 -1
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +11 -11
- package/dist/user/user.service.d.ts +27 -27
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +22 -0
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -0
- package/dist/webhook-integration/dto/webhook-action.dto.js +120 -0
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +7 -5
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +18 -5
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +18 -5
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +342 -59
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/dist/webhook-integration/webhook-utils.d.ts +1 -0
- package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-utils.js +38 -0
- package/dist/webhook-integration/webhook-utils.js.map +1 -1
- package/hedhog/data/menu.yaml +63 -4
- package/hedhog/data/route.yaml +1437 -0
- package/hedhog/data/setting_group.yaml +112 -0
- package/hedhog/data/setting_subgroup.yaml +32 -0
- package/hedhog/frontend/app/access-log/page.tsx.ejs +772 -0
- package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +285 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +32 -55
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +10 -3
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +33 -13
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +12 -5
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +12 -5
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +3559 -1835
- package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +633 -0
- package/hedhog/frontend/app/mcp_chat/chat-types.ts.ejs +16 -0
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +583 -384
- package/hedhog/frontend/app/menu/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/roles/page.tsx.ejs +18 -6
- package/hedhog/frontend/app/routes/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +822 -0
- package/hedhog/frontend/app/users/page.tsx.ejs +445 -203
- package/hedhog/frontend/app/users/user-access-sheet.tsx.ejs +310 -304
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +41 -44
- package/hedhog/frontend/messages/en.json +343 -3
- package/hedhog/frontend/messages/pt.json +343 -3
- package/hedhog/table/access_log.yaml +31 -0
- package/hedhog/table/mcp_api_key.yaml +30 -0
- package/hedhog/table/notification.yaml +72 -0
- package/hedhog/table/webhook_action_log.yaml +49 -0
- package/package.json +5 -4
- package/src/access-log/access-log.controller.ts +29 -0
- package/src/access-log/access-log.interceptor.ts +38 -0
- package/src/access-log/access-log.module.ts +16 -0
- package/src/access-log/access-log.service.ts +129 -0
- package/src/access-log/dto/query-access-log.dto.ts +23 -0
- package/src/auth/auth.service.ts +0 -7
- package/src/challenge/challenge.service.ts +0 -2
- package/src/core/system.module.ts +1 -0
- package/src/core.module.ts +15 -0
- package/src/dashboard/dashboard.module.ts +4 -1
- package/src/file/file.controller.ts +14 -14
- package/src/file/file.service.ts +198 -4
- package/src/file/provider/abstract.provider.ts +10 -0
- package/src/file/provider/azure.provider.ts +24 -0
- package/src/file/provider/gcs.provider.ts +20 -0
- package/src/file/provider/local.provider.ts +30 -2
- package/src/file/provider/provider.factory.ts +3 -0
- package/src/file/provider/s3.provider.ts +22 -0
- package/src/index.ts +5 -0
- package/src/mcp/guards/mcp-auth.guard.ts +64 -32
- package/src/mcp/mcp-api-key.controller.ts +42 -0
- package/src/mcp/mcp-api-key.service.ts +66 -0
- package/src/mcp/mcp-audit.service.ts +47 -36
- package/src/mcp/mcp-registry.service.ts +75 -69
- package/src/mcp/mcp.controller.ts +40 -30
- package/src/mcp/mcp.module.ts +115 -36
- package/src/mcp/tools/core-ai.mcp-tools.ts +156 -0
- package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +63 -0
- package/src/mcp/tools/core-dashboard.mcp-tools.ts +103 -0
- package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +134 -0
- package/src/mcp/tools/core-files.mcp-tools.ts +105 -0
- package/src/mcp/tools/core-integration-events.mcp-tools.ts +118 -0
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +128 -0
- package/src/mcp/tools/core-mail-sent.mcp-tools.ts +76 -0
- package/src/mcp/tools/core-mail.mcp-tools.ts +130 -0
- package/src/mcp/tools/core-mcp-chat.mcp-tools.ts +81 -0
- package/src/mcp/tools/core-menus.mcp-tools.ts +197 -0
- package/src/mcp/tools/core-notifications.mcp-tools.ts +128 -0
- package/src/mcp/tools/core-profile.mcp-tools.ts +74 -0
- package/src/mcp/tools/core-roles.mcp-tools.ts +288 -0
- package/src/mcp/tools/core-routes.mcp-tools.ts +196 -0
- package/src/mcp/tools/core-screens.mcp-tools.ts +186 -0
- package/src/mcp/tools/core-sessions.mcp-tools.ts +97 -0
- package/src/mcp/tools/core-settings.mcp-tools.ts +171 -53
- package/src/mcp/tools/core-system.mcp-tools.ts +19 -0
- package/src/mcp/tools/core-webhooks.mcp-tools.ts +199 -0
- package/src/mcp-chat/mcp-chat.controller.ts +113 -60
- package/src/mcp-chat/mcp-chat.service.ts +1343 -332
- package/src/notification/dto/create-notification.dto.ts +71 -0
- package/src/notification/dto/update-progress.dto.ts +16 -0
- package/src/notification/notification.controller.ts +83 -0
- package/src/notification/notification.module.ts +16 -0
- package/src/notification/notification.service.ts +324 -0
- package/src/pdf/pdf.service.ts +1 -1
- package/src/profile/profile.controller.ts +1 -1
- package/src/profile/profile.module.ts +1 -0
- package/src/setting/dto/update-setting-list.dto.ts +32 -0
- package/src/setting/setting.controller.ts +9 -0
- package/src/setting/setting.service.ts +99 -11
- package/src/task/task.service.ts +103 -0
- package/src/token/token.service.ts +0 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +96 -0
- package/src/webhook-integration/webhook-integration.controller.ts +124 -103
- package/src/webhook-integration/webhook-integration.service.ts +1137 -735
- package/src/webhook-integration/webhook-utils.ts +136 -79
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PaginationModule } from '@hed-hog/api-pagination';
|
|
2
|
+
import { PrismaModule } from '@hed-hog/api-prisma';
|
|
3
|
+
import { forwardRef, Module } from '@nestjs/common';
|
|
4
|
+
import { AccessLogController } from './access-log.controller';
|
|
5
|
+
import { AccessLogService } from './access-log.service';
|
|
6
|
+
|
|
7
|
+
@Module({
|
|
8
|
+
imports: [
|
|
9
|
+
forwardRef(() => PrismaModule),
|
|
10
|
+
forwardRef(() => PaginationModule),
|
|
11
|
+
],
|
|
12
|
+
controllers: [AccessLogController],
|
|
13
|
+
providers: [AccessLogService],
|
|
14
|
+
exports: [AccessLogService],
|
|
15
|
+
})
|
|
16
|
+
export class AccessLogModule {}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { PageOrderDirection, PaginationService } from '@hed-hog/api-pagination';
|
|
2
|
+
import { Prisma, PrismaService } from '@hed-hog/api-prisma';
|
|
3
|
+
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
|
|
4
|
+
|
|
5
|
+
interface RecordHttpData {
|
|
6
|
+
userId?: number;
|
|
7
|
+
ip?: string;
|
|
8
|
+
userAgent?: string;
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface RecordMcpData {
|
|
14
|
+
userId?: number;
|
|
15
|
+
mcpTool: string;
|
|
16
|
+
mcpPrompt?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type AccessLogListParams = {
|
|
20
|
+
page?: number;
|
|
21
|
+
pageSize?: number;
|
|
22
|
+
search?: string;
|
|
23
|
+
sortField?: string;
|
|
24
|
+
sortOrder?: PageOrderDirection;
|
|
25
|
+
fields?: string;
|
|
26
|
+
userId?: number;
|
|
27
|
+
userSearch?: string;
|
|
28
|
+
createdAtFrom?: string;
|
|
29
|
+
createdAtTo?: string;
|
|
30
|
+
type?: 'http' | 'mcp' | 'all';
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
@Injectable()
|
|
34
|
+
export class AccessLogService {
|
|
35
|
+
private readonly logger = new Logger(AccessLogService.name);
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
@Inject(forwardRef(() => PrismaService))
|
|
39
|
+
private readonly prisma: PrismaService,
|
|
40
|
+
@Inject(forwardRef(() => PaginationService))
|
|
41
|
+
private readonly pagination: PaginationService,
|
|
42
|
+
) {}
|
|
43
|
+
|
|
44
|
+
recordHttp(data: RecordHttpData): void {
|
|
45
|
+
this.prisma.access_log
|
|
46
|
+
.create({
|
|
47
|
+
data: {
|
|
48
|
+
user_id: data.userId ?? null,
|
|
49
|
+
ip: data.ip ?? null,
|
|
50
|
+
user_agent: data.userAgent ?? null,
|
|
51
|
+
method: data.method,
|
|
52
|
+
path: data.path,
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
.catch((e) => this.logger.warn(`Failed to persist HTTP access log: ${e.message}`));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
recordMcp(data: RecordMcpData): void {
|
|
59
|
+
this.prisma.access_log
|
|
60
|
+
.create({
|
|
61
|
+
data: {
|
|
62
|
+
user_id: data.userId ?? null,
|
|
63
|
+
mcp_tool: data.mcpTool,
|
|
64
|
+
mcp_prompt: data.mcpPrompt ?? null,
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
.catch((e) => this.logger.warn(`Failed to persist MCP access log: ${e.message}`));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async list(params: AccessLogListParams) {
|
|
71
|
+
const where: Prisma.access_logWhereInput = {};
|
|
72
|
+
|
|
73
|
+
if (params.userId) {
|
|
74
|
+
where.user_id = params.userId;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (params.userSearch) {
|
|
78
|
+
where.user = {
|
|
79
|
+
OR: [
|
|
80
|
+
{ name: { contains: params.userSearch, mode: 'insensitive' } },
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (params.createdAtFrom || params.createdAtTo) {
|
|
86
|
+
where.created_at = {};
|
|
87
|
+
if (params.createdAtFrom) {
|
|
88
|
+
where.created_at.gte = new Date(params.createdAtFrom);
|
|
89
|
+
}
|
|
90
|
+
if (params.createdAtTo) {
|
|
91
|
+
const to = new Date(params.createdAtTo);
|
|
92
|
+
to.setHours(23, 59, 59, 999);
|
|
93
|
+
where.created_at.lte = to;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (params.type === 'http') {
|
|
98
|
+
where.method = { not: null };
|
|
99
|
+
} else if (params.type === 'mcp') {
|
|
100
|
+
where.mcp_tool = { not: null };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return this.pagination.paginate(this.prisma.access_log, {
|
|
104
|
+
...params,
|
|
105
|
+
fields: params.fields ?? '',
|
|
106
|
+
}, {
|
|
107
|
+
where,
|
|
108
|
+
orderBy: { created_at: 'desc' },
|
|
109
|
+
include: {
|
|
110
|
+
user: { select: { id: true, name: true, photo_id: true } },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async clearOld(retentionDays: number, batchLimit: number): Promise<void> {
|
|
116
|
+
await this.prisma.$executeRaw`
|
|
117
|
+
WITH del AS (
|
|
118
|
+
SELECT id
|
|
119
|
+
FROM access_log
|
|
120
|
+
WHERE created_at < (now() - ${Prisma.sql`INTERVAL '${Prisma.raw(String(retentionDays))} days'`})
|
|
121
|
+
ORDER BY id
|
|
122
|
+
LIMIT ${batchLimit}
|
|
123
|
+
)
|
|
124
|
+
DELETE FROM access_log al
|
|
125
|
+
USING del
|
|
126
|
+
WHERE al.id = del.id
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IsIn, IsNumberString, IsOptional, IsString } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
export class QueryAccessLogDto {
|
|
4
|
+
@IsOptional()
|
|
5
|
+
@IsNumberString()
|
|
6
|
+
userId?: string;
|
|
7
|
+
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsString()
|
|
10
|
+
userSearch?: string;
|
|
11
|
+
|
|
12
|
+
@IsOptional()
|
|
13
|
+
@IsString()
|
|
14
|
+
createdAtFrom?: string;
|
|
15
|
+
|
|
16
|
+
@IsOptional()
|
|
17
|
+
@IsString()
|
|
18
|
+
createdAtTo?: string;
|
|
19
|
+
|
|
20
|
+
@IsOptional()
|
|
21
|
+
@IsIn(['http', 'mcp', 'all'])
|
|
22
|
+
type?: 'http' | 'mcp' | 'all';
|
|
23
|
+
}
|
package/src/auth/auth.service.ts
CHANGED
|
@@ -82,8 +82,6 @@ export class AuthService {
|
|
|
82
82
|
|
|
83
83
|
async requiresMfaForLogin(locale: string, email: string, user: any) {
|
|
84
84
|
|
|
85
|
-
console.log('MFA required, setting up email MFA');
|
|
86
|
-
|
|
87
85
|
const settings = await this.setting.getSettingValues([
|
|
88
86
|
'require-mfa',
|
|
89
87
|
'require-email-verification',
|
|
@@ -387,16 +385,11 @@ export class AuthService {
|
|
|
387
385
|
|
|
388
386
|
if (!user) throw new BadRequestException(getLocaleText('accessDenied', locale, 'Access denied.'));
|
|
389
387
|
|
|
390
|
-
console.debug({ user });
|
|
391
|
-
|
|
392
388
|
const credentials = (user as unknown as User).user_credential?.filter((c) => c.type === 'password') || [];
|
|
393
389
|
|
|
394
|
-
console.debug({ credentials });
|
|
395
|
-
|
|
396
390
|
const identifier = user.user_identifier?.find((i) => i.type === 'email' && i.value === email);
|
|
397
391
|
|
|
398
392
|
if (!(await this.security.validatePassword(locale, credentials, password))) {
|
|
399
|
-
console.debug('Invalid password');
|
|
400
393
|
throw new BadRequestException(getLocaleText('accessDenied', locale, 'Access denied.'));
|
|
401
394
|
}
|
|
402
395
|
|
|
@@ -376,8 +376,6 @@ export class ChallengeService {
|
|
|
376
376
|
|
|
377
377
|
async sendMfaCodeToMultipleEmails(locale: string, userId: number, emails: string[]) {
|
|
378
378
|
|
|
379
|
-
console.log('Sending MFA codes to multiple emails:', emails);
|
|
380
|
-
|
|
381
379
|
if (!emails || emails.length === 0) {
|
|
382
380
|
return { success: true };
|
|
383
381
|
}
|
package/src/core.module.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { LogInterceptor } from '@hed-hog/api';
|
|
2
2
|
import { LocaleModule } from '@hed-hog/api-locale';
|
|
3
|
+
import { AccessLogInterceptor } from './access-log/access-log.interceptor';
|
|
4
|
+
import { AccessLogModule } from './access-log/access-log.module';
|
|
5
|
+
import { AccessLogService } from './access-log/access-log.service';
|
|
3
6
|
import { MailModule as MailSendModule } from '@hed-hog/api-mail';
|
|
4
7
|
import { PaginationModule } from '@hed-hog/api-pagination';
|
|
5
8
|
import { PrismaModule, PrismaService } from '@hed-hog/api-prisma';
|
|
@@ -37,6 +40,7 @@ import { IsEmailWithSettingsConstraint } from './validators/is-email-with-settin
|
|
|
37
40
|
import { IsPinCodeWithSettingConstraint } from './validators/is-pin-code-with-setting.validator';
|
|
38
41
|
import { IsStrongPasswordWithSettingsConstraint } from './validators/is-strong-password-with-settings.validator';
|
|
39
42
|
import { ValidatorServiceLocator } from './validators/service-locator';
|
|
43
|
+
import { NotificationModule } from './notification/notification.module';
|
|
40
44
|
import { WebhookIntegrationModule } from './webhook-integration/webhook-integration.module';
|
|
41
45
|
|
|
42
46
|
@Global()
|
|
@@ -73,6 +77,8 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
73
77
|
forwardRef(() => McpModule),
|
|
74
78
|
forwardRef(() => McpChatModule),
|
|
75
79
|
forwardRef(() => PdfModule),
|
|
80
|
+
forwardRef(() => NotificationModule),
|
|
81
|
+
forwardRef(() => AccessLogModule),
|
|
76
82
|
],
|
|
77
83
|
exports: [
|
|
78
84
|
UserModule,
|
|
@@ -94,6 +100,8 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
94
100
|
IsEmailWithSettingsConstraint,
|
|
95
101
|
IsPinCodeWithSettingConstraint,
|
|
96
102
|
PdfModule,
|
|
103
|
+
NotificationModule,
|
|
104
|
+
AccessLogModule,
|
|
97
105
|
],
|
|
98
106
|
providers: [
|
|
99
107
|
Reflector,
|
|
@@ -107,6 +115,13 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
107
115
|
},
|
|
108
116
|
inject: [Reflector, PrismaService],
|
|
109
117
|
},
|
|
118
|
+
{
|
|
119
|
+
provide: APP_INTERCEPTOR,
|
|
120
|
+
useFactory: (accessLogService: AccessLogService) => {
|
|
121
|
+
return new AccessLogInterceptor(accessLogService);
|
|
122
|
+
},
|
|
123
|
+
inject: [AccessLogService],
|
|
124
|
+
},
|
|
110
125
|
]
|
|
111
126
|
})
|
|
112
127
|
export class CoreModule implements NestModule, OnModuleInit {
|
|
@@ -23,6 +23,9 @@ import { DashboardCrudModule } from './dashboard/dashboard.module';
|
|
|
23
23
|
],
|
|
24
24
|
controllers: [],
|
|
25
25
|
providers: [],
|
|
26
|
-
exports: [
|
|
26
|
+
exports: [
|
|
27
|
+
forwardRef(() => DashboardCrudModule),
|
|
28
|
+
forwardRef(() => DashboardItemModule),
|
|
29
|
+
],
|
|
27
30
|
})
|
|
28
31
|
export class DashboardModule {}
|
|
@@ -2,19 +2,19 @@ import { Public, Role } from '@hed-hog/api';
|
|
|
2
2
|
import { getLocaleText, Locale } from '@hed-hog/api-locale';
|
|
3
3
|
import { Pagination } from '@hed-hog/api-pagination';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
Body,
|
|
6
|
+
Controller,
|
|
7
|
+
Delete,
|
|
8
|
+
forwardRef,
|
|
9
|
+
Get,
|
|
10
|
+
Inject,
|
|
11
|
+
Param,
|
|
12
|
+
ParseIntPipe,
|
|
13
|
+
Post,
|
|
14
|
+
Put,
|
|
15
|
+
Res,
|
|
16
|
+
UploadedFile,
|
|
17
|
+
UseInterceptors,
|
|
18
18
|
} from '@nestjs/common';
|
|
19
19
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
20
20
|
import { Response } from 'express';
|
|
@@ -54,7 +54,7 @@ export class FileController {
|
|
|
54
54
|
|
|
55
55
|
@Put('download/:id')
|
|
56
56
|
async getTempURL(@Param('id', ParseIntPipe) id) {
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
return {
|
|
59
59
|
url: await this.fileService.tempURL(
|
|
60
60
|
(await this.fileService.get(id)).path,
|
package/src/file/file.service.ts
CHANGED
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
OnModuleInit
|
|
11
11
|
} from '@nestjs/common';
|
|
12
12
|
import { JwtService } from '@nestjs/jwt';
|
|
13
|
+
import { createWriteStream, promises as fs } from 'fs';
|
|
14
|
+
import { basename, dirname } from 'path';
|
|
15
|
+
import { pipeline } from 'stream/promises';
|
|
13
16
|
import { SettingService } from '../setting/setting.service';
|
|
14
17
|
import { DeleteDTO } from './dto/delete.dto';
|
|
15
18
|
import { AbstractProvider } from './provider/abstract.provider';
|
|
@@ -235,6 +238,113 @@ export class FileService implements OnModuleInit {
|
|
|
235
238
|
return settings['storage'];
|
|
236
239
|
}
|
|
237
240
|
|
|
241
|
+
private getProviderPath(storage: string, filepath: string) {
|
|
242
|
+
if (storage === EnumProvider.LOCAL) {
|
|
243
|
+
return filepath;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
return new URL(filepath).pathname;
|
|
248
|
+
} catch {
|
|
249
|
+
return filepath;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private mapStorageNotFoundError(error: any, fileId: number) {
|
|
254
|
+
const missingInStorage =
|
|
255
|
+
error?.name === 'NoSuchKey' ||
|
|
256
|
+
error?.Code === 'NoSuchKey' ||
|
|
257
|
+
error?.$metadata?.httpStatusCode === 404;
|
|
258
|
+
|
|
259
|
+
if (missingInStorage) {
|
|
260
|
+
throw new NotFoundException(`File not found in storage: ${fileId}`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async openReadStreamById(fileId: number) {
|
|
267
|
+
if (!fileId) {
|
|
268
|
+
throw new BadRequestException(`No file ID provided`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const file = await this.prismaService.file.findUnique({
|
|
272
|
+
where: {
|
|
273
|
+
id: fileId,
|
|
274
|
+
},
|
|
275
|
+
include: {
|
|
276
|
+
file_mimetype: true,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
if (!file) {
|
|
281
|
+
throw new NotFoundException(`File not found: ${fileId}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const storage = await this.getStorage();
|
|
285
|
+
const provider = await this.getProvider();
|
|
286
|
+
const providerPath = this.getProviderPath(storage, file.path);
|
|
287
|
+
|
|
288
|
+
let metadata: any;
|
|
289
|
+
try {
|
|
290
|
+
metadata = await provider.metaData(providerPath);
|
|
291
|
+
} catch {
|
|
292
|
+
metadata = undefined;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
const stream = await provider.readStream(providerPath);
|
|
297
|
+
return {
|
|
298
|
+
file,
|
|
299
|
+
stream,
|
|
300
|
+
size: file.size ?? this.getFileSizeFromMetadata(metadata),
|
|
301
|
+
};
|
|
302
|
+
} catch (error) {
|
|
303
|
+
this.mapStorageNotFoundError(error, fileId);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async downloadToPath(
|
|
308
|
+
fileId: number,
|
|
309
|
+
destinationPath: string,
|
|
310
|
+
options?: { maxBytes?: number },
|
|
311
|
+
) {
|
|
312
|
+
if (!destinationPath) {
|
|
313
|
+
throw new BadRequestException(`No destination path provided`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const { file, stream, size } = await this.openReadStreamById(fileId);
|
|
317
|
+
|
|
318
|
+
if (options?.maxBytes && size && size > options.maxBytes) {
|
|
319
|
+
throw new BadRequestException(
|
|
320
|
+
`File too large for streaming download: ${size} bytes (max ${options.maxBytes})`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
await fs.mkdir(dirname(destinationPath), { recursive: true });
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
await pipeline(stream, createWriteStream(destinationPath));
|
|
328
|
+
const stats = await fs.stat(destinationPath);
|
|
329
|
+
|
|
330
|
+
if (options?.maxBytes && stats.size > options.maxBytes) {
|
|
331
|
+
await fs.unlink(destinationPath).catch(() => undefined);
|
|
332
|
+
throw new BadRequestException(
|
|
333
|
+
`File too large for streaming download: ${stats.size} bytes (max ${options.maxBytes})`,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
file,
|
|
339
|
+
path: destinationPath,
|
|
340
|
+
size: stats.size,
|
|
341
|
+
};
|
|
342
|
+
} catch (error) {
|
|
343
|
+
await fs.unlink(destinationPath).catch(() => undefined);
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
238
348
|
async getBuffer(fileId: number) {
|
|
239
349
|
|
|
240
350
|
if (!fileId) {
|
|
@@ -258,8 +368,7 @@ export class FileService implements OnModuleInit {
|
|
|
258
368
|
|
|
259
369
|
const provider = await this.getProvider();
|
|
260
370
|
|
|
261
|
-
const providerPath =
|
|
262
|
-
storage === EnumProvider.LOCAL ? file.path : new URL(file.path).pathname;
|
|
371
|
+
const providerPath = this.getProviderPath(storage, file.path);
|
|
263
372
|
|
|
264
373
|
let providerBuffer: Buffer;
|
|
265
374
|
try {
|
|
@@ -341,6 +450,89 @@ export class FileService implements OnModuleInit {
|
|
|
341
450
|
return file;
|
|
342
451
|
}
|
|
343
452
|
|
|
453
|
+
async uploadFromPath(
|
|
454
|
+
destination: string,
|
|
455
|
+
filePath: string,
|
|
456
|
+
metadata?: {
|
|
457
|
+
originalname?: string;
|
|
458
|
+
filename?: string;
|
|
459
|
+
mimetype?: string;
|
|
460
|
+
size?: number;
|
|
461
|
+
encoding?: string;
|
|
462
|
+
},
|
|
463
|
+
) {
|
|
464
|
+
if (!filePath) {
|
|
465
|
+
throw new BadRequestException(`No file path provided`);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (!destination) {
|
|
469
|
+
throw new BadRequestException(`No destination provided`);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const stats = await fs.stat(filePath).catch(() => null);
|
|
473
|
+
if (!stats || !stats.isFile()) {
|
|
474
|
+
throw new NotFoundException(`File path not found: ${filePath}`);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const size = metadata?.size ?? stats.size;
|
|
478
|
+
const mimetype = metadata?.mimetype ?? 'application/octet-stream';
|
|
479
|
+
const originalname = this.normalizeUploadedFilename(
|
|
480
|
+
metadata?.originalname ?? metadata?.filename ?? basename(filePath),
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
if (!(await this.acceptMimetypes(mimetype))) {
|
|
484
|
+
throw new BadRequestException(`Invalid file type: ${mimetype}`);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (!(await this.maxFileSize(size))) {
|
|
488
|
+
throw new BadRequestException(`File too large: ${size} bytes`);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const provider = await this.getProvider();
|
|
492
|
+
const providerWithPathUpload = provider as AbstractProvider & {
|
|
493
|
+
uploadFromPath?: (
|
|
494
|
+
destination: string,
|
|
495
|
+
filePath: string,
|
|
496
|
+
options?: { filename?: string; mimetype?: string },
|
|
497
|
+
) => Promise<string>;
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
let url: string;
|
|
501
|
+
if (typeof providerWithPathUpload.uploadFromPath === 'function') {
|
|
502
|
+
url = await providerWithPathUpload.uploadFromPath(destination, filePath, {
|
|
503
|
+
filename: originalname,
|
|
504
|
+
mimetype,
|
|
505
|
+
});
|
|
506
|
+
} else {
|
|
507
|
+
// Fallback explícito para providers legados sem suporte nativo por path.
|
|
508
|
+
const buffer = await fs.readFile(filePath);
|
|
509
|
+
url = await provider.upload(destination, {
|
|
510
|
+
fieldname: 'file',
|
|
511
|
+
originalname,
|
|
512
|
+
encoding: metadata?.encoding ?? '7bit',
|
|
513
|
+
mimetype,
|
|
514
|
+
size,
|
|
515
|
+
destination: '',
|
|
516
|
+
filename: originalname,
|
|
517
|
+
path: filePath,
|
|
518
|
+
buffer,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const file = await this.prismaService.file.create({
|
|
523
|
+
data: {
|
|
524
|
+
filename: originalname,
|
|
525
|
+
path: url,
|
|
526
|
+
provider_id: this.providerId,
|
|
527
|
+
location: destination,
|
|
528
|
+
mimetype_id: await this.getMimeType(mimetype),
|
|
529
|
+
size,
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
return file;
|
|
534
|
+
}
|
|
535
|
+
|
|
344
536
|
async delete(locale:string,{ ids }: DeleteDTO) {
|
|
345
537
|
const files = await this.prismaService.file.findMany({
|
|
346
538
|
where: {
|
|
@@ -482,9 +674,11 @@ export class FileService implements OnModuleInit {
|
|
|
482
674
|
);
|
|
483
675
|
}
|
|
484
676
|
|
|
677
|
+
const storage = await this.getStorage();
|
|
485
678
|
const provider = await this.getProvider();
|
|
486
|
-
const
|
|
487
|
-
const
|
|
679
|
+
const providerPath = this.getProviderPath(storage, file.path);
|
|
680
|
+
const metadata = await provider.metaData(providerPath);
|
|
681
|
+
const stream = await provider.readStream(providerPath);
|
|
488
682
|
const size = this.getFileSizeFromMetadata(metadata);
|
|
489
683
|
|
|
490
684
|
return {
|
|
@@ -9,6 +9,11 @@ interface IProvider {
|
|
|
9
9
|
mimetype?: string,
|
|
10
10
|
): Promise<any>;
|
|
11
11
|
upload(destination: string, file: MulterFile): Promise<any>;
|
|
12
|
+
uploadFromPath(
|
|
13
|
+
destination: string,
|
|
14
|
+
filePath: string,
|
|
15
|
+
options?: { filename?: string; mimetype?: string },
|
|
16
|
+
): Promise<any>;
|
|
12
17
|
readStream(filepath: string): Promise<any>;
|
|
13
18
|
delete(filepath: string): Promise<any>;
|
|
14
19
|
metaData(filepath: string): Promise<any>;
|
|
@@ -25,6 +30,11 @@ export abstract class AbstractProvider implements IProvider {
|
|
|
25
30
|
mimetype?: string,
|
|
26
31
|
): Promise<any>;
|
|
27
32
|
abstract upload(destination: string, file: MulterFile): Promise<any>;
|
|
33
|
+
abstract uploadFromPath(
|
|
34
|
+
destination: string,
|
|
35
|
+
filePath: string,
|
|
36
|
+
options?: { filename?: string; mimetype?: string },
|
|
37
|
+
): Promise<any>;
|
|
28
38
|
abstract readStream(filepath: string): Promise<any>;
|
|
29
39
|
abstract delete(filepath: string): Promise<any>;
|
|
30
40
|
abstract metaData(filepath: string): Promise<any>;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
StorageSharedKeyCredential,
|
|
6
6
|
} from '@azure/storage-blob';
|
|
7
7
|
import { BadRequestException } from '@nestjs/common';
|
|
8
|
+
import { basename } from 'path';
|
|
8
9
|
import { AbstractProvider } from './abstract.provider';
|
|
9
10
|
|
|
10
11
|
export class AzureProvider extends AbstractProvider {
|
|
@@ -92,6 +93,29 @@ export class AzureProvider extends AbstractProvider {
|
|
|
92
93
|
return `https://${this.setting['storage-abs-container']}.azureedge.net/${filepath}`;
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
async uploadFromPath(
|
|
97
|
+
destination: string,
|
|
98
|
+
filePath: string,
|
|
99
|
+
options?: { filename?: string; mimetype?: string },
|
|
100
|
+
): Promise<any> {
|
|
101
|
+
const blobServiceClient = await this.getClient();
|
|
102
|
+
const containerClient = blobServiceClient.getContainerClient(
|
|
103
|
+
this.setting['storage-abs-container'],
|
|
104
|
+
);
|
|
105
|
+
const filepath = [destination, this.getFilename(options?.filename ?? basename(filePath))].join(
|
|
106
|
+
'/',
|
|
107
|
+
);
|
|
108
|
+
const blobClient = containerClient.getBlockBlobClient(filepath);
|
|
109
|
+
|
|
110
|
+
await blobClient.uploadFile(filePath, {
|
|
111
|
+
blobHTTPHeaders: options?.mimetype
|
|
112
|
+
? { blobContentType: options.mimetype }
|
|
113
|
+
: undefined,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return `https://${this.setting['storage-abs-container']}.azureedge.net/${filepath}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
95
119
|
async delete(filepath: string): Promise<any> {
|
|
96
120
|
const url = new URL(filepath);
|
|
97
121
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Storage } from '@google-cloud/storage';
|
|
2
2
|
import { BadRequestException } from '@nestjs/common';
|
|
3
|
+
import { basename } from 'path';
|
|
3
4
|
import { AbstractProvider } from './abstract.provider';
|
|
4
5
|
|
|
5
6
|
export class GCSProvider extends AbstractProvider {
|
|
@@ -67,6 +68,25 @@ export class GCSProvider extends AbstractProvider {
|
|
|
67
68
|
contentType: file.mimetype,
|
|
68
69
|
});
|
|
69
70
|
}
|
|
71
|
+
|
|
72
|
+
async uploadFromPath(
|
|
73
|
+
destination: string,
|
|
74
|
+
filePath: string,
|
|
75
|
+
options?: { filename?: string; mimetype?: string },
|
|
76
|
+
): Promise<any> {
|
|
77
|
+
const storage = await this.getClient();
|
|
78
|
+
const bucket = storage.bucket(this.setting['storage-gcs-bucket']);
|
|
79
|
+
const objectPath = [destination.replace(/\/$/, ''), this.getFilename(options?.filename ?? basename(filePath))]
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
.join('/');
|
|
82
|
+
|
|
83
|
+
await bucket.upload(filePath, {
|
|
84
|
+
destination: objectPath,
|
|
85
|
+
contentType: options?.mimetype,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return objectPath;
|
|
89
|
+
}
|
|
70
90
|
async readStream(filepath: string): Promise<any> {
|
|
71
91
|
const storage = await this.getClient();
|
|
72
92
|
const bucket = storage.bucket(this.setting['storage-gcs-bucket']);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BadRequestException } from '@nestjs/common';
|
|
2
2
|
import { JwtService } from '@nestjs/jwt';
|
|
3
3
|
import { createReadStream, existsSync, promises as fs } from 'fs';
|
|
4
|
-
import { mkdir, unlink, writeFile } from 'fs/promises';
|
|
4
|
+
import { copyFile, mkdir, stat, unlink, writeFile } from 'fs/promises';
|
|
5
5
|
import * as path from 'path';
|
|
6
|
-
import { join, sep } from 'path';
|
|
6
|
+
import { basename, join, sep } from 'path';
|
|
7
7
|
import { Stream } from 'stream';
|
|
8
8
|
import { AbstractProvider } from './abstract.provider';
|
|
9
9
|
|
|
@@ -99,6 +99,34 @@ export class LocalProvider extends AbstractProvider {
|
|
|
99
99
|
return filePath;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
async uploadFromPath(
|
|
103
|
+
destination: string,
|
|
104
|
+
filePath: string,
|
|
105
|
+
options?: { filename?: string; mimetype?: string },
|
|
106
|
+
): Promise<any> {
|
|
107
|
+
const sourcePath = this.resolveFilepath(filePath);
|
|
108
|
+
if (!existsSync(sourcePath)) {
|
|
109
|
+
throw new BadRequestException(`File not found: ${sourcePath}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const sourceStats = await stat(sourcePath);
|
|
113
|
+
if (!sourceStats.isFile()) {
|
|
114
|
+
throw new BadRequestException(`Invalid file path: ${sourcePath}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const storagePath = join(this.setting['storage-local-path'], destination);
|
|
118
|
+
|
|
119
|
+
if (!existsSync(storagePath)) {
|
|
120
|
+
await this.createFolderRecursive(storagePath);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const targetFilename = this.getFilename(options?.filename ?? basename(sourcePath));
|
|
124
|
+
const targetPath = join(storagePath, targetFilename);
|
|
125
|
+
await copyFile(sourcePath, targetPath);
|
|
126
|
+
|
|
127
|
+
return targetPath;
|
|
128
|
+
}
|
|
129
|
+
|
|
102
130
|
async delete(filepath: string): Promise<any> {
|
|
103
131
|
const fullPath = this.resolveFilepath(filepath);
|
|
104
132
|
|