@futdevpro/nts-dynamo 1.15.15 → 1.15.16
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/.c8rc.json +26 -26
- package/.copilot/patterns.json +7 -7
- package/.cursor/rules/__assistant_guide.mdc +30 -30
- package/.cursor/rules/_ag_backend-structure.mdc +85 -85
- package/.cursor/rules/_ag_backend.mdc +16 -16
- package/.cursor/rules/_ag_frontend-structure.mdc +86 -86
- package/.cursor/rules/_ag_frontend.mdc +39 -39
- package/.cursor/rules/_ag_import-rules.mdc +44 -44
- package/.cursor/rules/_ag_naming.mdc +115 -115
- package/.cursor/rules/_ag_should-be.mdc +6 -6
- package/.cursor/rules/ai_development_guide.md +60 -60
- package/.cursor/rules/cursor-rules.md +160 -160
- package/.cursor/rules/default-command.mdc +464 -464
- package/.cursor/rules/error_code_pattern.md +39 -39
- package/.cursor/rules/saved rule mcp server use.md +15 -15
- package/.dynamo/version-bump.config.json +5 -0
- package/.github/workflows/main.yml +426 -393
- package/.husky/pre-commit +1 -0
- package/.vscode/settings.json +10 -10
- package/HOWTO.md +15 -15
- package/LICENSE +21 -21
- package/__documentations/2026-04-28-logs-module.md +49 -0
- package/__documentations/nts-integration-tests-2026-03-17.md +26 -26
- package/_specifications/BACKLOG.md +50 -50
- package/_specifications/TODO.md +15 -15
- package/_specifications/agent.md +138 -138
- package/eslint.config.js +3 -3
- package/nodemon.json +24 -24
- package/package.json +343 -362
- package/pipeline.cicd.config.json +152 -0
- package/scripts/run-coverage-tests.js +28 -28
- package/spec/support/helpers/spec-reporter-loader.js +359 -359
- package/spec/support/helpers/ts-node-helper.js +93 -93
- package/spec/support/jasmine.coverage.json +24 -24
- package/spec/support/jasmine.json +24 -24
- package/src/_collections/archive.util.spec.ts +57 -57
- package/src/_collections/archive.util.ts +18 -18
- package/src/_collections/atlas-default-db-options.const.ts +9 -9
- package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -11
- package/src/_collections/default-fallback-cache-max-age.const.ts +2 -2
- package/src/_collections/default-not-found-page.const.spec.ts +19 -19
- package/src/_collections/default-not-found-page.const.ts +22 -22
- package/src/_collections/default-socket-path.const.spec.ts +12 -12
- package/src/_collections/default-socket-path.const.ts +2 -2
- package/src/_collections/get-environment-settings.util.spec.ts +210 -210
- package/src/_collections/get-environment-settings.util.ts +48 -48
- package/src/_collections/sample.env +21 -21
- package/src/_collections/star.controller.spec.ts +224 -224
- package/src/_collections/star.controller.ts +129 -129
- package/src/_enums/data-model-type.enum.ts +14 -14
- package/src/_enums/data-service-function.enum.ts +24 -24
- package/src/_enums/predefined-data-types.enum.ts +16 -16
- package/src/_enums/route-security.enum.ts +12 -12
- package/src/_models/control-models/api-call-params.control-model.spec.ts +152 -152
- package/src/_models/control-models/api-call-params.control-model.ts +142 -142
- package/src/_models/control-models/app-ext-system-controls.control-model.spec.ts +52 -52
- package/src/_models/control-models/app-ext-system-controls.control-model.ts +9 -9
- package/src/_models/control-models/app-params.control-model.spec.ts +225 -225
- package/src/_models/control-models/app-params.control-model.ts +136 -136
- package/src/_models/control-models/app-system-controls.control-model.spec.ts +31 -31
- package/src/_models/control-models/app-system-controls.control-model.ts +9 -9
- package/src/_models/control-models/endpoint-params.control-model.spec.ts +578 -578
- package/src/_models/control-models/endpoint-params.control-model.ts +526 -526
- package/src/_models/control-models/http-settings.control-model.spec.ts +77 -77
- package/src/_models/control-models/http-settings.control-model.ts +37 -37
- package/src/_models/control-models/system-control.control-model.spec.ts +27 -27
- package/src/_models/control-models/system-control.control-model.ts +12 -12
- package/src/_models/interfaces/certification-settings.interface.ts +7 -7
- package/src/_models/interfaces/environment-settings.interface.ts +59 -59
- package/src/_models/interfaces/global-log-settings.interface.ts +108 -108
- package/src/_models/interfaces/global-service-settings.interface.ts +47 -47
- package/src/_models/interfaces/routing-module-settings.interface.ts +21 -21
- package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -29
- package/src/_models/interfaces/static-client-settings.interface.ts +28 -28
- package/src/_models/types/db-update.type.ts +100 -100
- package/src/_modules/ai/_models/ai-input-interfaces.ts +117 -117
- package/src/_modules/ai/_models/ai-test-generation-result.interface.ts +16 -16
- package/src/_modules/ai/_modules/anthropic/_services/aai-user-key.control-service.ts +138 -138
- package/src/_modules/ai/_modules/anthropic/index.ts +5 -5
- package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.spec.ts +242 -242
- package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.ts +639 -639
- package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.spec.ts +209 -209
- package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.ts +85 -85
- package/src/_modules/ai/_modules/document-ai/_enums/dai-compare-result-type.enum.ts +7 -7
- package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-chunk.data-model.ts +146 -146
- package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-page.data-model.ts +162 -162
- package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-document.data-model.ts +99 -99
- package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-chunk-compare-result.interface.ts +18 -18
- package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-page-compare-result.interface.ts +19 -19
- package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-document-compare-result.interface.ts +25 -25
- package/src/_modules/ai/_modules/document-ai/index.ts +28 -28
- package/src/_modules/ai/_modules/fdp-ai/_services/fdpai-user-key.control-service.ts +189 -189
- package/src/_modules/ai/_modules/fdp-ai/index.ts +5 -5
- package/src/_modules/ai/_modules/open-ai/_collections/oai-global-settings.const.ts +9 -9
- package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests-hu.conts.ts +82 -82
- package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests.conts.ts +75 -75
- package/src/_modules/ai/_modules/open-ai/_enums/oai-gpt-message-role.enum.ts +45 -45
- package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-global-settings.interface.ts +7 -7
- package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-gpt-message.interface.ts +7 -7
- package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-llm-predefined-requests.interface.ts +57 -57
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-doc-chunk-data.service.ts +292 -292
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-document.data-service.spec.ts +342 -342
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.spec.ts +550 -550
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.ts +630 -630
- package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.spec.ts +240 -240
- package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.ts +98 -98
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.spec.ts +462 -462
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.ts +615 -615
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.spec.ts +437 -437
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +833 -833
- package/src/_modules/ai/_modules/open-ai/_services/oai-user-key.control-service.ts +157 -157
- package/src/_modules/ai/_services/ai-embedding.service-base.spec.ts +98 -98
- package/src/_modules/ai/_services/ai-embedding.service-base.ts +48 -48
- package/src/_modules/ai/_services/ai-llm-chat.service-base.spec.ts +229 -229
- package/src/_modules/ai/_services/ai-llm-chat.service-base.ts +68 -68
- package/src/_modules/ai/_services/ai-llm.service-base.spec.ts +250 -250
- package/src/_modules/ai/_services/ai-llm.service-base.ts +332 -332
- package/src/_modules/ai/_services/ai-provider.service-base.spec.ts +79 -79
- package/src/_modules/ai/_services/ai-provider.service-base.ts +29 -29
- package/src/_modules/ai/_services/ai-user-key.service-base.ts +59 -59
- package/src/_modules/ai/index.ts +13 -13
- package/src/_modules/assistant/_collections/ass-global-settings.const.ts +13 -13
- package/src/_modules/assistant/_collections/ass.util.spec.ts +176 -176
- package/src/_modules/assistant/_collections/ass.util.ts +50 -50
- package/src/_modules/assistant/_models/ass-global-settings.interface.ts +15 -15
- package/src/_modules/assistant/_services/ass-io.control-service.spec.ts +140 -140
- package/src/_modules/assistant/_services/ass-main.control-service.spec.ts +192 -192
- package/src/_modules/assistant/_services/ass-main.control-service.ts +107 -107
- package/src/_modules/bot/_collections/bot-default-commands.const.ts +12 -12
- package/src/_modules/bot/_collections/bot-global-settings.const.ts +39 -39
- package/src/_modules/bot/_models/bot-channel-wrapper.interface.ts +62 -62
- package/src/_modules/bot/_models/bot-command.interface.ts +8 -8
- package/src/_modules/bot/_models/bot-global-settings.interface.ts +96 -96
- package/src/_modules/bot/_models/bot-last-mention-date.interface.ts +6 -6
- package/src/_modules/bot/_models/bot-last-message-date.interface.ts +5 -5
- package/src/_modules/bot/_models/bot-user-wrapper.interface.ts +41 -41
- package/src/_modules/bot/_modules/discord-bot/_models/dib-platform.types.ts +9 -9
- package/src/_modules/bot/_modules/discord-bot/_services/dib-messaging-provider.control-service.spec.ts +431 -431
- package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.spec.ts +160 -160
- package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.ts +55 -55
- package/src/_modules/bot/_modules/dynamo-bot/_models/dyb-platform.types.ts +15 -15
- package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.spec.ts +374 -374
- package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.ts +447 -447
- package/src/_modules/bot/_modules/dynamo-bot/index.ts +15 -15
- package/src/_modules/bot/_modules/slack-bot/_models/slb-platform.types.ts +9 -9
- package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.spec.ts +344 -344
- package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.ts +197 -197
- package/src/_modules/bot/_modules/teams-bot/_models/teb-platform.types.ts +9 -9
- package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.spec.ts +345 -345
- package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.ts +197 -197
- package/src/_modules/bot/_services/bot-commands.control-service.spec.ts +116 -116
- package/src/_modules/bot/_services/bot-io.control-service.spec.ts +285 -285
- package/src/_modules/bot/_services/bot-main.control-service.spec.ts +208 -208
- package/src/_modules/bot/_services/bot-messaging-provider.service-base.spec.ts +349 -349
- package/src/_modules/bot/_services/bot-routines.control-service.spec.ts +111 -111
- package/src/_modules/custom-data/custom-data.controller.spec.ts +49 -49
- package/src/_modules/custom-data/custom-data.controller.ts +67 -67
- package/src/_modules/custom-data/custom-data.data-service.spec.ts +54 -54
- package/src/_modules/custom-data/custom-data.data-service.ts +21 -21
- package/src/_modules/custom-data/get-custom-data-routing-module.util.spec.ts +28 -28
- package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +24 -24
- package/src/_modules/custom-data/index.ts +9 -9
- package/src/_modules/defaults/_collections/default-endpoints.util.ts +487 -487
- package/src/_modules/defaults/_models/default-user.data-model.ts +72 -72
- package/src/_modules/defaults/_services/default-auth.service.spec.ts +269 -269
- package/src/_modules/defaults/_services/default-auth.service.ts +177 -177
- package/src/_modules/defaults/_services/default-socket-events.service.spec.ts +42 -42
- package/src/_modules/defaults/_services/default-socket-events.service.ts +61 -61
- package/src/_modules/defaults/_services/default-user.data-service.spec.ts +187 -187
- package/src/_modules/defaults/_services/default-user.data-service.ts +98 -98
- package/src/_modules/defaults/index.ts +17 -17
- package/src/_modules/discord-assistant/_collections/dias-global-settings.const.ts +19 -19
- package/src/_modules/discord-assistant/_collections/dias.util.spec.ts +366 -366
- package/src/_modules/discord-assistant/_collections/dias.util.ts +132 -132
- package/src/_modules/discord-assistant/_models/dias-global-settings.interface.ts +19 -19
- package/src/_modules/discord-assistant/_models/dias-knowledge.data-model.ts +52 -52
- package/src/_modules/discord-assistant/_services/dias-chunk.data-service.ts +177 -177
- package/src/_modules/discord-assistant/_services/dias-io.control-service.spec.ts +108 -108
- package/src/_modules/discord-assistant/_services/dias-io.control-service.ts +69 -69
- package/src/_modules/discord-assistant/_services/dias-main.control-service.spec.ts +22 -22
- package/src/_modules/discord-assistant/_services/dias-main.control-service.ts +27 -27
- package/src/_modules/discord-assistant/_services/dias.service-base.spec.ts +195 -195
- package/src/_modules/discord-assistant/_services/dias.service-base.ts +76 -76
- package/src/_modules/discord-assistant/index.ts +38 -38
- package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.spec.ts +34 -34
- package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.ts +11 -11
- package/src/_modules/discord-assistant-voiced/index.ts +36 -36
- package/src/_modules/discord-bot/_collections/dibo-default-commands.const.ts +16 -16
- package/src/_modules/discord-bot/_collections/dibo-global-settings.conts.ts +55 -55
- package/src/_modules/discord-bot/_collections/dibo-operations.util.spec.ts +214 -214
- package/src/_modules/discord-bot/_collections/dibo-operations.util.ts +387 -387
- package/src/_modules/discord-bot/_models/dibo-command.interface.ts +12 -12
- package/src/_modules/discord-bot/_models/dibo-global-settings.interface.ts +98 -98
- package/src/_modules/discord-bot/_models/dibo-last-mention-date.inteface.ts +7 -7
- package/src/_modules/discord-bot/_models/dibo-last-message-date.interface.ts +6 -6
- package/src/_modules/discord-bot/_services/dibo-commands.control-service.spec.ts +154 -154
- package/src/_modules/discord-bot/_services/dibo-commands.control-service.ts +153 -153
- package/src/_modules/discord-bot/_services/dibo-io.control-service.spec.ts +264 -264
- package/src/_modules/discord-bot/_services/dibo-io.control-service.ts +306 -306
- package/src/_modules/discord-bot/_services/dibo-main.control-service.spec.ts +408 -408
- package/src/_modules/discord-bot/_services/dibo-main.control-service.ts +487 -487
- package/src/_modules/discord-bot/_services/dibo-routines.control-service.spec.ts +105 -105
- package/src/_modules/discord-bot/index.ts +36 -36
- package/src/_modules/local-vector-search/_enums/lvs-search-mode.enum.ts +19 -19
- package/src/_modules/local-vector-search/_models/lvs-search-result.interface.ts +17 -17
- package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.spec.ts +418 -418
- package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.ts +276 -276
- package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.spec.ts +345 -345
- package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.ts +330 -330
- package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +393 -393
- package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +220 -220
- package/src/_modules/local-vector-search/index.ts +11 -11
- package/src/_modules/messaging/README.md +354 -354
- package/src/_modules/messaging/_collections/get-messaging-routing-module.util.ts +26 -26
- package/src/_modules/messaging/_collections/msg-global-settings.const.ts +22 -22
- package/src/_modules/messaging/_collections/msg.util.spec.ts +226 -226
- package/src/_modules/messaging/_models/msg-global-settings.interface.ts +37 -37
- package/src/_modules/messaging/_services/msg-conversation.data-service.ts +146 -146
- package/src/_modules/messaging/_services/msg-events.service.spec.ts +219 -219
- package/src/_modules/messaging/_services/msg-events.service.ts +267 -267
- package/src/_modules/messaging/_services/msg-integration.control-service.ts +179 -179
- package/src/_modules/messaging/_services/msg-main.control-service.spec.ts +147 -147
- package/src/_modules/messaging/_services/msg-main.control-service.ts +571 -571
- package/src/_modules/messaging/_services/msg-message.data-service.ts +129 -129
- package/src/_modules/messaging/_services/msg.controller.spec.ts +201 -201
- package/src/_modules/messaging/index.ts +30 -30
- package/src/_modules/mock/app-extended-server.mock.ts +201 -201
- package/src/_modules/mock/app-integration-test.mock.ts +51 -51
- package/src/_modules/mock/app-params.mock.spec.ts +21 -21
- package/src/_modules/mock/app-params.mock.ts +9 -9
- package/src/_modules/mock/app-server.mock.ts +188 -188
- package/src/_modules/mock/auth-service.mock.spec.ts +47 -47
- package/src/_modules/mock/auth-service.mock.ts +28 -28
- package/src/_modules/mock/controller.mock.spec.ts +26 -26
- package/src/_modules/mock/controller.mock.ts +16 -16
- package/src/_modules/mock/data-model.mock.spec.ts +111 -111
- package/src/_modules/mock/data-model.mock.ts +82 -82
- package/src/_modules/mock/email-service-collection.mock.spec.ts +24 -24
- package/src/_modules/mock/email-service-collection.mock.ts +15 -15
- package/src/_modules/mock/email-service.mock.spec.ts +17 -17
- package/src/_modules/mock/email-service.mock.ts +20 -20
- package/src/_modules/mock/email-template.mock.html +14 -14
- package/src/_modules/mock/endpoint.mock.ts +91 -91
- package/src/_modules/mock/socket-client.mock.spec.ts +40 -40
- package/src/_modules/mock/socket-client.mock.ts +45 -45
- package/src/_modules/mock/socket-server.mock.spec.ts +44 -44
- package/src/_modules/mock/socket-server.mock.ts +46 -46
- package/src/_modules/oauth2/_routes/oauth2.controller.spec.ts +107 -107
- package/src/_modules/oauth2/_routes/oauth2.controller.ts +98 -98
- package/src/_modules/oauth2/_services/oauth2.auth-service.spec.ts +254 -254
- package/src/_modules/oauth2/_services/oauth2.auth-service.ts +232 -232
- package/src/_modules/oauth2/_services/oauth2.control-service.spec.ts +585 -585
- package/src/_modules/oauth2/_services/oauth2.control-service.ts +653 -653
- package/src/_modules/oauth2/index.ts +17 -17
- package/src/_modules/server/errors/errors.control-service.spec.ts +230 -230
- package/src/_modules/server/errors/errors.control-service.ts +69 -69
- package/src/_modules/server/errors/errors.controller.spec.ts +165 -165
- package/src/_modules/server/errors/errors.controller.ts +270 -270
- package/src/_modules/server/errors/errors.data-service.spec.ts +355 -355
- package/src/_modules/server/index.ts +30 -30
- package/src/_modules/server/server-status/server-status-snapshot.control-service.spec.ts +70 -70
- package/src/_modules/server/server-status/server-status-snapshot.control-service.ts +17 -17
- package/src/_modules/server/server-status/server-status-snapshot.data-service.spec.ts +77 -77
- package/src/_modules/server/server-status/server-status-snapshot.data-service.ts +37 -37
- package/src/_modules/server/server-status/server-status.control-service.spec.ts +516 -516
- package/src/_modules/server/server-status/server-status.control-service.ts +336 -336
- package/src/_modules/server/server-status/server-status.controller.spec.ts +156 -156
- package/src/_modules/server/server-status/server-status.controller.ts +131 -131
- package/src/_modules/socket/_enums/socket-security.enum.ts +11 -11
- package/src/_modules/socket/_models/socket-client-service-params.control-model.spec.ts +32 -32
- package/src/_modules/socket/_models/socket-client-service-params.control-model.ts +22 -22
- package/src/_modules/socket/_models/socket-presence.control-model.spec.ts +164 -164
- package/src/_modules/socket/_models/socket-presence.control-model.ts +210 -210
- package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +46 -46
- package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +22 -22
- package/src/_modules/socket/_services/socket-client.service.spec.ts +15 -15
- package/src/_modules/socket/_services/socket-client.service.ts +260 -260
- package/src/_modules/socket/_services/socket-server.service.spec.ts +11 -11
- package/src/_modules/socket/app-extended.integration.spec.ts +85 -85
- package/src/_modules/socket/app-extended.server.ts +630 -630
- package/src/_modules/socket/index.ts +42 -42
- package/src/_modules/test/get-test-routing-module.util.spec.ts +28 -28
- package/src/_modules/test/get-test-routing-module.util.ts +23 -23
- package/src/_modules/test/index.ts +11 -11
- package/src/_modules/test/test.controller.spec.ts +72 -72
- package/src/_modules/test/test.controller.ts +115 -115
- package/src/_modules/usage/get-usage-routing-module.util.ts +22 -22
- package/src/_modules/usage/index.ts +15 -15
- package/src/_modules/usage/usage.controller.spec.ts +81 -81
- package/src/_modules/usage/usage.controller.ts +126 -126
- package/src/_modules/usage/usage.data-service.spec.ts +332 -332
- package/src/_modules/usage/usage.data-service.ts +185 -185
- package/src/_services/base/api.service-base.spec.ts +125 -125
- package/src/_services/base/api.service-base.ts +74 -74
- package/src/_services/base/archive-data.service.spec.ts +196 -196
- package/src/_services/base/archive-data.service.ts +216 -216
- package/src/_services/base/data.service.spec.ts +493 -493
- package/src/_services/base/data.service.ts +2525 -2525
- package/src/_services/base/db.service.spec.ts +73 -73
- package/src/_services/base/db.service.ts +1575 -1575
- package/src/_services/base/singleton.service-base.spec.ts +28 -28
- package/src/_services/base/singleton.service-base.ts +24 -24
- package/src/_services/base/singleton.service.spec.ts +114 -114
- package/src/_services/base/singleton.service.ts +38 -38
- package/src/_services/core/api.service.spec.ts +140 -140
- package/src/_services/core/auth.service.spec.ts +159 -159
- package/src/_services/core/auth.service.ts +174 -174
- package/src/_services/core/email.service.spec.ts +85 -85
- package/src/_services/core/email.service.ts +742 -742
- package/src/_services/core/global.service.spec.ts +275 -275
- package/src/_services/core/global.service.ts +461 -461
- package/src/_services/core/service-collection.service.spec.ts +46 -46
- package/src/_services/core/service-collection.service.ts +6 -6
- package/src/_services/route/controller.service.spec.ts +53 -53
- package/src/_services/route/controller.service.ts +148 -148
- package/src/_services/route/routing-module.service.spec.ts +98 -98
- package/src/_services/route/routing-module.service.ts +330 -330
- package/src/_services/shared.static-service.spec.ts +99 -99
- package/src/_services/shared.static-service.ts +78 -78
- package/src/index.ts +94 -94
- package/tsconfig.app.json +12 -12
- package/tsconfig.json +42 -42
- package/build/_modules/logs/get-logs-routing-module.util.d.ts +0 -19
- package/build/_modules/logs/get-logs-routing-module.util.d.ts.map +0 -1
- package/build/_modules/logs/get-logs-routing-module.util.js +0 -32
- package/build/_modules/logs/get-logs-routing-module.util.js.map +0 -1
- package/build/_modules/logs/index.d.ts +0 -4
- package/build/_modules/logs/index.d.ts.map +0 -1
- package/build/_modules/logs/index.js +0 -10
- package/build/_modules/logs/index.js.map +0 -1
- package/build/_modules/logs/log-buffer.service.d.ts +0 -38
- package/build/_modules/logs/log-buffer.service.d.ts.map +0 -1
- package/build/_modules/logs/log-buffer.service.js +0 -97
- package/build/_modules/logs/log-buffer.service.js.map +0 -1
- package/build/_modules/logs/logs.controller.d.ts +0 -27
- package/build/_modules/logs/logs.controller.d.ts.map +0 -1
- package/build/_modules/logs/logs.controller.js +0 -90
- package/build/_modules/logs/logs.controller.js.map +0 -1
- package/build/_modules/logs/logs.service.d.ts +0 -40
- package/build/_modules/logs/logs.service.d.ts.map +0 -1
- package/build/_modules/logs/logs.service.js +0 -97
- package/build/_modules/logs/logs.service.js.map +0 -1
- package/src/_modules/logs/get-logs-routing-module.util.ts +0 -36
- package/src/_modules/logs/index.ts +0 -3
- package/src/_modules/logs/log-buffer.service.ts +0 -101
- package/src/_modules/logs/logs.controller.ts +0 -109
- package/src/_modules/logs/logs.service.ts +0 -100
|
@@ -1,387 +1,387 @@
|
|
|
1
|
-
import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Client, Guild, GuildChannelManager, GuildBasedChannel, Message, TextBasedChannel, GuildMember,
|
|
5
|
-
TextChannel,
|
|
6
|
-
VoiceChannel
|
|
7
|
-
} from 'discord.js';
|
|
8
|
-
import { Collection } from 'discord.js';
|
|
9
|
-
import { DyNTS_DiBo_global_settings } from './dibo-global-settings.conts';
|
|
10
|
-
import { DyNTS_DiBo_LastMessageDate } from '../_models/dibo-last-message-date.interface';
|
|
11
|
-
import { DyNTS_DiBo_LastMentionDate } from '../_models/dibo-last-mention-date.inteface';
|
|
12
|
-
import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
|
|
13
|
-
|
|
14
|
-
export class DyNTS_DiBo_Operations_Util {
|
|
15
|
-
|
|
16
|
-
static findChannelByName(channels: GuildChannelManager, name: string): GuildBasedChannel {
|
|
17
|
-
const channel = channels.cache.find(
|
|
18
|
-
(ch) => ch.name === name && ch.isTextBased()
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
if (!channel) {
|
|
22
|
-
DyFM_Log.error(`No text channel found with name "${name}"`)
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return channel
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
static findTextChannelByName(channels: GuildChannelManager, name: string): TextChannel {
|
|
30
|
-
const channel = this.findChannelByName(channels, name)
|
|
31
|
-
|
|
32
|
-
if (!channel.isTextBased()) {
|
|
33
|
-
throw new Error(`Channel is not text based with name "${name}"`)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return channel as TextChannel
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static findVoiceChannelByName(channels: GuildChannelManager, name: string): VoiceChannel {
|
|
40
|
-
const channel = this.findChannelByName(channels, name)
|
|
41
|
-
|
|
42
|
-
if (!channel.isVoiceBased()) {
|
|
43
|
-
throw new Error(`Channel is not voice based with name "${name}"`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return channel as VoiceChannel
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
static async reportIn(guild: Guild, client: Client): Promise<void> {
|
|
50
|
-
try {
|
|
51
|
-
const lastReportMessage = await this.getLastMessageInChannel(
|
|
52
|
-
guild,
|
|
53
|
-
DyNTS_DiBo_global_settings.channelSettings.reportChannelName
|
|
54
|
-
)
|
|
55
|
-
const reportMessage = `${client.user?.username} report for duty! ` +
|
|
56
|
-
`(v${DyNTS_global_settings.systemVersion} ${DyNTS_global_settings.env_settings?.environment})`;
|
|
57
|
-
|
|
58
|
-
if (lastReportMessage?.content === reportMessage) {
|
|
59
|
-
await this.deleteMessage(lastReportMessage).catch((error) => {
|
|
60
|
-
DyFM_Error.logSimple('Failed to delete message', error);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this.sendMessageToChannelByName(
|
|
65
|
-
guild,
|
|
66
|
-
DyNTS_DiBo_global_settings.channelSettings.reportChannelName,
|
|
67
|
-
reportMessage
|
|
68
|
-
)
|
|
69
|
-
} catch (error) {
|
|
70
|
-
DyFM_Error.logSimple('Failed to report in', error);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static sendMessageToChannelByName(guild: Guild, channelName: string, message: string) {
|
|
75
|
-
const channel = this.findChannelByName(guild.channels, channelName)
|
|
76
|
-
|
|
77
|
-
if (channel?.isTextBased()) {
|
|
78
|
-
channel.send(message)
|
|
79
|
-
DyFM_Log.success('Message sent to channel', channel.name)
|
|
80
|
-
} else {
|
|
81
|
-
DyFM_Log.error(`Channel is not text based "${channelName}"`)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
static async readMembersInChannel(
|
|
86
|
-
guild: Guild,
|
|
87
|
-
channelName: string
|
|
88
|
-
): Promise<Collection<string, GuildMember>> {
|
|
89
|
-
const channel = this.findChannelByName(guild.channels, channelName)
|
|
90
|
-
|
|
91
|
-
const members = await this.fetchMembersInGuild(guild)
|
|
92
|
-
|
|
93
|
-
const allowedMembers = members?.filter((member) =>
|
|
94
|
-
channel.permissionsFor(member)?.has('ViewChannel')
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
return allowedMembers
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
static async fetchMembersInGuild(guild: Guild): Promise<Collection<string, GuildMember>> {
|
|
101
|
-
try {
|
|
102
|
-
// Try to fetch with a limit to avoid timeout
|
|
103
|
-
return await guild?.members.fetch({ limit: 1000 })
|
|
104
|
-
} catch (fetchError) {
|
|
105
|
-
throw new DyFM_Error({
|
|
106
|
-
errorCode: 'DIB-OPS-FMI0',
|
|
107
|
-
message: 'Failed to fetch members',
|
|
108
|
-
error: fetchError,
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
static async readMemberNamesInChannel(guild: Guild, channelName: string): Promise<string[]> {
|
|
114
|
-
const members = await this.readMembersInChannel(guild, channelName)
|
|
115
|
-
|
|
116
|
-
const memberNames = members?.map((member) => member.user.username)
|
|
117
|
-
|
|
118
|
-
return memberNames
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
static async fetchAllMessagesWithPaging(
|
|
122
|
-
channel: TextBasedChannel,
|
|
123
|
-
maxFetch = 1000
|
|
124
|
-
): Promise<Collection<string, Message<true>>> {
|
|
125
|
-
let lastId: string | undefined = undefined;
|
|
126
|
-
let fetched = 0;
|
|
127
|
-
const allMessages = new Collection<string, Message<true>>();
|
|
128
|
-
|
|
129
|
-
while (fetched < maxFetch) {
|
|
130
|
-
const options: any = { limit: 100 };
|
|
131
|
-
if (lastId) options.before = lastId;
|
|
132
|
-
|
|
133
|
-
const messages = await channel.messages.fetch(options) as unknown as Collection<string, Message<true>>;
|
|
134
|
-
if (messages.size === 0) break;
|
|
135
|
-
|
|
136
|
-
messages.forEach((msg: Message<true>) => {
|
|
137
|
-
allMessages.set(msg.id, msg);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
lastId = messages.last()?.id;
|
|
141
|
-
fetched += messages.size;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
DyFM_Log.success('Fetched messages with paging', allMessages.size);
|
|
145
|
-
return allMessages;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
static async readLastMessageDatesByMembers(
|
|
149
|
-
guild: Guild,
|
|
150
|
-
channelName: string,
|
|
151
|
-
memberNames: string[]
|
|
152
|
-
): Promise<DyNTS_DiBo_LastMessageDate[]> {
|
|
153
|
-
const channel = this.findChannelByName(guild.channels, channelName)
|
|
154
|
-
|
|
155
|
-
if (!channel?.isTextBased()) {
|
|
156
|
-
DyFM_Log.error(`Channel is not text based "${channelName}"`)
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Prepare tracking for each member
|
|
161
|
-
const memberStatus: Record<string, { lastMessageDate: Date | null, allMessages: number }> = {};
|
|
162
|
-
memberNames.forEach(name => {
|
|
163
|
-
memberStatus[name] = { lastMessageDate: null, allMessages: 0 };
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
let lastId: string | undefined = undefined;
|
|
167
|
-
let done = false;
|
|
168
|
-
const cutoffTime = Date.now() - DyNTS_DiBo_global_settings.messageSettings.messageFetchTimeLimit;
|
|
169
|
-
let totalFetched = 0;
|
|
170
|
-
|
|
171
|
-
while (
|
|
172
|
-
!done &&
|
|
173
|
-
totalFetched < DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
174
|
-
) {
|
|
175
|
-
const options: any = { limit: 100 };
|
|
176
|
-
if (lastId) options.before = lastId;
|
|
177
|
-
const messages = await channel.messages.fetch(options) as unknown as Collection<string, Message<true>>;
|
|
178
|
-
if (messages.size === 0) break;
|
|
179
|
-
|
|
180
|
-
let shouldStop = false;
|
|
181
|
-
messages.forEach((message) => {
|
|
182
|
-
// Check if message is too old
|
|
183
|
-
if (message.createdTimestamp < cutoffTime) {
|
|
184
|
-
shouldStop = true;
|
|
185
|
-
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const author = message.author.username;
|
|
190
|
-
if (memberStatus[author] !== undefined) {
|
|
191
|
-
memberStatus[author].allMessages++;
|
|
192
|
-
|
|
193
|
-
// Only set lastMessageDate if not already set (since we fetch newest first)
|
|
194
|
-
if (!memberStatus[author].lastMessageDate) {
|
|
195
|
-
memberStatus[author].lastMessageDate = message.createdAt;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
if (shouldStop) {
|
|
201
|
-
DyFM_Log.warn('Reached time limit cutoff');
|
|
202
|
-
break;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Check if all members have a lastMessageDate
|
|
206
|
-
done = memberNames.every(name => memberStatus[name].lastMessageDate !== null);
|
|
207
|
-
lastId = messages.last()?.id;
|
|
208
|
-
totalFetched += messages.size;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (totalFetched >= DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit) {
|
|
212
|
-
DyFM_Log.warn(
|
|
213
|
-
'Reached maximum fetch count limit',
|
|
214
|
-
DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const lastMessageDatesByMembers: DyNTS_DiBo_LastMessageDate[] = memberNames.map((memberName) => {
|
|
219
|
-
const status = memberStatus[memberName];
|
|
220
|
-
if (!status.lastMessageDate) {
|
|
221
|
-
DyFM_Log.warn('No last message date found for member', memberName);
|
|
222
|
-
|
|
223
|
-
return {
|
|
224
|
-
memberName: memberName,
|
|
225
|
-
allMessages: status.allMessages,
|
|
226
|
-
lastMessageDate: null/* new Date(0) */
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return ({
|
|
231
|
-
memberName: memberName,
|
|
232
|
-
allMessages: status.allMessages,
|
|
233
|
-
lastMessageDate: new Date(status.lastMessageDate)
|
|
234
|
-
})
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
return lastMessageDatesByMembers;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
static async readLastMessageWithMemberNamePingInIt(
|
|
241
|
-
guild: Guild,
|
|
242
|
-
channelName: string,
|
|
243
|
-
members: Collection<string, GuildMember>
|
|
244
|
-
): Promise<DyNTS_DiBo_LastMentionDate[]> {
|
|
245
|
-
const channel = this.findChannelByName(guild.channels, channelName)
|
|
246
|
-
|
|
247
|
-
if (!channel?.isTextBased()) {
|
|
248
|
-
DyFM_Log.error(`Channel is not text based "${channelName}"`)
|
|
249
|
-
return []
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Prepare tracking for each member
|
|
253
|
-
const memberStatus: Record<string, { lastMentionDate: Date | null, allMentions: number }> = {};
|
|
254
|
-
members.forEach(member => {
|
|
255
|
-
memberStatus[member.user.username] = { lastMentionDate: null, allMentions: 0 };
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
let lastId: string | undefined = undefined;
|
|
259
|
-
let done = false;
|
|
260
|
-
const cutoffTime = Date.now() - DyNTS_DiBo_global_settings.messageSettings.messageFetchTimeLimit;
|
|
261
|
-
let totalFetched = 0;
|
|
262
|
-
|
|
263
|
-
while (
|
|
264
|
-
!done &&
|
|
265
|
-
totalFetched < DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
266
|
-
) {
|
|
267
|
-
const options: any = { limit: 100 };
|
|
268
|
-
if (lastId) options.before = lastId;
|
|
269
|
-
const messages = await channel.messages.fetch(options) as unknown as Collection<string, Message<true>>;
|
|
270
|
-
if (messages.size === 0) break;
|
|
271
|
-
|
|
272
|
-
let shouldStop = false;
|
|
273
|
-
messages.forEach((message) => {
|
|
274
|
-
// Check if message is too old
|
|
275
|
-
if (message.createdTimestamp < cutoffTime) {
|
|
276
|
-
shouldStop = true;
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Check if message content contains "@Username" for any member
|
|
281
|
-
members.forEach(member => {
|
|
282
|
-
if (
|
|
283
|
-
message.content.includes(`@${member.user.id}`) &&
|
|
284
|
-
!memberStatus[member.user.username].lastMentionDate
|
|
285
|
-
) {
|
|
286
|
-
memberStatus[member.user.username].lastMentionDate = message.createdAt;
|
|
287
|
-
memberStatus[member.user.username].allMentions++;
|
|
288
|
-
DyFM_Log.success(
|
|
289
|
-
'Found message with member ping',
|
|
290
|
-
{
|
|
291
|
-
memberName: member.user.username,
|
|
292
|
-
messageId: message.id
|
|
293
|
-
}
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
if (shouldStop) {
|
|
300
|
-
DyFM_Log.warn('Reached time limit cutoff while searching for member pings');
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Check if all members have a lastMessageDate
|
|
305
|
-
done = members.every(member => memberStatus[member.user.username].lastMentionDate !== null);
|
|
306
|
-
lastId = messages.last()?.id;
|
|
307
|
-
totalFetched += messages.size;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (totalFetched >= DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit) {
|
|
311
|
-
DyFM_Log.warn(
|
|
312
|
-
'Reached maximum fetch count limit while searching for member pings',
|
|
313
|
-
DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const lastMentionDatesByMembers: DyNTS_DiBo_LastMentionDate[] = members.map((member) => {
|
|
318
|
-
const status = memberStatus[member.user.username];
|
|
319
|
-
if (!status.lastMentionDate) {
|
|
320
|
-
DyFM_Log.warn('No message found with member ping', member.user.username);
|
|
321
|
-
return {
|
|
322
|
-
memberId: member.user.id,
|
|
323
|
-
memberName: member.user.username,
|
|
324
|
-
allMentions: status.allMentions,
|
|
325
|
-
lastMentionDate: null/* new Date(0) */
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return ({
|
|
329
|
-
memberId: member.user.id,
|
|
330
|
-
memberName: member.user.username,
|
|
331
|
-
allMentions: status.allMentions,
|
|
332
|
-
lastMentionDate: new Date(status.lastMentionDate)
|
|
333
|
-
})
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
return lastMentionDatesByMembers;
|
|
337
|
-
}
|
|
338
|
-
static readMentionsInChannel = this.readLastMessageWithMemberNamePingInIt
|
|
339
|
-
|
|
340
|
-
static async readLastMessagesInChannel(
|
|
341
|
-
guild: Guild,
|
|
342
|
-
channelName: string,
|
|
343
|
-
): Promise<Collection<string, Message<true>>> {
|
|
344
|
-
const channel = this.findChannelByName(guild.channels, channelName)
|
|
345
|
-
|
|
346
|
-
if (!channel?.isTextBased()) {
|
|
347
|
-
DyFM_Log.error(`Channel is not text based with name "${channelName}"`)
|
|
348
|
-
return
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const messages = await channel.messages.fetch({ limit: 100 })
|
|
352
|
-
|
|
353
|
-
return messages
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
static async getLastMessageInChannel(
|
|
357
|
-
guild: Guild,
|
|
358
|
-
channelName: string
|
|
359
|
-
): Promise<Message<true>> {
|
|
360
|
-
const channel = this.findChannelByName(guild.channels, channelName)
|
|
361
|
-
|
|
362
|
-
if (!channel?.isTextBased()) {
|
|
363
|
-
DyFM_Log.error(`Channel is not text based with name "${channelName}"`)
|
|
364
|
-
return
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const messages = await channel.messages.fetch({ limit: 1 })
|
|
368
|
-
|
|
369
|
-
return messages.first()
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
static getMemberIdByName(
|
|
373
|
-
members: Collection<string, GuildMember>,
|
|
374
|
-
username: string
|
|
375
|
-
): string | undefined {
|
|
376
|
-
const member = members.find(m => m.user.username === username);
|
|
377
|
-
return member ? member.user.id : undefined;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
static async deleteMessage(message: Message): Promise<void> {
|
|
381
|
-
await message.delete().catch((error) => {
|
|
382
|
-
DyFM_Error.logSimple('Failed to delete message', error);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
DyFM_Log.success('Message deleted:', message.content);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
1
|
+
import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Client, Guild, GuildChannelManager, GuildBasedChannel, Message, TextBasedChannel, GuildMember,
|
|
5
|
+
TextChannel,
|
|
6
|
+
VoiceChannel
|
|
7
|
+
} from 'discord.js';
|
|
8
|
+
import { Collection } from 'discord.js';
|
|
9
|
+
import { DyNTS_DiBo_global_settings } from './dibo-global-settings.conts';
|
|
10
|
+
import { DyNTS_DiBo_LastMessageDate } from '../_models/dibo-last-message-date.interface';
|
|
11
|
+
import { DyNTS_DiBo_LastMentionDate } from '../_models/dibo-last-mention-date.inteface';
|
|
12
|
+
import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
|
|
13
|
+
|
|
14
|
+
export class DyNTS_DiBo_Operations_Util {
|
|
15
|
+
|
|
16
|
+
static findChannelByName(channels: GuildChannelManager, name: string): GuildBasedChannel {
|
|
17
|
+
const channel = channels.cache.find(
|
|
18
|
+
(ch) => ch.name === name && ch.isTextBased()
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if (!channel) {
|
|
22
|
+
DyFM_Log.error(`No text channel found with name "${name}"`)
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return channel
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static findTextChannelByName(channels: GuildChannelManager, name: string): TextChannel {
|
|
30
|
+
const channel = this.findChannelByName(channels, name)
|
|
31
|
+
|
|
32
|
+
if (!channel.isTextBased()) {
|
|
33
|
+
throw new Error(`Channel is not text based with name "${name}"`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return channel as TextChannel
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static findVoiceChannelByName(channels: GuildChannelManager, name: string): VoiceChannel {
|
|
40
|
+
const channel = this.findChannelByName(channels, name)
|
|
41
|
+
|
|
42
|
+
if (!channel.isVoiceBased()) {
|
|
43
|
+
throw new Error(`Channel is not voice based with name "${name}"`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return channel as VoiceChannel
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static async reportIn(guild: Guild, client: Client): Promise<void> {
|
|
50
|
+
try {
|
|
51
|
+
const lastReportMessage = await this.getLastMessageInChannel(
|
|
52
|
+
guild,
|
|
53
|
+
DyNTS_DiBo_global_settings.channelSettings.reportChannelName
|
|
54
|
+
)
|
|
55
|
+
const reportMessage = `${client.user?.username} report for duty! ` +
|
|
56
|
+
`(v${DyNTS_global_settings.systemVersion} ${DyNTS_global_settings.env_settings?.environment})`;
|
|
57
|
+
|
|
58
|
+
if (lastReportMessage?.content === reportMessage) {
|
|
59
|
+
await this.deleteMessage(lastReportMessage).catch((error) => {
|
|
60
|
+
DyFM_Error.logSimple('Failed to delete message', error);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.sendMessageToChannelByName(
|
|
65
|
+
guild,
|
|
66
|
+
DyNTS_DiBo_global_settings.channelSettings.reportChannelName,
|
|
67
|
+
reportMessage
|
|
68
|
+
)
|
|
69
|
+
} catch (error) {
|
|
70
|
+
DyFM_Error.logSimple('Failed to report in', error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static sendMessageToChannelByName(guild: Guild, channelName: string, message: string) {
|
|
75
|
+
const channel = this.findChannelByName(guild.channels, channelName)
|
|
76
|
+
|
|
77
|
+
if (channel?.isTextBased()) {
|
|
78
|
+
channel.send(message)
|
|
79
|
+
DyFM_Log.success('Message sent to channel', channel.name)
|
|
80
|
+
} else {
|
|
81
|
+
DyFM_Log.error(`Channel is not text based "${channelName}"`)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static async readMembersInChannel(
|
|
86
|
+
guild: Guild,
|
|
87
|
+
channelName: string
|
|
88
|
+
): Promise<Collection<string, GuildMember>> {
|
|
89
|
+
const channel = this.findChannelByName(guild.channels, channelName)
|
|
90
|
+
|
|
91
|
+
const members = await this.fetchMembersInGuild(guild)
|
|
92
|
+
|
|
93
|
+
const allowedMembers = members?.filter((member) =>
|
|
94
|
+
channel.permissionsFor(member)?.has('ViewChannel')
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return allowedMembers
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static async fetchMembersInGuild(guild: Guild): Promise<Collection<string, GuildMember>> {
|
|
101
|
+
try {
|
|
102
|
+
// Try to fetch with a limit to avoid timeout
|
|
103
|
+
return await guild?.members.fetch({ limit: 1000 })
|
|
104
|
+
} catch (fetchError) {
|
|
105
|
+
throw new DyFM_Error({
|
|
106
|
+
errorCode: 'DIB-OPS-FMI0',
|
|
107
|
+
message: 'Failed to fetch members',
|
|
108
|
+
error: fetchError,
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static async readMemberNamesInChannel(guild: Guild, channelName: string): Promise<string[]> {
|
|
114
|
+
const members = await this.readMembersInChannel(guild, channelName)
|
|
115
|
+
|
|
116
|
+
const memberNames = members?.map((member) => member.user.username)
|
|
117
|
+
|
|
118
|
+
return memberNames
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static async fetchAllMessagesWithPaging(
|
|
122
|
+
channel: TextBasedChannel,
|
|
123
|
+
maxFetch = 1000
|
|
124
|
+
): Promise<Collection<string, Message<true>>> {
|
|
125
|
+
let lastId: string | undefined = undefined;
|
|
126
|
+
let fetched = 0;
|
|
127
|
+
const allMessages = new Collection<string, Message<true>>();
|
|
128
|
+
|
|
129
|
+
while (fetched < maxFetch) {
|
|
130
|
+
const options: any = { limit: 100 };
|
|
131
|
+
if (lastId) options.before = lastId;
|
|
132
|
+
|
|
133
|
+
const messages = await channel.messages.fetch(options) as unknown as Collection<string, Message<true>>;
|
|
134
|
+
if (messages.size === 0) break;
|
|
135
|
+
|
|
136
|
+
messages.forEach((msg: Message<true>) => {
|
|
137
|
+
allMessages.set(msg.id, msg);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
lastId = messages.last()?.id;
|
|
141
|
+
fetched += messages.size;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
DyFM_Log.success('Fetched messages with paging', allMessages.size);
|
|
145
|
+
return allMessages;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static async readLastMessageDatesByMembers(
|
|
149
|
+
guild: Guild,
|
|
150
|
+
channelName: string,
|
|
151
|
+
memberNames: string[]
|
|
152
|
+
): Promise<DyNTS_DiBo_LastMessageDate[]> {
|
|
153
|
+
const channel = this.findChannelByName(guild.channels, channelName)
|
|
154
|
+
|
|
155
|
+
if (!channel?.isTextBased()) {
|
|
156
|
+
DyFM_Log.error(`Channel is not text based "${channelName}"`)
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Prepare tracking for each member
|
|
161
|
+
const memberStatus: Record<string, { lastMessageDate: Date | null, allMessages: number }> = {};
|
|
162
|
+
memberNames.forEach(name => {
|
|
163
|
+
memberStatus[name] = { lastMessageDate: null, allMessages: 0 };
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
let lastId: string | undefined = undefined;
|
|
167
|
+
let done = false;
|
|
168
|
+
const cutoffTime = Date.now() - DyNTS_DiBo_global_settings.messageSettings.messageFetchTimeLimit;
|
|
169
|
+
let totalFetched = 0;
|
|
170
|
+
|
|
171
|
+
while (
|
|
172
|
+
!done &&
|
|
173
|
+
totalFetched < DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
174
|
+
) {
|
|
175
|
+
const options: any = { limit: 100 };
|
|
176
|
+
if (lastId) options.before = lastId;
|
|
177
|
+
const messages = await channel.messages.fetch(options) as unknown as Collection<string, Message<true>>;
|
|
178
|
+
if (messages.size === 0) break;
|
|
179
|
+
|
|
180
|
+
let shouldStop = false;
|
|
181
|
+
messages.forEach((message) => {
|
|
182
|
+
// Check if message is too old
|
|
183
|
+
if (message.createdTimestamp < cutoffTime) {
|
|
184
|
+
shouldStop = true;
|
|
185
|
+
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const author = message.author.username;
|
|
190
|
+
if (memberStatus[author] !== undefined) {
|
|
191
|
+
memberStatus[author].allMessages++;
|
|
192
|
+
|
|
193
|
+
// Only set lastMessageDate if not already set (since we fetch newest first)
|
|
194
|
+
if (!memberStatus[author].lastMessageDate) {
|
|
195
|
+
memberStatus[author].lastMessageDate = message.createdAt;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (shouldStop) {
|
|
201
|
+
DyFM_Log.warn('Reached time limit cutoff');
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Check if all members have a lastMessageDate
|
|
206
|
+
done = memberNames.every(name => memberStatus[name].lastMessageDate !== null);
|
|
207
|
+
lastId = messages.last()?.id;
|
|
208
|
+
totalFetched += messages.size;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (totalFetched >= DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit) {
|
|
212
|
+
DyFM_Log.warn(
|
|
213
|
+
'Reached maximum fetch count limit',
|
|
214
|
+
DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const lastMessageDatesByMembers: DyNTS_DiBo_LastMessageDate[] = memberNames.map((memberName) => {
|
|
219
|
+
const status = memberStatus[memberName];
|
|
220
|
+
if (!status.lastMessageDate) {
|
|
221
|
+
DyFM_Log.warn('No last message date found for member', memberName);
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
memberName: memberName,
|
|
225
|
+
allMessages: status.allMessages,
|
|
226
|
+
lastMessageDate: null/* new Date(0) */
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return ({
|
|
231
|
+
memberName: memberName,
|
|
232
|
+
allMessages: status.allMessages,
|
|
233
|
+
lastMessageDate: new Date(status.lastMessageDate)
|
|
234
|
+
})
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
return lastMessageDatesByMembers;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static async readLastMessageWithMemberNamePingInIt(
|
|
241
|
+
guild: Guild,
|
|
242
|
+
channelName: string,
|
|
243
|
+
members: Collection<string, GuildMember>
|
|
244
|
+
): Promise<DyNTS_DiBo_LastMentionDate[]> {
|
|
245
|
+
const channel = this.findChannelByName(guild.channels, channelName)
|
|
246
|
+
|
|
247
|
+
if (!channel?.isTextBased()) {
|
|
248
|
+
DyFM_Log.error(`Channel is not text based "${channelName}"`)
|
|
249
|
+
return []
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Prepare tracking for each member
|
|
253
|
+
const memberStatus: Record<string, { lastMentionDate: Date | null, allMentions: number }> = {};
|
|
254
|
+
members.forEach(member => {
|
|
255
|
+
memberStatus[member.user.username] = { lastMentionDate: null, allMentions: 0 };
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
let lastId: string | undefined = undefined;
|
|
259
|
+
let done = false;
|
|
260
|
+
const cutoffTime = Date.now() - DyNTS_DiBo_global_settings.messageSettings.messageFetchTimeLimit;
|
|
261
|
+
let totalFetched = 0;
|
|
262
|
+
|
|
263
|
+
while (
|
|
264
|
+
!done &&
|
|
265
|
+
totalFetched < DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
266
|
+
) {
|
|
267
|
+
const options: any = { limit: 100 };
|
|
268
|
+
if (lastId) options.before = lastId;
|
|
269
|
+
const messages = await channel.messages.fetch(options) as unknown as Collection<string, Message<true>>;
|
|
270
|
+
if (messages.size === 0) break;
|
|
271
|
+
|
|
272
|
+
let shouldStop = false;
|
|
273
|
+
messages.forEach((message) => {
|
|
274
|
+
// Check if message is too old
|
|
275
|
+
if (message.createdTimestamp < cutoffTime) {
|
|
276
|
+
shouldStop = true;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Check if message content contains "@Username" for any member
|
|
281
|
+
members.forEach(member => {
|
|
282
|
+
if (
|
|
283
|
+
message.content.includes(`@${member.user.id}`) &&
|
|
284
|
+
!memberStatus[member.user.username].lastMentionDate
|
|
285
|
+
) {
|
|
286
|
+
memberStatus[member.user.username].lastMentionDate = message.createdAt;
|
|
287
|
+
memberStatus[member.user.username].allMentions++;
|
|
288
|
+
DyFM_Log.success(
|
|
289
|
+
'Found message with member ping',
|
|
290
|
+
{
|
|
291
|
+
memberName: member.user.username,
|
|
292
|
+
messageId: message.id
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (shouldStop) {
|
|
300
|
+
DyFM_Log.warn('Reached time limit cutoff while searching for member pings');
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Check if all members have a lastMessageDate
|
|
305
|
+
done = members.every(member => memberStatus[member.user.username].lastMentionDate !== null);
|
|
306
|
+
lastId = messages.last()?.id;
|
|
307
|
+
totalFetched += messages.size;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (totalFetched >= DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit) {
|
|
311
|
+
DyFM_Log.warn(
|
|
312
|
+
'Reached maximum fetch count limit while searching for member pings',
|
|
313
|
+
DyNTS_DiBo_global_settings.messageSettings.messageFetchCountLimit
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const lastMentionDatesByMembers: DyNTS_DiBo_LastMentionDate[] = members.map((member) => {
|
|
318
|
+
const status = memberStatus[member.user.username];
|
|
319
|
+
if (!status.lastMentionDate) {
|
|
320
|
+
DyFM_Log.warn('No message found with member ping', member.user.username);
|
|
321
|
+
return {
|
|
322
|
+
memberId: member.user.id,
|
|
323
|
+
memberName: member.user.username,
|
|
324
|
+
allMentions: status.allMentions,
|
|
325
|
+
lastMentionDate: null/* new Date(0) */
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return ({
|
|
329
|
+
memberId: member.user.id,
|
|
330
|
+
memberName: member.user.username,
|
|
331
|
+
allMentions: status.allMentions,
|
|
332
|
+
lastMentionDate: new Date(status.lastMentionDate)
|
|
333
|
+
})
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return lastMentionDatesByMembers;
|
|
337
|
+
}
|
|
338
|
+
static readMentionsInChannel = this.readLastMessageWithMemberNamePingInIt
|
|
339
|
+
|
|
340
|
+
static async readLastMessagesInChannel(
|
|
341
|
+
guild: Guild,
|
|
342
|
+
channelName: string,
|
|
343
|
+
): Promise<Collection<string, Message<true>>> {
|
|
344
|
+
const channel = this.findChannelByName(guild.channels, channelName)
|
|
345
|
+
|
|
346
|
+
if (!channel?.isTextBased()) {
|
|
347
|
+
DyFM_Log.error(`Channel is not text based with name "${channelName}"`)
|
|
348
|
+
return
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const messages = await channel.messages.fetch({ limit: 100 })
|
|
352
|
+
|
|
353
|
+
return messages
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
static async getLastMessageInChannel(
|
|
357
|
+
guild: Guild,
|
|
358
|
+
channelName: string
|
|
359
|
+
): Promise<Message<true>> {
|
|
360
|
+
const channel = this.findChannelByName(guild.channels, channelName)
|
|
361
|
+
|
|
362
|
+
if (!channel?.isTextBased()) {
|
|
363
|
+
DyFM_Log.error(`Channel is not text based with name "${channelName}"`)
|
|
364
|
+
return
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const messages = await channel.messages.fetch({ limit: 1 })
|
|
368
|
+
|
|
369
|
+
return messages.first()
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
static getMemberIdByName(
|
|
373
|
+
members: Collection<string, GuildMember>,
|
|
374
|
+
username: string
|
|
375
|
+
): string | undefined {
|
|
376
|
+
const member = members.find(m => m.user.username === username);
|
|
377
|
+
return member ? member.user.id : undefined;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
static async deleteMessage(message: Message): Promise<void> {
|
|
381
|
+
await message.delete().catch((error) => {
|
|
382
|
+
DyFM_Error.logSimple('Failed to delete message', error);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
DyFM_Log.success('Message deleted:', message.content);
|
|
386
|
+
}
|
|
387
|
+
}
|