@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,572 +1,572 @@
|
|
|
1
|
-
import { DyNTS_SingletonService } from '../../../_services/base/singleton.service';
|
|
2
|
-
import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
3
|
-
import {
|
|
4
|
-
DyFM_Msg_Message,
|
|
5
|
-
DyFM_Msg_Conversation,
|
|
6
|
-
DyFM_Msg_Status,
|
|
7
|
-
DyFM_Msg_Reaction,
|
|
8
|
-
DyFM_Msg_Participant,
|
|
9
|
-
DyFM_Msg_ParticipantRole,
|
|
10
|
-
DyFM_Msg_Type,
|
|
11
|
-
DyFM_Msg_ConversationType,
|
|
12
|
-
} from '@futdevpro/fsm-dynamo/messaging';
|
|
13
|
-
|
|
14
|
-
import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
|
|
15
|
-
import { DyNTS_Msg_Message_DataService } from './msg-message.data-service';
|
|
16
|
-
import { DyNTS_Msg_Conversation_DataService } from './msg-conversation.data-service';
|
|
17
|
-
import { DyNTS_Msg_Events_Service } from './msg-events.service';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Main Messaging Control Service
|
|
21
|
-
* Handles all business logic for messaging operations
|
|
22
|
-
*/
|
|
23
|
-
export class DyNTS_Msg_Main_ControlService extends DyNTS_SingletonService {
|
|
24
|
-
|
|
25
|
-
static getInstance(): DyNTS_Msg_Main_ControlService {
|
|
26
|
-
return DyNTS_Msg_Main_ControlService.getSingletonInstance();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
private eventsService = DyNTS_Msg_Events_Service.getInstance();
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Send a message
|
|
33
|
-
*/
|
|
34
|
-
async sendMessage(
|
|
35
|
-
conversationId: string,
|
|
36
|
-
messageData: Partial<DyFM_Msg_Message>,
|
|
37
|
-
senderId: string,
|
|
38
|
-
issuer: string
|
|
39
|
-
): Promise<DyFM_Msg_Message> {
|
|
40
|
-
try {
|
|
41
|
-
if (!messageData?.content) {
|
|
42
|
-
throw new Error('Message content is required');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Create message
|
|
46
|
-
const message = new DyFM_Msg_Message({
|
|
47
|
-
conversationId: conversationId,
|
|
48
|
-
senderId: senderId,
|
|
49
|
-
content: messageData.content,
|
|
50
|
-
type: messageData.type || DyFM_Msg_Type.text,
|
|
51
|
-
status: DyFM_Msg_Status.sent,
|
|
52
|
-
sentAt: new Date(),
|
|
53
|
-
__createdBy: issuer,
|
|
54
|
-
__lastModifiedBy: issuer,
|
|
55
|
-
...messageData,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// Save message
|
|
59
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
60
|
-
message,
|
|
61
|
-
issuer,
|
|
62
|
-
});
|
|
63
|
-
await messageService.saveData(messageService.data, false, false);
|
|
64
|
-
|
|
65
|
-
// Update conversation last message
|
|
66
|
-
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
67
|
-
issuer,
|
|
68
|
-
});
|
|
69
|
-
await conversationService.updateLastMessage(
|
|
70
|
-
conversationId,
|
|
71
|
-
messageService.data._id!,
|
|
72
|
-
message.content.substring(0, 100)
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
// Emit event
|
|
76
|
-
this.eventsService.emitMessageSent(messageService.data, conversationId);
|
|
77
|
-
|
|
78
|
-
return messageService.data;
|
|
79
|
-
} catch (error) {
|
|
80
|
-
throw new DyFM_Error({
|
|
81
|
-
...this.getDefaultErrorSettings('sendMessage', error, issuer),
|
|
82
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-SM`,
|
|
83
|
-
userMessage: 'Failed to send message.',
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Edit a message
|
|
90
|
-
*/
|
|
91
|
-
async editMessage(
|
|
92
|
-
messageId: string,
|
|
93
|
-
content: string,
|
|
94
|
-
userId: string,
|
|
95
|
-
issuer: string
|
|
96
|
-
): Promise<DyFM_Msg_Message> {
|
|
97
|
-
try {
|
|
98
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
99
|
-
issuer,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const message = await messageService.getDataById(messageId);
|
|
103
|
-
|
|
104
|
-
if (!message) {
|
|
105
|
-
throw new Error('Message not found');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (message.senderId !== userId) {
|
|
109
|
-
throw new Error('Unauthorized: Only the message sender can edit it');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
message.content = content;
|
|
113
|
-
message.editedAt = new Date();
|
|
114
|
-
message.status = DyFM_Msg_Status.sent; // Keep as sent since edited is not a status
|
|
115
|
-
message.__lastModifiedBy = issuer;
|
|
116
|
-
|
|
117
|
-
await messageService.saveData(message, false, false);
|
|
118
|
-
|
|
119
|
-
// Emit event
|
|
120
|
-
this.eventsService.emitMessageUpdated(messageService.data, message.conversationId);
|
|
121
|
-
|
|
122
|
-
return messageService.data;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
throw new DyFM_Error({
|
|
125
|
-
...this.getDefaultErrorSettings('editMessage', error, issuer),
|
|
126
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-EM`,
|
|
127
|
-
userMessage: 'Failed to edit message.',
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async modifyMessage(message: DyFM_Msg_Message, issuer: string): Promise<DyFM_Msg_Message> {
|
|
133
|
-
try {
|
|
134
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
135
|
-
issuer,
|
|
136
|
-
});
|
|
137
|
-
await messageService.saveData(message);
|
|
138
|
-
|
|
139
|
-
// Emit event
|
|
140
|
-
this.eventsService.emitMessageUpdated(messageService.data, message.conversationId);
|
|
141
|
-
|
|
142
|
-
return messageService.data;
|
|
143
|
-
} catch (error) {
|
|
144
|
-
throw new DyFM_Error({
|
|
145
|
-
...this.getDefaultErrorSettings('modifyMessage', error, issuer),
|
|
146
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-MM`,
|
|
147
|
-
userMessage: 'Failed to modify message.',
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Delete a message
|
|
154
|
-
*/
|
|
155
|
-
async deleteMessage(
|
|
156
|
-
messageId: string,
|
|
157
|
-
userId: string,
|
|
158
|
-
issuer: string
|
|
159
|
-
): Promise<void> {
|
|
160
|
-
try {
|
|
161
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
162
|
-
issuer,
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const message = await messageService.getDataById(messageId);
|
|
166
|
-
|
|
167
|
-
if (!message) {
|
|
168
|
-
throw new Error('Message not found');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (message.senderId !== userId) {
|
|
172
|
-
throw new Error('Unauthorized: Only the message sender can delete it');
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const conversationId = message.conversationId;
|
|
176
|
-
await messageService.deleteData(messageId);
|
|
177
|
-
|
|
178
|
-
// Emit event
|
|
179
|
-
this.eventsService.emitMessageDeleted(messageId, conversationId);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
throw new DyFM_Error({
|
|
182
|
-
...this.getDefaultErrorSettings('deleteMessage', error, issuer),
|
|
183
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-DM`,
|
|
184
|
-
userMessage: 'Failed to delete message.',
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Mark messages as read
|
|
191
|
-
*/
|
|
192
|
-
async markMessagesAsRead(
|
|
193
|
-
messageIds: string[],
|
|
194
|
-
userId: string,
|
|
195
|
-
issuer: string
|
|
196
|
-
): Promise<{ success: boolean; count: number }> {
|
|
197
|
-
try {
|
|
198
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
199
|
-
issuer,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
for (const messageId of messageIds) {
|
|
203
|
-
await messageService.markAsRead(messageId, userId);
|
|
204
|
-
|
|
205
|
-
// Get message to get conversationId for event
|
|
206
|
-
const message = await messageService.getDataById(messageId);
|
|
207
|
-
this.eventsService.emitMessageRead(messageId, userId, message.conversationId);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return { success: true, count: messageIds.length };
|
|
211
|
-
} catch (error) {
|
|
212
|
-
throw new DyFM_Error({
|
|
213
|
-
...this.getDefaultErrorSettings('markMessagesAsRead', error, issuer),
|
|
214
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-MAR`,
|
|
215
|
-
userMessage: 'Failed to mark messages as read.',
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Add reaction to message
|
|
222
|
-
*/
|
|
223
|
-
async addReaction(
|
|
224
|
-
messageId: string,
|
|
225
|
-
emoji: string,
|
|
226
|
-
userId: string,
|
|
227
|
-
issuer: string
|
|
228
|
-
): Promise<DyFM_Msg_Message> {
|
|
229
|
-
try {
|
|
230
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
231
|
-
issuer,
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
const message = await messageService.getDataById(messageId);
|
|
235
|
-
|
|
236
|
-
if (!message) {
|
|
237
|
-
throw new Error('Message not found');
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (!message.reactions) {
|
|
241
|
-
message.reactions = [];
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Check if user already reacted with this emoji
|
|
245
|
-
const existingReaction = message.reactions.find((r: any) => r.emoji === emoji && r.userId === userId);
|
|
246
|
-
|
|
247
|
-
if (!existingReaction) {
|
|
248
|
-
const newReaction = {
|
|
249
|
-
emoji,
|
|
250
|
-
userId,
|
|
251
|
-
reactedAt: new Date(),
|
|
252
|
-
} as any;
|
|
253
|
-
message.reactions.push(newReaction);
|
|
254
|
-
|
|
255
|
-
await messageService.saveData(message, false, false);
|
|
256
|
-
|
|
257
|
-
// Emit event
|
|
258
|
-
this.eventsService.emitReactionAdded(messageId, newReaction);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return messageService.data;
|
|
262
|
-
} catch (error) {
|
|
263
|
-
throw new DyFM_Error({
|
|
264
|
-
...this.getDefaultErrorSettings('addReaction', error, issuer),
|
|
265
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-AR`,
|
|
266
|
-
userMessage: 'Failed to add reaction.',
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Remove reaction from message
|
|
273
|
-
*/
|
|
274
|
-
async removeReaction(
|
|
275
|
-
messageId: string,
|
|
276
|
-
emoji: string,
|
|
277
|
-
userId: string,
|
|
278
|
-
issuer: string
|
|
279
|
-
): Promise<DyFM_Msg_Message> {
|
|
280
|
-
try {
|
|
281
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
282
|
-
issuer,
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
const message = await messageService.getDataById(messageId);
|
|
286
|
-
|
|
287
|
-
if (!message) {
|
|
288
|
-
throw new Error('Message not found');
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (!message.reactions) {
|
|
292
|
-
message.reactions = [];
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Remove user's reaction with this emoji
|
|
296
|
-
const initialLength = message.reactions.length;
|
|
297
|
-
message.reactions = message.reactions.filter((r: any) => !(r.emoji === emoji && r.userId === userId));
|
|
298
|
-
|
|
299
|
-
if (message.reactions.length < initialLength) {
|
|
300
|
-
await messageService.saveData(message, false, false);
|
|
301
|
-
|
|
302
|
-
// Emit event
|
|
303
|
-
this.eventsService.emitReactionRemoved(messageId, userId, emoji);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return messageService.data;
|
|
307
|
-
} catch (error) {
|
|
308
|
-
throw new DyFM_Error({
|
|
309
|
-
...this.getDefaultErrorSettings('removeReaction', error, issuer),
|
|
310
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-RR`,
|
|
311
|
-
userMessage: 'Failed to remove reaction.',
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Create conversation
|
|
318
|
-
*/
|
|
319
|
-
async createConversation(
|
|
320
|
-
conversationData: Partial<DyFM_Msg_Conversation>,
|
|
321
|
-
creatorId: string,
|
|
322
|
-
issuer: string
|
|
323
|
-
): Promise<DyFM_Msg_Conversation> {
|
|
324
|
-
try {
|
|
325
|
-
// Ensure creator is in participants
|
|
326
|
-
if (!conversationData.participants?.some(p => p.userId === creatorId)) {
|
|
327
|
-
if (!conversationData.participants) {
|
|
328
|
-
conversationData.participants = [];
|
|
329
|
-
}
|
|
330
|
-
conversationData.participants.push({
|
|
331
|
-
userId: creatorId,
|
|
332
|
-
role: DyFM_Msg_ParticipantRole.owner,
|
|
333
|
-
joinedAt: new Date(),
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const conversation = new DyFM_Msg_Conversation({
|
|
338
|
-
type: conversationData.type || DyFM_Msg_ConversationType.direct,
|
|
339
|
-
participants: conversationData.participants || [],
|
|
340
|
-
__createdBy: issuer,
|
|
341
|
-
__lastModifiedBy: issuer,
|
|
342
|
-
...conversationData,
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
346
|
-
conversation,
|
|
347
|
-
issuer,
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
await conversationService.saveData(conversationService.data, false, false);
|
|
351
|
-
|
|
352
|
-
// Emit event
|
|
353
|
-
const participantIds = conversationService.data.participants?.map(p => p.userId) || [];
|
|
354
|
-
this.eventsService.emitConversationCreated(conversationService.data, participantIds);
|
|
355
|
-
|
|
356
|
-
return conversationService.data;
|
|
357
|
-
} catch (error) {
|
|
358
|
-
throw new DyFM_Error({
|
|
359
|
-
...this.getDefaultErrorSettings('createConversation', error, issuer),
|
|
360
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-CC`,
|
|
361
|
-
userMessage: 'Failed to create conversation.',
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Update conversation
|
|
368
|
-
*/
|
|
369
|
-
async updateConversation(
|
|
370
|
-
conversationId: string,
|
|
371
|
-
updateData: Partial<DyFM_Msg_Conversation>,
|
|
372
|
-
userId: string,
|
|
373
|
-
issuer: string
|
|
374
|
-
): Promise<DyFM_Msg_Conversation> {
|
|
375
|
-
try {
|
|
376
|
-
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
377
|
-
issuer,
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
const conversation = await conversationService.getDataById(conversationId);
|
|
381
|
-
|
|
382
|
-
if (!conversation) {
|
|
383
|
-
throw new Error('Conversation not found');
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Check if user is participant
|
|
387
|
-
const isParticipant = conversation.participants?.some(p => p.userId === userId);
|
|
388
|
-
if (!isParticipant) {
|
|
389
|
-
throw new Error('Unauthorized: User is not a participant in this conversation');
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
Object.assign(conversation, updateData);
|
|
393
|
-
conversation.__lastModifiedBy = issuer;
|
|
394
|
-
|
|
395
|
-
await conversationService.saveData(conversation, false, false);
|
|
396
|
-
|
|
397
|
-
// Emit event
|
|
398
|
-
this.eventsService.emitConversationUpdated(conversationService.data);
|
|
399
|
-
|
|
400
|
-
return conversationService.data;
|
|
401
|
-
} catch (error) {
|
|
402
|
-
throw new DyFM_Error({
|
|
403
|
-
...this.getDefaultErrorSettings('updateConversation', error, issuer),
|
|
404
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-UC`,
|
|
405
|
-
userMessage: 'Failed to update conversation.',
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Delete conversation
|
|
412
|
-
*/
|
|
413
|
-
async deleteConversation(
|
|
414
|
-
conversationId: string,
|
|
415
|
-
userId: string,
|
|
416
|
-
issuer: string
|
|
417
|
-
): Promise<void> {
|
|
418
|
-
try {
|
|
419
|
-
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
420
|
-
issuer,
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
const conversation = await conversationService.getDataById(conversationId);
|
|
424
|
-
|
|
425
|
-
if (!conversation) {
|
|
426
|
-
throw new Error('Conversation not found');
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Check if user is owner or admin
|
|
430
|
-
const isOwnerOrAdmin = conversation.participants?.some(p =>
|
|
431
|
-
p.userId === userId && (p.role === DyFM_Msg_ParticipantRole.owner || p.role === DyFM_Msg_ParticipantRole.admin)
|
|
432
|
-
);
|
|
433
|
-
if (!isOwnerOrAdmin) {
|
|
434
|
-
throw new Error('Unauthorized: Only owners or admins can delete conversations');
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
await conversationService.deleteData(conversationId);
|
|
438
|
-
|
|
439
|
-
// Emit event
|
|
440
|
-
this.eventsService.emitConversationDeleted(conversationId);
|
|
441
|
-
} catch (error) {
|
|
442
|
-
throw new DyFM_Error({
|
|
443
|
-
...this.getDefaultErrorSettings('deleteConversation', error, issuer),
|
|
444
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-DC`,
|
|
445
|
-
userMessage: 'Failed to delete conversation.',
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Add participant to conversation
|
|
452
|
-
*/
|
|
453
|
-
async addParticipant(
|
|
454
|
-
conversationId: string,
|
|
455
|
-
newUserId: string,
|
|
456
|
-
role: DyFM_Msg_ParticipantRole = DyFM_Msg_ParticipantRole.member,
|
|
457
|
-
requesterId: string,
|
|
458
|
-
issuer: string
|
|
459
|
-
): Promise<void> {
|
|
460
|
-
try {
|
|
461
|
-
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
462
|
-
issuer,
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
const conversation = await conversationService.getDataById(conversationId);
|
|
466
|
-
|
|
467
|
-
if (!conversation) {
|
|
468
|
-
throw new Error('Conversation not found');
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Check if requester is owner or admin
|
|
472
|
-
const isOwnerOrAdmin = conversation.participants?.some(p =>
|
|
473
|
-
p.userId === requesterId && (p.role === DyFM_Msg_ParticipantRole.owner || p.role === DyFM_Msg_ParticipantRole.admin)
|
|
474
|
-
);
|
|
475
|
-
if (!isOwnerOrAdmin) {
|
|
476
|
-
throw new Error('Unauthorized: Only owners or admins can add participants');
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
const newParticipant: DyFM_Msg_Participant = {
|
|
480
|
-
userId: newUserId,
|
|
481
|
-
role,
|
|
482
|
-
joinedAt: new Date(),
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
await conversationService.addParticipant(conversationId, newParticipant);
|
|
486
|
-
|
|
487
|
-
// Emit event
|
|
488
|
-
this.eventsService.emitParticipantAdded(conversationId, newUserId);
|
|
489
|
-
} catch (error) {
|
|
490
|
-
throw new DyFM_Error({
|
|
491
|
-
...this.getDefaultErrorSettings('addParticipant', error, issuer),
|
|
492
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-AP`,
|
|
493
|
-
userMessage: 'Failed to add participant.',
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Remove participant from conversation
|
|
500
|
-
*/
|
|
501
|
-
async removeParticipant(
|
|
502
|
-
conversationId: string,
|
|
503
|
-
userIdToRemove: string,
|
|
504
|
-
requesterId: string,
|
|
505
|
-
issuer: string
|
|
506
|
-
): Promise<void> {
|
|
507
|
-
try {
|
|
508
|
-
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
509
|
-
issuer,
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
const conversation = await conversationService.getDataById(conversationId);
|
|
513
|
-
|
|
514
|
-
if (!conversation) {
|
|
515
|
-
throw new Error('Conversation not found');
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Check if requester is owner or admin, or removing themselves
|
|
519
|
-
const isOwnerOrAdmin = conversation.participants?.some(p =>
|
|
520
|
-
p.userId === requesterId && (p.role === DyFM_Msg_ParticipantRole.owner || p.role === DyFM_Msg_ParticipantRole.admin)
|
|
521
|
-
);
|
|
522
|
-
const isSelfRemoval = requesterId === userIdToRemove;
|
|
523
|
-
|
|
524
|
-
if (!isOwnerOrAdmin && !isSelfRemoval) {
|
|
525
|
-
throw new Error('Unauthorized: Only owners, admins, or the user themselves can remove participants');
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
await conversationService.removeParticipant(conversationId, userIdToRemove);
|
|
529
|
-
|
|
530
|
-
// Emit event
|
|
531
|
-
this.eventsService.emitParticipantRemoved(conversationId, userIdToRemove);
|
|
532
|
-
} catch (error) {
|
|
533
|
-
throw new DyFM_Error({
|
|
534
|
-
...this.getDefaultErrorSettings('removeParticipant', error, issuer),
|
|
535
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-RP`,
|
|
536
|
-
userMessage: 'Failed to remove participant.',
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Get agent process steps for a message
|
|
543
|
-
*/
|
|
544
|
-
async getAgentProcessSteps(
|
|
545
|
-
messageId: string,
|
|
546
|
-
issuer: string
|
|
547
|
-
): Promise<any[]> {
|
|
548
|
-
try {
|
|
549
|
-
const messageService = new DyNTS_Msg_Message_DataService({
|
|
550
|
-
issuer,
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
const message = await messageService.getDataById(messageId);
|
|
554
|
-
|
|
555
|
-
if (!message) {
|
|
556
|
-
throw new Error('Message not found');
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
if (!message.agentProcessSteps) {
|
|
560
|
-
throw new Error('No agent process steps found for this message');
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
return message.agentProcessSteps;
|
|
564
|
-
} catch (error) {
|
|
565
|
-
throw new DyFM_Error({
|
|
566
|
-
...this.getDefaultErrorSettings('getAgentProcessSteps', error, issuer),
|
|
567
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-GAPS`,
|
|
568
|
-
userMessage: 'Failed to get agent process steps.',
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
}
|
|
1
|
+
import { DyNTS_SingletonService } from '../../../_services/base/singleton.service';
|
|
2
|
+
import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
3
|
+
import {
|
|
4
|
+
DyFM_Msg_Message,
|
|
5
|
+
DyFM_Msg_Conversation,
|
|
6
|
+
DyFM_Msg_Status,
|
|
7
|
+
DyFM_Msg_Reaction,
|
|
8
|
+
DyFM_Msg_Participant,
|
|
9
|
+
DyFM_Msg_ParticipantRole,
|
|
10
|
+
DyFM_Msg_Type,
|
|
11
|
+
DyFM_Msg_ConversationType,
|
|
12
|
+
} from '@futdevpro/fsm-dynamo/messaging';
|
|
13
|
+
|
|
14
|
+
import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
|
|
15
|
+
import { DyNTS_Msg_Message_DataService } from './msg-message.data-service';
|
|
16
|
+
import { DyNTS_Msg_Conversation_DataService } from './msg-conversation.data-service';
|
|
17
|
+
import { DyNTS_Msg_Events_Service } from './msg-events.service';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Main Messaging Control Service
|
|
21
|
+
* Handles all business logic for messaging operations
|
|
22
|
+
*/
|
|
23
|
+
export class DyNTS_Msg_Main_ControlService extends DyNTS_SingletonService {
|
|
24
|
+
|
|
25
|
+
static getInstance(): DyNTS_Msg_Main_ControlService {
|
|
26
|
+
return DyNTS_Msg_Main_ControlService.getSingletonInstance();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private eventsService = DyNTS_Msg_Events_Service.getInstance();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Send a message
|
|
33
|
+
*/
|
|
34
|
+
async sendMessage(
|
|
35
|
+
conversationId: string,
|
|
36
|
+
messageData: Partial<DyFM_Msg_Message>,
|
|
37
|
+
senderId: string,
|
|
38
|
+
issuer: string
|
|
39
|
+
): Promise<DyFM_Msg_Message> {
|
|
40
|
+
try {
|
|
41
|
+
if (!messageData?.content) {
|
|
42
|
+
throw new Error('Message content is required');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Create message
|
|
46
|
+
const message = new DyFM_Msg_Message({
|
|
47
|
+
conversationId: conversationId,
|
|
48
|
+
senderId: senderId,
|
|
49
|
+
content: messageData.content,
|
|
50
|
+
type: messageData.type || DyFM_Msg_Type.text,
|
|
51
|
+
status: DyFM_Msg_Status.sent,
|
|
52
|
+
sentAt: new Date(),
|
|
53
|
+
__createdBy: issuer,
|
|
54
|
+
__lastModifiedBy: issuer,
|
|
55
|
+
...messageData,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Save message
|
|
59
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
60
|
+
message,
|
|
61
|
+
issuer,
|
|
62
|
+
});
|
|
63
|
+
await messageService.saveData(messageService.data, false, false);
|
|
64
|
+
|
|
65
|
+
// Update conversation last message
|
|
66
|
+
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
67
|
+
issuer,
|
|
68
|
+
});
|
|
69
|
+
await conversationService.updateLastMessage(
|
|
70
|
+
conversationId,
|
|
71
|
+
messageService.data._id!,
|
|
72
|
+
message.content.substring(0, 100)
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Emit event
|
|
76
|
+
this.eventsService.emitMessageSent(messageService.data, conversationId);
|
|
77
|
+
|
|
78
|
+
return messageService.data;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
throw new DyFM_Error({
|
|
81
|
+
...this.getDefaultErrorSettings('sendMessage', error, issuer),
|
|
82
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-SM`,
|
|
83
|
+
userMessage: 'Failed to send message.',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Edit a message
|
|
90
|
+
*/
|
|
91
|
+
async editMessage(
|
|
92
|
+
messageId: string,
|
|
93
|
+
content: string,
|
|
94
|
+
userId: string,
|
|
95
|
+
issuer: string
|
|
96
|
+
): Promise<DyFM_Msg_Message> {
|
|
97
|
+
try {
|
|
98
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
99
|
+
issuer,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const message = await messageService.getDataById(messageId);
|
|
103
|
+
|
|
104
|
+
if (!message) {
|
|
105
|
+
throw new Error('Message not found');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (message.senderId !== userId) {
|
|
109
|
+
throw new Error('Unauthorized: Only the message sender can edit it');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
message.content = content;
|
|
113
|
+
message.editedAt = new Date();
|
|
114
|
+
message.status = DyFM_Msg_Status.sent; // Keep as sent since edited is not a status
|
|
115
|
+
message.__lastModifiedBy = issuer;
|
|
116
|
+
|
|
117
|
+
await messageService.saveData(message, false, false);
|
|
118
|
+
|
|
119
|
+
// Emit event
|
|
120
|
+
this.eventsService.emitMessageUpdated(messageService.data, message.conversationId);
|
|
121
|
+
|
|
122
|
+
return messageService.data;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
throw new DyFM_Error({
|
|
125
|
+
...this.getDefaultErrorSettings('editMessage', error, issuer),
|
|
126
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-EM`,
|
|
127
|
+
userMessage: 'Failed to edit message.',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async modifyMessage(message: DyFM_Msg_Message, issuer: string): Promise<DyFM_Msg_Message> {
|
|
133
|
+
try {
|
|
134
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
135
|
+
issuer,
|
|
136
|
+
});
|
|
137
|
+
await messageService.saveData(message);
|
|
138
|
+
|
|
139
|
+
// Emit event
|
|
140
|
+
this.eventsService.emitMessageUpdated(messageService.data, message.conversationId);
|
|
141
|
+
|
|
142
|
+
return messageService.data;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
throw new DyFM_Error({
|
|
145
|
+
...this.getDefaultErrorSettings('modifyMessage', error, issuer),
|
|
146
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-MM`,
|
|
147
|
+
userMessage: 'Failed to modify message.',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Delete a message
|
|
154
|
+
*/
|
|
155
|
+
async deleteMessage(
|
|
156
|
+
messageId: string,
|
|
157
|
+
userId: string,
|
|
158
|
+
issuer: string
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
try {
|
|
161
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
162
|
+
issuer,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const message = await messageService.getDataById(messageId);
|
|
166
|
+
|
|
167
|
+
if (!message) {
|
|
168
|
+
throw new Error('Message not found');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (message.senderId !== userId) {
|
|
172
|
+
throw new Error('Unauthorized: Only the message sender can delete it');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const conversationId = message.conversationId;
|
|
176
|
+
await messageService.deleteData(messageId);
|
|
177
|
+
|
|
178
|
+
// Emit event
|
|
179
|
+
this.eventsService.emitMessageDeleted(messageId, conversationId);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw new DyFM_Error({
|
|
182
|
+
...this.getDefaultErrorSettings('deleteMessage', error, issuer),
|
|
183
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-DM`,
|
|
184
|
+
userMessage: 'Failed to delete message.',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Mark messages as read
|
|
191
|
+
*/
|
|
192
|
+
async markMessagesAsRead(
|
|
193
|
+
messageIds: string[],
|
|
194
|
+
userId: string,
|
|
195
|
+
issuer: string
|
|
196
|
+
): Promise<{ success: boolean; count: number }> {
|
|
197
|
+
try {
|
|
198
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
199
|
+
issuer,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
for (const messageId of messageIds) {
|
|
203
|
+
await messageService.markAsRead(messageId, userId);
|
|
204
|
+
|
|
205
|
+
// Get message to get conversationId for event
|
|
206
|
+
const message = await messageService.getDataById(messageId);
|
|
207
|
+
this.eventsService.emitMessageRead(messageId, userId, message.conversationId);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { success: true, count: messageIds.length };
|
|
211
|
+
} catch (error) {
|
|
212
|
+
throw new DyFM_Error({
|
|
213
|
+
...this.getDefaultErrorSettings('markMessagesAsRead', error, issuer),
|
|
214
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-MAR`,
|
|
215
|
+
userMessage: 'Failed to mark messages as read.',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Add reaction to message
|
|
222
|
+
*/
|
|
223
|
+
async addReaction(
|
|
224
|
+
messageId: string,
|
|
225
|
+
emoji: string,
|
|
226
|
+
userId: string,
|
|
227
|
+
issuer: string
|
|
228
|
+
): Promise<DyFM_Msg_Message> {
|
|
229
|
+
try {
|
|
230
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
231
|
+
issuer,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const message = await messageService.getDataById(messageId);
|
|
235
|
+
|
|
236
|
+
if (!message) {
|
|
237
|
+
throw new Error('Message not found');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!message.reactions) {
|
|
241
|
+
message.reactions = [];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Check if user already reacted with this emoji
|
|
245
|
+
const existingReaction = message.reactions.find((r: any) => r.emoji === emoji && r.userId === userId);
|
|
246
|
+
|
|
247
|
+
if (!existingReaction) {
|
|
248
|
+
const newReaction = {
|
|
249
|
+
emoji,
|
|
250
|
+
userId,
|
|
251
|
+
reactedAt: new Date(),
|
|
252
|
+
} as any;
|
|
253
|
+
message.reactions.push(newReaction);
|
|
254
|
+
|
|
255
|
+
await messageService.saveData(message, false, false);
|
|
256
|
+
|
|
257
|
+
// Emit event
|
|
258
|
+
this.eventsService.emitReactionAdded(messageId, newReaction);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return messageService.data;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
throw new DyFM_Error({
|
|
264
|
+
...this.getDefaultErrorSettings('addReaction', error, issuer),
|
|
265
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-AR`,
|
|
266
|
+
userMessage: 'Failed to add reaction.',
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Remove reaction from message
|
|
273
|
+
*/
|
|
274
|
+
async removeReaction(
|
|
275
|
+
messageId: string,
|
|
276
|
+
emoji: string,
|
|
277
|
+
userId: string,
|
|
278
|
+
issuer: string
|
|
279
|
+
): Promise<DyFM_Msg_Message> {
|
|
280
|
+
try {
|
|
281
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
282
|
+
issuer,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const message = await messageService.getDataById(messageId);
|
|
286
|
+
|
|
287
|
+
if (!message) {
|
|
288
|
+
throw new Error('Message not found');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!message.reactions) {
|
|
292
|
+
message.reactions = [];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Remove user's reaction with this emoji
|
|
296
|
+
const initialLength = message.reactions.length;
|
|
297
|
+
message.reactions = message.reactions.filter((r: any) => !(r.emoji === emoji && r.userId === userId));
|
|
298
|
+
|
|
299
|
+
if (message.reactions.length < initialLength) {
|
|
300
|
+
await messageService.saveData(message, false, false);
|
|
301
|
+
|
|
302
|
+
// Emit event
|
|
303
|
+
this.eventsService.emitReactionRemoved(messageId, userId, emoji);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return messageService.data;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
throw new DyFM_Error({
|
|
309
|
+
...this.getDefaultErrorSettings('removeReaction', error, issuer),
|
|
310
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-RR`,
|
|
311
|
+
userMessage: 'Failed to remove reaction.',
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Create conversation
|
|
318
|
+
*/
|
|
319
|
+
async createConversation(
|
|
320
|
+
conversationData: Partial<DyFM_Msg_Conversation>,
|
|
321
|
+
creatorId: string,
|
|
322
|
+
issuer: string
|
|
323
|
+
): Promise<DyFM_Msg_Conversation> {
|
|
324
|
+
try {
|
|
325
|
+
// Ensure creator is in participants
|
|
326
|
+
if (!conversationData.participants?.some(p => p.userId === creatorId)) {
|
|
327
|
+
if (!conversationData.participants) {
|
|
328
|
+
conversationData.participants = [];
|
|
329
|
+
}
|
|
330
|
+
conversationData.participants.push({
|
|
331
|
+
userId: creatorId,
|
|
332
|
+
role: DyFM_Msg_ParticipantRole.owner,
|
|
333
|
+
joinedAt: new Date(),
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const conversation = new DyFM_Msg_Conversation({
|
|
338
|
+
type: conversationData.type || DyFM_Msg_ConversationType.direct,
|
|
339
|
+
participants: conversationData.participants || [],
|
|
340
|
+
__createdBy: issuer,
|
|
341
|
+
__lastModifiedBy: issuer,
|
|
342
|
+
...conversationData,
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
346
|
+
conversation,
|
|
347
|
+
issuer,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
await conversationService.saveData(conversationService.data, false, false);
|
|
351
|
+
|
|
352
|
+
// Emit event
|
|
353
|
+
const participantIds = conversationService.data.participants?.map(p => p.userId) || [];
|
|
354
|
+
this.eventsService.emitConversationCreated(conversationService.data, participantIds);
|
|
355
|
+
|
|
356
|
+
return conversationService.data;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
throw new DyFM_Error({
|
|
359
|
+
...this.getDefaultErrorSettings('createConversation', error, issuer),
|
|
360
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-CC`,
|
|
361
|
+
userMessage: 'Failed to create conversation.',
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Update conversation
|
|
368
|
+
*/
|
|
369
|
+
async updateConversation(
|
|
370
|
+
conversationId: string,
|
|
371
|
+
updateData: Partial<DyFM_Msg_Conversation>,
|
|
372
|
+
userId: string,
|
|
373
|
+
issuer: string
|
|
374
|
+
): Promise<DyFM_Msg_Conversation> {
|
|
375
|
+
try {
|
|
376
|
+
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
377
|
+
issuer,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const conversation = await conversationService.getDataById(conversationId);
|
|
381
|
+
|
|
382
|
+
if (!conversation) {
|
|
383
|
+
throw new Error('Conversation not found');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Check if user is participant
|
|
387
|
+
const isParticipant = conversation.participants?.some(p => p.userId === userId);
|
|
388
|
+
if (!isParticipant) {
|
|
389
|
+
throw new Error('Unauthorized: User is not a participant in this conversation');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
Object.assign(conversation, updateData);
|
|
393
|
+
conversation.__lastModifiedBy = issuer;
|
|
394
|
+
|
|
395
|
+
await conversationService.saveData(conversation, false, false);
|
|
396
|
+
|
|
397
|
+
// Emit event
|
|
398
|
+
this.eventsService.emitConversationUpdated(conversationService.data);
|
|
399
|
+
|
|
400
|
+
return conversationService.data;
|
|
401
|
+
} catch (error) {
|
|
402
|
+
throw new DyFM_Error({
|
|
403
|
+
...this.getDefaultErrorSettings('updateConversation', error, issuer),
|
|
404
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-UC`,
|
|
405
|
+
userMessage: 'Failed to update conversation.',
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Delete conversation
|
|
412
|
+
*/
|
|
413
|
+
async deleteConversation(
|
|
414
|
+
conversationId: string,
|
|
415
|
+
userId: string,
|
|
416
|
+
issuer: string
|
|
417
|
+
): Promise<void> {
|
|
418
|
+
try {
|
|
419
|
+
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
420
|
+
issuer,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const conversation = await conversationService.getDataById(conversationId);
|
|
424
|
+
|
|
425
|
+
if (!conversation) {
|
|
426
|
+
throw new Error('Conversation not found');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Check if user is owner or admin
|
|
430
|
+
const isOwnerOrAdmin = conversation.participants?.some(p =>
|
|
431
|
+
p.userId === userId && (p.role === DyFM_Msg_ParticipantRole.owner || p.role === DyFM_Msg_ParticipantRole.admin)
|
|
432
|
+
);
|
|
433
|
+
if (!isOwnerOrAdmin) {
|
|
434
|
+
throw new Error('Unauthorized: Only owners or admins can delete conversations');
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
await conversationService.deleteData(conversationId);
|
|
438
|
+
|
|
439
|
+
// Emit event
|
|
440
|
+
this.eventsService.emitConversationDeleted(conversationId);
|
|
441
|
+
} catch (error) {
|
|
442
|
+
throw new DyFM_Error({
|
|
443
|
+
...this.getDefaultErrorSettings('deleteConversation', error, issuer),
|
|
444
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-DC`,
|
|
445
|
+
userMessage: 'Failed to delete conversation.',
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Add participant to conversation
|
|
452
|
+
*/
|
|
453
|
+
async addParticipant(
|
|
454
|
+
conversationId: string,
|
|
455
|
+
newUserId: string,
|
|
456
|
+
role: DyFM_Msg_ParticipantRole = DyFM_Msg_ParticipantRole.member,
|
|
457
|
+
requesterId: string,
|
|
458
|
+
issuer: string
|
|
459
|
+
): Promise<void> {
|
|
460
|
+
try {
|
|
461
|
+
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
462
|
+
issuer,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
const conversation = await conversationService.getDataById(conversationId);
|
|
466
|
+
|
|
467
|
+
if (!conversation) {
|
|
468
|
+
throw new Error('Conversation not found');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Check if requester is owner or admin
|
|
472
|
+
const isOwnerOrAdmin = conversation.participants?.some(p =>
|
|
473
|
+
p.userId === requesterId && (p.role === DyFM_Msg_ParticipantRole.owner || p.role === DyFM_Msg_ParticipantRole.admin)
|
|
474
|
+
);
|
|
475
|
+
if (!isOwnerOrAdmin) {
|
|
476
|
+
throw new Error('Unauthorized: Only owners or admins can add participants');
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const newParticipant: DyFM_Msg_Participant = {
|
|
480
|
+
userId: newUserId,
|
|
481
|
+
role,
|
|
482
|
+
joinedAt: new Date(),
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
await conversationService.addParticipant(conversationId, newParticipant);
|
|
486
|
+
|
|
487
|
+
// Emit event
|
|
488
|
+
this.eventsService.emitParticipantAdded(conversationId, newUserId);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
throw new DyFM_Error({
|
|
491
|
+
...this.getDefaultErrorSettings('addParticipant', error, issuer),
|
|
492
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-AP`,
|
|
493
|
+
userMessage: 'Failed to add participant.',
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Remove participant from conversation
|
|
500
|
+
*/
|
|
501
|
+
async removeParticipant(
|
|
502
|
+
conversationId: string,
|
|
503
|
+
userIdToRemove: string,
|
|
504
|
+
requesterId: string,
|
|
505
|
+
issuer: string
|
|
506
|
+
): Promise<void> {
|
|
507
|
+
try {
|
|
508
|
+
const conversationService = new DyNTS_Msg_Conversation_DataService({
|
|
509
|
+
issuer,
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
const conversation = await conversationService.getDataById(conversationId);
|
|
513
|
+
|
|
514
|
+
if (!conversation) {
|
|
515
|
+
throw new Error('Conversation not found');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Check if requester is owner or admin, or removing themselves
|
|
519
|
+
const isOwnerOrAdmin = conversation.participants?.some(p =>
|
|
520
|
+
p.userId === requesterId && (p.role === DyFM_Msg_ParticipantRole.owner || p.role === DyFM_Msg_ParticipantRole.admin)
|
|
521
|
+
);
|
|
522
|
+
const isSelfRemoval = requesterId === userIdToRemove;
|
|
523
|
+
|
|
524
|
+
if (!isOwnerOrAdmin && !isSelfRemoval) {
|
|
525
|
+
throw new Error('Unauthorized: Only owners, admins, or the user themselves can remove participants');
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
await conversationService.removeParticipant(conversationId, userIdToRemove);
|
|
529
|
+
|
|
530
|
+
// Emit event
|
|
531
|
+
this.eventsService.emitParticipantRemoved(conversationId, userIdToRemove);
|
|
532
|
+
} catch (error) {
|
|
533
|
+
throw new DyFM_Error({
|
|
534
|
+
...this.getDefaultErrorSettings('removeParticipant', error, issuer),
|
|
535
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-RP`,
|
|
536
|
+
userMessage: 'Failed to remove participant.',
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Get agent process steps for a message
|
|
543
|
+
*/
|
|
544
|
+
async getAgentProcessSteps(
|
|
545
|
+
messageId: string,
|
|
546
|
+
issuer: string
|
|
547
|
+
): Promise<any[]> {
|
|
548
|
+
try {
|
|
549
|
+
const messageService = new DyNTS_Msg_Message_DataService({
|
|
550
|
+
issuer,
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
const message = await messageService.getDataById(messageId);
|
|
554
|
+
|
|
555
|
+
if (!message) {
|
|
556
|
+
throw new Error('Message not found');
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (!message.agentProcessSteps) {
|
|
560
|
+
throw new Error('No agent process steps found for this message');
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return message.agentProcessSteps;
|
|
564
|
+
} catch (error) {
|
|
565
|
+
throw new DyFM_Error({
|
|
566
|
+
...this.getDefaultErrorSettings('getAgentProcessSteps', error, issuer),
|
|
567
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-MSG-GAPS`,
|
|
568
|
+
userMessage: 'Failed to get agent process steps.',
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
572
|
}
|