@talkpilot/core-db 1.3.66 → 1.3.68
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/.cursor/rules/development.mdc +65 -65
- package/AGENTS.md +49 -49
- package/DEVELOPMENT.md +141 -141
- package/README.md +1 -48
- package/dist/configuration/models/models.constants.d.ts +1 -1
- package/dist/configuration/models/models.constants.d.ts.map +1 -1
- package/dist/configuration/models/models.constants.js +6 -1
- package/dist/configuration/models/models.constants.js.map +1 -1
- package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.d.ts +10 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.d.ts.map +1 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.js +15 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.js.map +1 -0
- package/dist/municipal/streets/streets.setters.d.ts +10 -0
- package/dist/municipal/streets/streets.setters.d.ts.map +1 -0
- package/dist/municipal/streets/streets.setters.js +15 -0
- package/dist/municipal/streets/streets.setters.js.map +1 -0
- package/dist/reconcile/index.d.ts +5 -0
- package/dist/reconcile/index.d.ts.map +1 -0
- package/dist/{talkpilot/clientDeletionLogs → reconcile}/index.js +4 -3
- package/dist/reconcile/index.js.map +1 -0
- package/dist/reconcile/reconcile.diff.d.ts +4 -0
- package/dist/reconcile/reconcile.diff.d.ts.map +1 -0
- package/dist/reconcile/reconcile.diff.js +36 -0
- package/dist/reconcile/reconcile.diff.js.map +1 -0
- package/dist/reconcile/reconcile.execute.d.ts +7 -0
- package/dist/reconcile/reconcile.execute.d.ts.map +1 -0
- package/dist/reconcile/reconcile.execute.js +20 -0
- package/dist/reconcile/reconcile.execute.js.map +1 -0
- package/dist/reconcile/reconcile.ops.d.ts +12 -0
- package/dist/reconcile/reconcile.ops.d.ts.map +1 -0
- package/dist/reconcile/reconcile.ops.js +24 -0
- package/dist/reconcile/reconcile.ops.js.map +1 -0
- package/dist/reconcile/reconcile.types.d.ts +32 -0
- package/dist/reconcile/reconcile.types.d.ts.map +1 -0
- package/dist/{talkpilot/auditLogs/auditLogs.types.js → reconcile/reconcile.types.js} +1 -1
- package/dist/reconcile/reconcile.types.js.map +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.d.ts +4 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.d.ts.map +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.js +30 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.getters.js.map +1 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.d.ts +28 -0
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.d.ts.map +1 -0
- package/dist/talkpilot/{clientDeletionLogs/clientDeletionLogs.types.js → callTokenUsage/callTokenUsage.types.js} +1 -1
- package/dist/talkpilot/callTokenUsage/callTokenUsage.types.js.map +1 -0
- package/dist/talkpilot/callTokenUsage/index.d.ts +3 -0
- package/dist/talkpilot/callTokenUsage/index.d.ts.map +1 -0
- package/dist/talkpilot/{auditLogs → callTokenUsage}/index.js +1 -2
- package/dist/talkpilot/callTokenUsage/index.js.map +1 -0
- package/dist/talkpilot/calls/calls.constants.d.ts +1 -9
- package/dist/talkpilot/calls/calls.constants.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.constants.js +1 -9
- package/dist/talkpilot/calls/calls.constants.js.map +1 -1
- package/dist/talkpilot/calls/calls.getters.d.ts +1 -7
- package/dist/talkpilot/calls/calls.getters.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.getters.js +1 -181
- package/dist/talkpilot/calls/calls.getters.js.map +1 -1
- package/dist/talkpilot/calls/calls.types.d.ts +2 -35
- package/dist/talkpilot/calls/calls.types.d.ts.map +1 -1
- package/dist/talkpilot/clients/clients.getters.d.ts +0 -2
- package/dist/talkpilot/clients/clients.getters.d.ts.map +1 -1
- package/dist/talkpilot/clients/clients.getters.js +1 -15
- package/dist/talkpilot/clients/clients.getters.js.map +1 -1
- package/dist/talkpilot/clients/clients.types.d.ts +0 -21
- package/dist/talkpilot/clients/clients.types.d.ts.map +1 -1
- package/dist/talkpilot/clients/index.d.ts +0 -2
- package/dist/talkpilot/clients/index.d.ts.map +1 -1
- package/dist/talkpilot/clients/index.js +0 -2
- package/dist/talkpilot/clients/index.js.map +1 -1
- package/dist/talkpilot/index.d.ts +1 -1
- package/dist/talkpilot/index.d.ts.map +1 -1
- package/dist/talkpilot/index.js +1 -1
- package/dist/talkpilot/index.js.map +1 -1
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts +1 -9
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts.map +1 -1
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.js +1 -66
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.js.map +1 -1
- package/dist/talkpilot/phone_numbers/phone_numbers.types.d.ts +0 -5
- package/dist/talkpilot/phone_numbers/phone_numbers.types.d.ts.map +1 -1
- package/dist/test-utils/factories/index.d.ts +0 -2
- package/dist/test-utils/factories/index.d.ts.map +1 -1
- package/dist/test-utils/factories/index.js +0 -2
- package/dist/test-utils/factories/index.js.map +1 -1
- package/jest.config.js +20 -20
- package/package.json +46 -46
- package/src/__tests__/setup.ts +20 -20
- package/src/bulkWrite/__tests__/bulkWrite.spec.ts +65 -65
- package/src/bulkWrite/bulkWrite.ops.ts +45 -45
- package/src/bulkWrite/bulkWrite.types.ts +4 -4
- package/src/bulkWrite/index.ts +2 -2
- package/src/config.ts +9 -9
- package/src/configuration/index.ts +17 -17
- package/src/configuration/internalModels/index.ts +3 -3
- package/src/configuration/internalModels/internalModels.constants.ts +1 -1
- package/src/configuration/internalModels/internalModels.getters.ts +33 -33
- package/src/configuration/internalModels/internalModels.types.ts +12 -12
- package/src/configuration/models/__tests__/models.getters.spec.ts +67 -67
- package/src/configuration/models/index.ts +27 -27
- package/src/configuration/models/models.constants.ts +20 -15
- package/src/configuration/models/models.getters.ts +71 -71
- package/src/configuration/models/models.types.ts +80 -80
- package/src/configuration/mongodb-client.ts +62 -62
- package/src/configuration/prompts/index.ts +2 -2
- package/src/configuration/prompts/prompts.getters.ts +49 -49
- package/src/configuration/prompts/prompts.types.ts +11 -11
- package/src/connection.ts +81 -81
- package/src/index.ts +47 -47
- package/src/municipal/__tests__/validation.spec.ts +62 -62
- package/src/municipal/cities/cities.getters.ts +50 -50
- package/src/municipal/cities/cities.types.ts +11 -11
- package/src/municipal/cities/index.ts +2 -2
- package/src/municipal/departmentsSubjects/__tests__/departmentsSubjects.spec.ts +272 -272
- package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +317 -317
- package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +73 -73
- package/src/municipal/departmentsSubjects/index.ts +9 -9
- package/src/municipal/index.ts +22 -22
- package/src/municipal/mongodb-client.ts +61 -61
- package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +94 -94
- package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +92 -92
- package/src/municipal/muniIssues/index.ts +17 -17
- package/src/municipal/muniIssues/muniIssues.constants.ts +18 -18
- package/src/municipal/muniIssues/muniIssues.getters.ts +24 -24
- package/src/municipal/muniIssues/muniIssues.schema.ts +66 -66
- package/src/municipal/muniIssues/muniIssues.setters.ts +24 -24
- package/src/municipal/muniIssues/muniIssues.setup.ts +65 -65
- package/src/municipal/muniIssues/muniIssues.types.ts +37 -37
- package/src/municipal/streets/__tests__/streets.spec.ts +253 -253
- package/src/municipal/streets/index.ts +2 -2
- package/src/municipal/streets/streets.getters.ts +140 -140
- package/src/municipal/streets/streets.types.ts +19 -19
- package/src/municipal/systemInstructions/__tests__/getters.spec.ts +113 -113
- package/src/municipal/systemInstructions/__tests__/setters.spec.ts +274 -274
- package/src/municipal/systemInstructions/index.ts +7 -7
- package/src/municipal/systemInstructions/instructions.getters.ts +57 -57
- package/src/municipal/systemInstructions/instructions.setters.ts +119 -119
- package/src/municipal/systemInstructions/instructions.types.ts +30 -30
- package/src/municipal/tickets/__tests__/tickets.getters.spec.ts +30 -30
- package/src/municipal/tickets/__tests__/tickets.statistics.spec.ts +99 -99
- package/src/municipal/tickets/index.ts +9 -9
- package/src/municipal/tickets/tickets.constants.ts +8 -8
- package/src/municipal/tickets/tickets.getters.ts +121 -121
- package/src/municipal/tickets/tickets.statistics.aggregation.ts +110 -110
- package/src/municipal/tickets/tickets.statistics.getters.ts +145 -145
- package/src/municipal/tickets/tickets.types.ts +54 -54
- package/src/municipal/utils/types.ts +11 -11
- package/src/talkpilot/__tests__/db.spec.ts +38 -38
- package/src/talkpilot/__tests__/mongodb-client.spec.ts +18 -18
- package/src/talkpilot/__tests__/validation.spec.ts +68 -68
- package/src/talkpilot/agents/__tests__/agents.getters.spec.ts +29 -29
- package/src/talkpilot/agents/agents.getters.ts +34 -34
- package/src/talkpilot/agents/agents.types.ts +14 -14
- package/src/talkpilot/agents/index.ts +2 -2
- package/src/talkpilot/backgroundToolResults/__tests__/backgroundToolResults.getters.spec.ts +147 -147
- package/src/talkpilot/backgroundToolResults/backgroundToolResults.getters.ts +65 -65
- package/src/talkpilot/backgroundToolResults/backgroundToolResults.types.ts +23 -23
- package/src/talkpilot/backgroundToolResults/index.ts +2 -2
- package/src/talkpilot/callTokenUsage/__tests__/callTokenUsage.getters.spec.ts +57 -0
- package/src/talkpilot/callTokenUsage/callTokenUsage.getters.ts +42 -0
- package/src/talkpilot/callTokenUsage/callTokenUsage.types.ts +28 -0
- package/src/talkpilot/callTokenUsage/index.ts +2 -0
- package/src/talkpilot/calls/__tests__/callStats.utils.spec.ts +128 -128
- package/src/talkpilot/calls/__tests__/calls.dashboard.spec.ts +229 -229
- package/src/talkpilot/calls/__tests__/calls.spec.ts +471 -471
- package/src/talkpilot/calls/__tests__/calls.statistics.spec.ts +483 -483
- package/src/talkpilot/calls/calls.constants.ts +49 -61
- package/src/talkpilot/calls/calls.getters.ts +1 -270
- package/src/talkpilot/calls/calls.statistics.getters.ts +668 -668
- package/src/talkpilot/calls/calls.statistics.types.ts +48 -48
- package/src/talkpilot/calls/calls.types.ts +2 -40
- package/src/talkpilot/calls/dashboard/calls.dashboard.ts +295 -295
- package/src/talkpilot/calls/dashboard/calls.dashboard.types.ts +57 -57
- package/src/talkpilot/calls/index.ts +6 -6
- package/src/talkpilot/clientAudioBuffers/__tests__/clientAudioBuffer.getters.spec.ts +160 -160
- package/src/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.ts +117 -117
- package/src/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.ts +25 -25
- package/src/talkpilot/clientAudioBuffers/index.ts +2 -2
- package/src/talkpilot/clients/__tests__/clients.quota.spec.ts +123 -123
- package/src/talkpilot/clients/clients.getters.ts +19 -32
- package/src/talkpilot/clients/clients.quota.getters.ts +119 -119
- package/src/talkpilot/clients/clients.quota.types.ts +27 -27
- package/src/talkpilot/clients/clients.types.ts +18 -37
- package/src/talkpilot/clients/index.ts +4 -6
- package/src/talkpilot/clientsConfig/__tests__/clientsConfig.getters.spec.ts +423 -423
- package/src/talkpilot/clientsConfig/__tests__/clientsConfig.spec.ts +212 -212
- package/src/talkpilot/clientsConfig/clientsConfig.constants.ts +2 -2
- package/src/talkpilot/clientsConfig/clientsConfig.getters.ts +247 -247
- package/src/talkpilot/clientsConfig/clientsConfig.types.ts +137 -137
- package/src/talkpilot/clientsConfig/index.ts +3 -3
- package/src/talkpilot/contextNotes/__tests__/contextNotes.getters.spec.ts +217 -217
- package/src/talkpilot/contextNotes/contextNotes.getters.ts +85 -85
- package/src/talkpilot/contextNotes/contextNotes.types.ts +20 -20
- package/src/talkpilot/contextNotes/index.ts +2 -2
- package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +124 -124
- package/src/talkpilot/flows/flows.getter.ts +34 -34
- package/src/talkpilot/flows/flows.schema.ts +180 -180
- package/src/talkpilot/flows/flows.types.ts +211 -211
- package/src/talkpilot/flows/index.ts +7 -7
- package/src/talkpilot/groups/__tests__/groups.spec.ts +90 -90
- package/src/talkpilot/groups/__tests__/phone.utils.spec.ts +32 -32
- package/src/talkpilot/groups/groups.getters.ts +30 -30
- package/src/talkpilot/groups/groups.types.ts +29 -29
- package/src/talkpilot/groups/index.ts +3 -3
- package/src/talkpilot/groups/phone.utils.ts +46 -46
- package/src/talkpilot/index.ts +32 -32
- package/src/talkpilot/leads/index.ts +2 -2
- package/src/talkpilot/leads/leads.getter.ts +6 -6
- package/src/talkpilot/leads/leads.schema.ts +33 -33
- package/src/talkpilot/leads/leads.types.ts +20 -20
- package/src/talkpilot/mongodb-client.ts +78 -78
- package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +530 -774
- package/src/talkpilot/phone_numbers/index.ts +2 -2
- package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +240 -324
- package/src/talkpilot/phone_numbers/phone_numbers.schema.ts +17 -17
- package/src/talkpilot/phone_numbers/phone_numbers.types.ts +30 -36
- package/src/talkpilot/phone_numbers/phone_numbers.utils.ts +9 -9
- package/src/talkpilot/plans/__tests__/plans.spec.ts +70 -70
- package/src/talkpilot/plans/index.ts +2 -2
- package/src/talkpilot/plans/plans.getters.ts +132 -132
- package/src/talkpilot/plans/plans.types.ts +89 -89
- package/src/talkpilot/products/__tests__/products.getters.spec.ts +44 -44
- package/src/talkpilot/products/index.ts +2 -2
- package/src/talkpilot/products/products.getters.ts +12 -12
- package/src/talkpilot/products/products.types.ts +9 -9
- package/src/talkpilot/results/index.ts +7 -7
- package/src/talkpilot/results/results.getter.ts +39 -39
- package/src/talkpilot/results/results.schema.ts +25 -25
- package/src/talkpilot/results/results.types.ts +34 -34
- package/src/talkpilot/retry_analyze/__tests__/retryAnalyze.getters.spec.ts +156 -156
- package/src/talkpilot/retry_analyze/index.ts +2 -2
- package/src/talkpilot/retry_analyze/retryAnalyze.getters.ts +84 -84
- package/src/talkpilot/retry_analyze/retryAnalyze.types.ts +13 -13
- package/src/talkpilot/sessions/__tests__/sessions.spec.ts +147 -147
- package/src/talkpilot/sessions/index.ts +2 -2
- package/src/talkpilot/sessions/sessions.getter.ts +92 -92
- package/src/talkpilot/sessions/sessions.schema.ts +34 -34
- package/src/talkpilot/sessions/sessions.types.ts +30 -30
- package/src/talkpilot/subscriptions/__tests__/subscriptions.getters.utils.spec.ts +45 -45
- package/src/talkpilot/subscriptions/index.ts +3 -3
- package/src/talkpilot/subscriptions/subscriptions.getters.ts +146 -146
- package/src/talkpilot/subscriptions/subscriptions.getters.utils.ts +33 -33
- package/src/talkpilot/subscriptions/subscriptions.types.ts +66 -66
- package/src/talkpilot/utils/__tests__/query.utils.spec.ts +49 -49
- package/src/talkpilot/utils/query.utils.ts +21 -21
- package/src/test-utils/db-utils.ts +33 -33
- package/src/test-utils/factories/index.ts +18 -20
- package/src/test-utils/factories/municipal/cities.ts +16 -16
- package/src/test-utils/factories/municipal/departmentsSubjects.ts +37 -37
- package/src/test-utils/factories/municipal/muniIssues.ts +32 -32
- package/src/test-utils/factories/municipal/streets.ts +22 -22
- package/src/test-utils/factories/municipal/tickets.ts +39 -39
- package/src/test-utils/factories/talkpilot/agents.ts +19 -19
- package/src/test-utils/factories/talkpilot/calls.ts +37 -37
- package/src/test-utils/factories/talkpilot/clientAudioBuffers.ts +20 -20
- package/src/test-utils/factories/talkpilot/clientsConfig.ts +18 -18
- package/src/test-utils/factories/talkpilot/contextNotes.ts +40 -40
- package/src/test-utils/factories/talkpilot/flows.ts +33 -33
- package/src/test-utils/factories/talkpilot/groups.ts +33 -33
- package/src/test-utils/factories/talkpilot/phone_numbers.ts +22 -22
- package/src/test-utils/factories/talkpilot/sessions.ts +35 -35
- package/src/test-utils/factories/websitalk/knowledgeDocuments.ts +29 -29
- package/src/test-utils/factories/websitalk/scanResources.ts +26 -26
- package/src/test-utils/factories/websitalk/scans.ts +30 -30
- package/src/test-utils/factories/websitalk/websiteUrls.ts +17 -17
- package/src/utils/date.utils.ts +126 -126
- package/src/utils/shared.types.ts +4 -4
- package/src/utils/validation.ts +23 -23
- package/src/websitalk/index.ts +18 -18
- package/src/websitalk/knowledgeDocuments/__tests__/knowledgeDocuments.spec.ts +238 -238
- package/src/websitalk/knowledgeDocuments/index.ts +3 -3
- package/src/websitalk/knowledgeDocuments/knowledgeDocuments.constants.ts +26 -26
- package/src/websitalk/knowledgeDocuments/knowledgeDocuments.getters.ts +95 -95
- package/src/websitalk/knowledgeDocuments/knowledgeDocuments.types.ts +75 -75
- package/src/websitalk/mongodb-client.ts +61 -61
- package/src/websitalk/scanResources/__tests__/scanResources.spec.ts +267 -267
- package/src/websitalk/scanResources/index.ts +4 -4
- package/src/websitalk/scanResources/scanResources.constants.ts +60 -60
- package/src/websitalk/scanResources/scanResources.getters.ts +128 -128
- package/src/websitalk/scanResources/scanResources.types.ts +105 -105
- package/src/websitalk/scanResources/scanResources.utils.ts +31 -31
- package/src/websitalk/scans/__tests__/scans.spec.ts +362 -362
- package/src/websitalk/scans/index.ts +4 -4
- package/src/websitalk/scans/scans.constants.ts +18 -18
- package/src/websitalk/scans/scans.getters.ts +172 -172
- package/src/websitalk/scans/scans.types.ts +58 -58
- package/src/websitalk/scans/scans.utils.ts +5 -5
- package/src/websitalk/websiteUrls/__tests__/websiteUrls.spec.ts +77 -77
- package/src/websitalk/websiteUrls/index.ts +2 -2
- package/src/websitalk/websiteUrls/websiteUrls.getters.ts +65 -65
- package/src/websitalk/websiteUrls/websiteUrls.types.ts +13 -13
- package/tsconfig.json +23 -23
- package/dist/talkpilot/auditLogs/auditLogs.getters.d.ts +0 -8
- package/dist/talkpilot/auditLogs/auditLogs.getters.d.ts.map +0 -1
- package/dist/talkpilot/auditLogs/auditLogs.getters.js +0 -26
- package/dist/talkpilot/auditLogs/auditLogs.getters.js.map +0 -1
- package/dist/talkpilot/auditLogs/auditLogs.setters.d.ts +0 -3
- package/dist/talkpilot/auditLogs/auditLogs.setters.d.ts.map +0 -1
- package/dist/talkpilot/auditLogs/auditLogs.setters.js +0 -9
- package/dist/talkpilot/auditLogs/auditLogs.setters.js.map +0 -1
- package/dist/talkpilot/auditLogs/auditLogs.types.d.ts +0 -11
- package/dist/talkpilot/auditLogs/auditLogs.types.d.ts.map +0 -1
- package/dist/talkpilot/auditLogs/auditLogs.types.js.map +0 -1
- package/dist/talkpilot/auditLogs/index.d.ts +0 -3
- package/dist/talkpilot/auditLogs/index.d.ts.map +0 -1
- package/dist/talkpilot/auditLogs/index.js.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.d.ts +0 -4
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.d.ts.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.js +0 -9
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.js.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.d.ts +0 -3
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.d.ts.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.js +0 -9
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.js.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.d.ts +0 -10
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.d.ts.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.js.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/index.d.ts +0 -4
- package/dist/talkpilot/clientDeletionLogs/index.d.ts.map +0 -1
- package/dist/talkpilot/clientDeletionLogs/index.js.map +0 -1
- package/dist/talkpilot/clients/clients.constants.d.ts +0 -3
- package/dist/talkpilot/clients/clients.constants.d.ts.map +0 -1
- package/dist/talkpilot/clients/clients.constants.js +0 -6
- package/dist/talkpilot/clients/clients.constants.js.map +0 -1
- package/dist/talkpilot/clients/clients.lifecycle.d.ts +0 -10
- package/dist/talkpilot/clients/clients.lifecycle.d.ts.map +0 -1
- package/dist/talkpilot/clients/clients.lifecycle.js +0 -95
- package/dist/talkpilot/clients/clients.lifecycle.js.map +0 -1
- package/dist/talkpilot/results/results.constants.d.ts +0 -4
- package/dist/talkpilot/results/results.constants.d.ts.map +0 -1
- package/dist/talkpilot/results/results.constants.js +0 -10
- package/dist/talkpilot/results/results.constants.js.map +0 -1
- package/dist/talkpilot/results/results.statistics.getters.d.ts +0 -12
- package/dist/talkpilot/results/results.statistics.getters.d.ts.map +0 -1
- package/dist/talkpilot/results/results.statistics.getters.js +0 -258
- package/dist/talkpilot/results/results.statistics.getters.js.map +0 -1
- package/dist/talkpilot/results/results.statistics.types.d.ts +0 -22
- package/dist/talkpilot/results/results.statistics.types.d.ts.map +0 -1
- package/dist/talkpilot/results/results.statistics.types.js +0 -3
- package/dist/talkpilot/results/results.statistics.types.js.map +0 -1
- package/dist/test-utils/factories/talkpilot/clients.d.ts +0 -14
- package/dist/test-utils/factories/talkpilot/clients.d.ts.map +0 -1
- package/dist/test-utils/factories/talkpilot/clients.js +0 -19
- package/dist/test-utils/factories/talkpilot/clients.js.map +0 -1
- package/dist/test-utils/factories/talkpilot/results.d.ts +0 -16
- package/dist/test-utils/factories/talkpilot/results.d.ts.map +0 -1
- package/dist/test-utils/factories/talkpilot/results.js +0 -40
- package/dist/test-utils/factories/talkpilot/results.js.map +0 -1
- package/src/talkpilot/auditLogs/__tests__/auditLogs.spec.ts +0 -91
- package/src/talkpilot/auditLogs/auditLogs.getters.ts +0 -26
- package/src/talkpilot/auditLogs/auditLogs.types.ts +0 -12
- package/src/talkpilot/auditLogs/index.ts +0 -2
- package/src/talkpilot/calls/__tests__/calls.statistics.getters.spec.ts +0 -374
- package/src/talkpilot/clients/__tests__/clients.getters.spec.ts +0 -51
- package/src/talkpilot/clients/__tests__/clients.lifecycle.spec.ts +0 -166
- package/src/talkpilot/clients/clients.constants.ts +0 -2
- package/src/talkpilot/clients/clients.lifecycle.ts +0 -116
- package/src/test-utils/factories/talkpilot/clients.ts +0 -21
- package/src/test-utils/factories/talkpilot/results.ts +0 -43
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
import { ObjectId } from "mongodb";
|
|
2
|
-
import {
|
|
3
|
-
aggregateActiveCallsSummary,
|
|
4
|
-
aggregateTodayCallsSummary,
|
|
5
|
-
aggregateClientCallStats,
|
|
6
|
-
aggregateSessionCallStats,
|
|
7
|
-
getAllClientsLastCallDate,
|
|
8
|
-
findClientIdsByCallSids,
|
|
9
|
-
getCallsCollection,
|
|
10
|
-
} from "../calls.getters";
|
|
11
|
-
import { getSessionsCollection } from "../../sessions/sessions.getter";
|
|
12
|
-
import type { Call } from "../calls.types";
|
|
13
|
-
import {
|
|
14
|
-
createOutGoingCallDoc,
|
|
15
|
-
createIncomingCallDoc,
|
|
16
|
-
createSession,
|
|
17
|
-
} from "../../../test-utils/factories";
|
|
18
|
-
|
|
19
|
-
const insertCall = (call: Call) =>
|
|
20
|
-
getCallsCollection().insertOne({ ...call, env: call.env ?? "test" });
|
|
21
|
-
|
|
22
|
-
describe("calls.getters statistics", () => {
|
|
23
|
-
describe("aggregateActiveCallsSummary", () => {
|
|
24
|
-
it("should count distinct active calls within the last 2 hours, split incoming/outgoing", async () => {
|
|
25
|
-
const now = new Date();
|
|
26
|
-
await Promise.all([
|
|
27
|
-
insertCall(createIncomingCallDoc({ clientId: "clientA", status: "in-progress", updatedAt: now })),
|
|
28
|
-
insertCall(createOutGoingCallDoc({ clientId: "clientB", status: "in-progress", updatedAt: now })),
|
|
29
|
-
insertCall(createIncomingCallDoc({ clientId: "clientC", status: "completed", updatedAt: now })),
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
const summary = await aggregateActiveCallsSummary();
|
|
33
|
-
|
|
34
|
-
expect(summary.total).toBe(2);
|
|
35
|
-
expect(summary.incoming).toBe(1);
|
|
36
|
-
expect(summary.outgoing).toBe(1);
|
|
37
|
-
expect(summary.activeClientIds.sort()).toEqual(["clientA", "clientB"]);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it("should filter by clientId when provided", async () => {
|
|
41
|
-
const now = new Date();
|
|
42
|
-
await Promise.all([
|
|
43
|
-
insertCall(createOutGoingCallDoc({ clientId: "onlyThisClient", status: "in-progress", updatedAt: now })),
|
|
44
|
-
insertCall(createOutGoingCallDoc({ clientId: "otherClient", status: "in-progress", updatedAt: now })),
|
|
45
|
-
]);
|
|
46
|
-
|
|
47
|
-
const summary = await aggregateActiveCallsSummary("onlyThisClient");
|
|
48
|
-
expect(summary.total).toBe(1);
|
|
49
|
-
expect(summary.activeClientIds).toEqual(["onlyThisClient"]);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("should exclude calls whose updatedAt is older than 2 hours", async () => {
|
|
53
|
-
const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000);
|
|
54
|
-
await insertCall(createOutGoingCallDoc({ status: "in-progress", updatedAt: threeHoursAgo }));
|
|
55
|
-
|
|
56
|
-
const summary = await aggregateActiveCallsSummary();
|
|
57
|
-
expect(summary.total).toBe(0);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("aggregateTodayCallsSummary", () => {
|
|
62
|
-
it("should aggregate status/type counts and total minutes within the given date range", async () => {
|
|
63
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
64
|
-
await Promise.all([
|
|
65
|
-
insertCall(createIncomingCallDoc({ status: "completed", callLength: 120, createdAt: new Date() })),
|
|
66
|
-
insertCall(createOutGoingCallDoc({ status: "failed", callLength: 30, createdAt: new Date() })),
|
|
67
|
-
]);
|
|
68
|
-
|
|
69
|
-
const summary = await aggregateTodayCallsSummary({ dateFrom: today, dateTo: today });
|
|
70
|
-
|
|
71
|
-
expect(summary.total).toBe(2);
|
|
72
|
-
expect(summary.incoming).toBe(1);
|
|
73
|
-
expect(summary.outgoing).toBe(1);
|
|
74
|
-
expect(summary.completed).toBe(1);
|
|
75
|
-
expect(summary.failed).toBe(1);
|
|
76
|
-
expect(summary.totalMinutes).toBe(3); // ceil(150/60)
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("should respect the given timezone when resolving an explicit date", async () => {
|
|
80
|
-
// 23:30 UTC on 2026-01-01 is already 2026-01-02 in Asia/Jerusalem (+2).
|
|
81
|
-
const lateUtc = new Date("2026-01-01T23:30:00.000Z");
|
|
82
|
-
await insertCall(createOutGoingCallDoc({ status: "completed", createdAt: lateUtc }));
|
|
83
|
-
|
|
84
|
-
const summaryUtc = await aggregateTodayCallsSummary({
|
|
85
|
-
dateFrom: "2026-01-01",
|
|
86
|
-
dateTo: "2026-01-01",
|
|
87
|
-
timezone: "UTC",
|
|
88
|
-
});
|
|
89
|
-
expect(summaryUtc.total).toBe(1);
|
|
90
|
-
|
|
91
|
-
const summaryJerusalem = await aggregateTodayCallsSummary({
|
|
92
|
-
dateFrom: "2026-01-01",
|
|
93
|
-
dateTo: "2026-01-01",
|
|
94
|
-
timezone: "Asia/Jerusalem",
|
|
95
|
-
});
|
|
96
|
-
expect(summaryJerusalem.total).toBe(0);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it("should include a call's full history (not just today) when no date range is given", async () => {
|
|
100
|
-
const sixMonthsAgo = new Date(Date.now() - 180 * 24 * 60 * 60 * 1000);
|
|
101
|
-
await insertCall(createOutGoingCallDoc({ status: "completed", createdAt: sixMonthsAgo }));
|
|
102
|
-
|
|
103
|
-
const summary = await aggregateTodayCallsSummary({});
|
|
104
|
-
expect(summary.total).toBe(1);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe("aggregateClientCallStats", () => {
|
|
109
|
-
it("should group call counts and minutes by clientId", async () => {
|
|
110
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
111
|
-
await Promise.all([
|
|
112
|
-
insertCall(
|
|
113
|
-
createOutGoingCallDoc({ clientId: "clientX", status: "completed", callLength: 60, createdAt: new Date() }),
|
|
114
|
-
),
|
|
115
|
-
insertCall(
|
|
116
|
-
createOutGoingCallDoc({ clientId: "clientX", status: "failed", callLength: 60, createdAt: new Date() }),
|
|
117
|
-
),
|
|
118
|
-
]);
|
|
119
|
-
|
|
120
|
-
const rows = await aggregateClientCallStats({ dateFrom: today, dateTo: today });
|
|
121
|
-
const row = rows.find((r) => r.clientId === "clientX");
|
|
122
|
-
|
|
123
|
-
expect(row?.totalCalls).toBe(2);
|
|
124
|
-
expect(row?.statusCounts).toMatchObject({ completed: 1, failed: 1 });
|
|
125
|
-
expect(row?.totalMinutes).toBe(2);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it("should not include other clients when filtered by clientId", async () => {
|
|
129
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
130
|
-
await Promise.all([
|
|
131
|
-
insertCall(createOutGoingCallDoc({ clientId: "wantedClient", status: "completed", createdAt: new Date() })),
|
|
132
|
-
insertCall(createOutGoingCallDoc({ clientId: "unwantedClient", status: "completed", createdAt: new Date() })),
|
|
133
|
-
]);
|
|
134
|
-
|
|
135
|
-
const rows = await aggregateClientCallStats({
|
|
136
|
-
dateFrom: today,
|
|
137
|
-
dateTo: today,
|
|
138
|
-
clientId: "wantedClient",
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
expect(rows).toHaveLength(1);
|
|
142
|
-
expect(rows[0].clientId).toBe("wantedClient");
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it("should include a client's full history when no date range is given", async () => {
|
|
146
|
-
const sixMonthsAgo = new Date(Date.now() - 180 * 24 * 60 * 60 * 1000);
|
|
147
|
-
await Promise.all([
|
|
148
|
-
insertCall(createOutGoingCallDoc({ clientId: "longHistoryClient", status: "completed", createdAt: sixMonthsAgo })),
|
|
149
|
-
insertCall(createOutGoingCallDoc({ clientId: "longHistoryClient", status: "completed", createdAt: new Date() })),
|
|
150
|
-
]);
|
|
151
|
-
|
|
152
|
-
const rows = await aggregateClientCallStats({});
|
|
153
|
-
const row = rows.find((r) => r.clientId === "longHistoryClient");
|
|
154
|
-
|
|
155
|
-
expect(row?.totalCalls).toBe(2);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("should set lastCallDate to the most recent call", async () => {
|
|
159
|
-
const earlierCall = new Date("2026-01-01T00:00:00.000Z");
|
|
160
|
-
const laterCall = new Date("2026-03-10T00:00:00.000Z");
|
|
161
|
-
await Promise.all([
|
|
162
|
-
insertCall(createOutGoingCallDoc({ clientId: "lastCallDateClient", status: "completed", createdAt: earlierCall })),
|
|
163
|
-
insertCall(createOutGoingCallDoc({ clientId: "lastCallDateClient", status: "completed", createdAt: laterCall })),
|
|
164
|
-
]);
|
|
165
|
-
|
|
166
|
-
const rows = await aggregateClientCallStats({});
|
|
167
|
-
const row = rows.find((r) => r.clientId === "lastCallDateClient");
|
|
168
|
-
|
|
169
|
-
expect(row?.lastCallDate).toEqual(laterCall);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("should filter by clientId alone when no date range is given", async () => {
|
|
173
|
-
await Promise.all([
|
|
174
|
-
insertCall(createOutGoingCallDoc({ clientId: "onlyThisClientNoRange", status: "completed", createdAt: new Date() })),
|
|
175
|
-
insertCall(createOutGoingCallDoc({ clientId: "otherClientNoRange", status: "completed", createdAt: new Date() })),
|
|
176
|
-
]);
|
|
177
|
-
|
|
178
|
-
const rows = await aggregateClientCallStats({ clientId: "onlyThisClientNoRange" });
|
|
179
|
-
|
|
180
|
-
expect(rows).toHaveLength(1);
|
|
181
|
-
expect(rows[0].clientId).toBe("onlyThisClientNoRange");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("should count every real status separately, including queued; a missing status only inflates totalCalls", async () => {
|
|
185
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
186
|
-
await Promise.all([
|
|
187
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "completed", createdAt: new Date() })),
|
|
188
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "canceled", createdAt: new Date() })),
|
|
189
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "queued" as any, createdAt: new Date() })),
|
|
190
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "ringing", createdAt: new Date() })),
|
|
191
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "initiated", createdAt: new Date() })),
|
|
192
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "answered", createdAt: new Date() })),
|
|
193
|
-
insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: undefined, createdAt: new Date() })),
|
|
194
|
-
]);
|
|
195
|
-
|
|
196
|
-
const rows = await aggregateClientCallStats({ dateFrom: today, dateTo: today });
|
|
197
|
-
const row = rows.find((r) => r.clientId === "statusBucketClient");
|
|
198
|
-
|
|
199
|
-
expect(row?.totalCalls).toBe(7);
|
|
200
|
-
expect(row?.statusCounts).toMatchObject({
|
|
201
|
-
completed: 1,
|
|
202
|
-
canceled: 1,
|
|
203
|
-
queued: 1,
|
|
204
|
-
ringing: 1,
|
|
205
|
-
initiated: 1,
|
|
206
|
-
answered: 1,
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
describe("aggregateSessionCallStats", () => {
|
|
212
|
-
it("should group by sessionId and resolve the session's current name via the sessions collection", async () => {
|
|
213
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
214
|
-
const sessionId = new ObjectId();
|
|
215
|
-
await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "My Session" }));
|
|
216
|
-
await insertCall(
|
|
217
|
-
createOutGoingCallDoc({ sessionId, status: "completed", createdAt: new Date() }),
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
|
|
221
|
-
const row = rows.find((r) => r.sessionId === sessionId.toString());
|
|
222
|
-
|
|
223
|
-
expect(row).toMatchObject({ sessionName: "My Session", totalCalls: 1 });
|
|
224
|
-
expect(row?.statusCounts).toMatchObject({ completed: 1 });
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it("should always show the session's current name, even if it was renamed after some calls happened", async () => {
|
|
228
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
229
|
-
const sessionId = new ObjectId();
|
|
230
|
-
const earlierCall = new Date(Date.now() - 60 * 60 * 1000);
|
|
231
|
-
const laterCall = new Date();
|
|
232
|
-
|
|
233
|
-
await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "New Name" }));
|
|
234
|
-
await Promise.all([
|
|
235
|
-
insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: earlierCall })),
|
|
236
|
-
insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: laterCall })),
|
|
237
|
-
]);
|
|
238
|
-
|
|
239
|
-
const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
|
|
240
|
-
const merged = rows.find((r) => r.sessionId === sessionId.toString());
|
|
241
|
-
|
|
242
|
-
expect(merged).toMatchObject({ sessionName: "New Name", totalCalls: 2 });
|
|
243
|
-
expect(merged?.statusCounts).toMatchObject({ completed: 2 });
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it("should show 'Unknown' when the session no longer exists in the sessions collection", async () => {
|
|
247
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
248
|
-
const orphanedSessionId = new ObjectId();
|
|
249
|
-
await insertCall(createOutGoingCallDoc({ sessionId: orphanedSessionId, status: "completed", createdAt: new Date() }));
|
|
250
|
-
|
|
251
|
-
const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
|
|
252
|
-
const row = rows.find((r) => r.sessionId === orphanedSessionId.toString());
|
|
253
|
-
|
|
254
|
-
expect(row?.sessionName).toBe("Unknown");
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it("should label a null sessionId as 'Incoming Call', not 'Unknown' — a call with no session is expected, not broken data", async () => {
|
|
258
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
259
|
-
await Promise.all([
|
|
260
|
-
insertCall(createIncomingCallDoc({ status: "completed", createdAt: new Date() })),
|
|
261
|
-
insertCall(createIncomingCallDoc({ status: "failed", createdAt: new Date() })),
|
|
262
|
-
]);
|
|
263
|
-
|
|
264
|
-
const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
|
|
265
|
-
const row = rows.find((r) => r.sessionName === "Incoming Call");
|
|
266
|
-
|
|
267
|
-
expect(row).toBeDefined();
|
|
268
|
-
expect(row?.totalCalls).toBe(2);
|
|
269
|
-
expect(row?.statusCounts).toMatchObject({ completed: 1, failed: 1 });
|
|
270
|
-
expect(row?.sessionName).not.toBe("Unknown");
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it("should only include the given client's sessions when clientId is provided", async () => {
|
|
274
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
275
|
-
const sessionA = new ObjectId();
|
|
276
|
-
const sessionB = new ObjectId();
|
|
277
|
-
await getSessionsCollection().insertMany([
|
|
278
|
-
createSession({ _id: sessionA, session_name: "Session A" }),
|
|
279
|
-
createSession({ _id: sessionB, session_name: "Session B" }),
|
|
280
|
-
]);
|
|
281
|
-
await Promise.all([
|
|
282
|
-
insertCall(createOutGoingCallDoc({ clientId: "clientA", sessionId: sessionA, status: "completed", createdAt: new Date() })),
|
|
283
|
-
insertCall(createOutGoingCallDoc({ clientId: "clientB", sessionId: sessionB, status: "completed", createdAt: new Date() })),
|
|
284
|
-
]);
|
|
285
|
-
|
|
286
|
-
const rows = await aggregateSessionCallStats({
|
|
287
|
-
dateFrom: today,
|
|
288
|
-
dateTo: today,
|
|
289
|
-
clientId: "clientA",
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
expect(rows).toHaveLength(1);
|
|
293
|
-
expect(rows[0]).toMatchObject({ sessionId: sessionA.toString(), sessionName: "Session A" });
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it("should exclude a session with no calls in the given date range", async () => {
|
|
297
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
298
|
-
const longAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
299
|
-
const oldSessionId = new ObjectId();
|
|
300
|
-
await getSessionsCollection().insertOne(createSession({ _id: oldSessionId, session_name: "Old Session" }));
|
|
301
|
-
await insertCall(createOutGoingCallDoc({ sessionId: oldSessionId, status: "completed", createdAt: longAgo }));
|
|
302
|
-
|
|
303
|
-
const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
|
|
304
|
-
|
|
305
|
-
expect(rows.find((r) => r.sessionId === oldSessionId.toString())).toBeUndefined();
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("should include a session's full history when no date range is given", async () => {
|
|
309
|
-
const longAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
310
|
-
const sessionId = new ObjectId();
|
|
311
|
-
await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "All Time Session" }));
|
|
312
|
-
await insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: longAgo }));
|
|
313
|
-
|
|
314
|
-
const rows = await aggregateSessionCallStats({});
|
|
315
|
-
const row = rows.find((r) => r.sessionId === sessionId.toString());
|
|
316
|
-
|
|
317
|
-
expect(row?.totalCalls).toBe(1);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it("should count each real status separately, including queued", async () => {
|
|
321
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
322
|
-
const sessionId = new ObjectId();
|
|
323
|
-
await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "Bucket Session" }));
|
|
324
|
-
await Promise.all([
|
|
325
|
-
insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: new Date() })),
|
|
326
|
-
insertCall(createOutGoingCallDoc({ sessionId, status: "canceled", createdAt: new Date() })),
|
|
327
|
-
insertCall(createOutGoingCallDoc({ sessionId, status: "queued" as any, createdAt: new Date() })),
|
|
328
|
-
]);
|
|
329
|
-
|
|
330
|
-
const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
|
|
331
|
-
const row = rows.find((r) => r.sessionId === sessionId.toString());
|
|
332
|
-
|
|
333
|
-
expect(row?.totalCalls).toBe(3);
|
|
334
|
-
expect(row?.statusCounts).toMatchObject({ completed: 1, canceled: 1, queued: 1 });
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe("getAllClientsLastCallDate", () => {
|
|
339
|
-
it("should map each clientId to its most recent call, ignoring any date range", async () => {
|
|
340
|
-
const earlierCall = new Date("2026-01-01T00:00:00.000Z");
|
|
341
|
-
const laterCall = new Date("2026-03-10T00:00:00.000Z");
|
|
342
|
-
await Promise.all([
|
|
343
|
-
insertCall(createOutGoingCallDoc({ clientId: "lastCallMapClientA", status: "completed", createdAt: earlierCall })),
|
|
344
|
-
insertCall(createOutGoingCallDoc({ clientId: "lastCallMapClientA", status: "completed", createdAt: laterCall })),
|
|
345
|
-
insertCall(createOutGoingCallDoc({ clientId: "lastCallMapClientB", status: "completed", createdAt: earlierCall })),
|
|
346
|
-
]);
|
|
347
|
-
|
|
348
|
-
const map = await getAllClientsLastCallDate();
|
|
349
|
-
|
|
350
|
-
expect(map.get("lastCallMapClientA")).toEqual(laterCall);
|
|
351
|
-
expect(map.get("lastCallMapClientB")).toEqual(earlierCall);
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
describe("findClientIdsByCallSids", () => {
|
|
356
|
-
it("should map each callSid to the clientId that owns it", async () => {
|
|
357
|
-
await Promise.all([
|
|
358
|
-
insertCall(createOutGoingCallDoc({ clientId: "clientA", callSid: "CAaaa" })),
|
|
359
|
-
insertCall(createOutGoingCallDoc({ clientId: "clientB", callSid: "CAbbb" })),
|
|
360
|
-
]);
|
|
361
|
-
|
|
362
|
-
const map = await findClientIdsByCallSids(["CAaaa", "CAbbb", "CAunknown"]);
|
|
363
|
-
|
|
364
|
-
expect(map.get("CAaaa")).toBe("clientA");
|
|
365
|
-
expect(map.get("CAbbb")).toBe("clientB");
|
|
366
|
-
expect(map.has("CAunknown")).toBe(false);
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
it("should return an empty map when given no callSids", async () => {
|
|
370
|
-
const map = await findClientIdsByCallSids([]);
|
|
371
|
-
expect(map.size).toBe(0);
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { getClientsCollection, getAllClientCredits, getAllClientIds } from "../clients.getters";
|
|
2
|
-
import { createClient } from "../../../test-utils/factories";
|
|
3
|
-
|
|
4
|
-
describe("db.clients", () => {
|
|
5
|
-
describe("getAllClientCredits", () => {
|
|
6
|
-
it("should return a Map of clientId to credits across all clients", async () => {
|
|
7
|
-
await getClientsCollection().insertMany([
|
|
8
|
-
createClient({ clientId: "creditsClientA", credits: 100 }),
|
|
9
|
-
createClient({ clientId: "creditsClientB", credits: 250 }),
|
|
10
|
-
]);
|
|
11
|
-
|
|
12
|
-
const result = await getAllClientCredits();
|
|
13
|
-
|
|
14
|
-
expect(result).toBeInstanceOf(Map);
|
|
15
|
-
expect(result.get("creditsClientA")).toBe(100);
|
|
16
|
-
expect(result.get("creditsClientB")).toBe(250);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("should default missing credits to 0", async () => {
|
|
20
|
-
const client = createClient({ clientId: "noCreditsClient" });
|
|
21
|
-
delete (client as { credits?: number }).credits;
|
|
22
|
-
await getClientsCollection().insertOne(client);
|
|
23
|
-
|
|
24
|
-
const result = await getAllClientCredits();
|
|
25
|
-
expect(result.get("noCreditsClient")).toBe(0);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("should return an empty Map when there are no clients", async () => {
|
|
29
|
-
const result = await getAllClientCredits();
|
|
30
|
-
expect(result.size).toBe(0);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe("getAllClientIds", () => {
|
|
35
|
-
it("should return the ids of all clients", async () => {
|
|
36
|
-
await getClientsCollection().insertMany([
|
|
37
|
-
createClient({ clientId: "idClientA" }),
|
|
38
|
-
createClient({ clientId: "idClientB" }),
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const result = await getAllClientIds();
|
|
42
|
-
|
|
43
|
-
expect(result.sort()).toEqual(["idClientA", "idClientB"]);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("should return an empty array when there are no clients", async () => {
|
|
47
|
-
const result = await getAllClientIds();
|
|
48
|
-
expect(result).toEqual([]);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
});
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
clientExistsInAnyCollection,
|
|
3
|
-
deleteClientDataAcrossDomains,
|
|
4
|
-
} from "../clients.lifecycle";
|
|
5
|
-
import { getPhoneNumbersCollection } from "../../phone_numbers/phone_numbers.getter";
|
|
6
|
-
import {
|
|
7
|
-
createMuniIssue,
|
|
8
|
-
generateMuniIssueId,
|
|
9
|
-
getAuditLogsCollection,
|
|
10
|
-
getScansCollection,
|
|
11
|
-
} from "../../../index";
|
|
12
|
-
import {
|
|
13
|
-
createPhoneNumber,
|
|
14
|
-
createMuniIssueInput,
|
|
15
|
-
createScanFixture,
|
|
16
|
-
} from "../../../test-utils/factories";
|
|
17
|
-
|
|
18
|
-
describe("db.clients.lifecycle", () => {
|
|
19
|
-
describe("clientExistsInAnyCollection", () => {
|
|
20
|
-
it("should return true when the client exists only in phone_numbers (client_id field)", async () => {
|
|
21
|
-
const clientId = "existsPhoneOnly";
|
|
22
|
-
await getPhoneNumbersCollection().insertOne(
|
|
23
|
-
createPhoneNumber({ client_id: clientId }),
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
expect(await clientExistsInAnyCollection(clientId)).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it("should return true when the client exists only in muniIssues (municipal DB)", async () => {
|
|
30
|
-
const clientId = "existsMuniOnly";
|
|
31
|
-
await createMuniIssue(
|
|
32
|
-
createMuniIssueInput({ clientId }),
|
|
33
|
-
generateMuniIssueId(),
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
expect(await clientExistsInAnyCollection(clientId)).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("should return false when the client does not exist anywhere", async () => {
|
|
40
|
-
expect(await clientExistsInAnyCollection("noSuchClientAtAll")).toBe(
|
|
41
|
-
false,
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should not consider websitalk data (scans/websiteUrls) at all", async () => {
|
|
46
|
-
const clientId = "onlyInWebsitalk";
|
|
47
|
-
await getScansCollection().insertOne(createScanFixture({ clientId }));
|
|
48
|
-
|
|
49
|
-
expect(await clientExistsInAnyCollection(clientId)).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("should not be fooled by unrelated collections lacking a clientId/client_id field", async () => {
|
|
53
|
-
await global.db
|
|
54
|
-
.collection("someUnrelatedCollection")
|
|
55
|
-
.insertOne({ someField: "someValue" });
|
|
56
|
-
|
|
57
|
-
expect(await clientExistsInAnyCollection("noSuchClientAtAll")).toBe(
|
|
58
|
-
false,
|
|
59
|
-
);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("deleteClientDataAcrossDomains", () => {
|
|
64
|
-
it("should return deleted:false with a reason and delete nothing when the client does not exist", async () => {
|
|
65
|
-
await getPhoneNumbersCollection().insertOne(
|
|
66
|
-
createPhoneNumber({ client_id: "unrelatedClient" }),
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
const summary = await deleteClientDataAcrossDomains(
|
|
70
|
-
"missingClient",
|
|
71
|
-
"admin@callai.co.il",
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
expect(summary.deleted).toBe(false);
|
|
75
|
-
if (!summary.deleted) {
|
|
76
|
-
expect(summary.reason).toBeTruthy();
|
|
77
|
-
}
|
|
78
|
-
expect(
|
|
79
|
-
await getPhoneNumbersCollection().findOne({
|
|
80
|
-
client_id: "unrelatedClient",
|
|
81
|
-
}),
|
|
82
|
-
).not.toBeNull();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("should not write an audit log entry when the client does not exist", async () => {
|
|
86
|
-
await deleteClientDataAcrossDomains(
|
|
87
|
-
"missingClientNoAudit",
|
|
88
|
-
"admin@callai.co.il",
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
expect(
|
|
92
|
-
await getAuditLogsCollection().findOne({
|
|
93
|
-
clientId: "missingClientNoAudit",
|
|
94
|
-
}),
|
|
95
|
-
).toBeNull();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("should delete the client's data across talkpilot and municipal domains", async () => {
|
|
99
|
-
const clientId = "deleteMeEverywhere";
|
|
100
|
-
await getPhoneNumbersCollection().insertOne(
|
|
101
|
-
createPhoneNumber({ client_id: clientId }),
|
|
102
|
-
);
|
|
103
|
-
await createMuniIssue(
|
|
104
|
-
createMuniIssueInput({ clientId }),
|
|
105
|
-
generateMuniIssueId(),
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
const adminEmail = "admin@callai.co.il";
|
|
109
|
-
const summary = await deleteClientDataAcrossDomains(
|
|
110
|
-
clientId,
|
|
111
|
-
adminEmail,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
expect(summary.deleted).toBe(true);
|
|
115
|
-
if (summary.deleted) {
|
|
116
|
-
expect(summary.allSucceeded).toBe(true);
|
|
117
|
-
const byName = (name: string) =>
|
|
118
|
-
summary.results.find((r) => r.collectionName === name);
|
|
119
|
-
expect(byName("phone_numbers")?.deletedCount).toBe(1);
|
|
120
|
-
expect(byName("muniIssues")?.deletedCount).toBe(1);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
expect(await clientExistsInAnyCollection(clientId)).toBe(false);
|
|
124
|
-
|
|
125
|
-
// The audit entry itself must survive the client's own deletion.
|
|
126
|
-
const auditEntry = await getAuditLogsCollection().findOne({ clientId });
|
|
127
|
-
expect(auditEntry).toMatchObject({
|
|
128
|
-
clientId,
|
|
129
|
-
adminEmail,
|
|
130
|
-
action: "delete",
|
|
131
|
-
});
|
|
132
|
-
expect(auditEntry?.timestamp).toBeInstanceOf(Date);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("should not touch websitalk data (scans/websiteUrls) — callers must call the external website-talk deletion API separately", async () => {
|
|
136
|
-
const clientId = "hasWebsitalkData";
|
|
137
|
-
await getPhoneNumbersCollection().insertOne(
|
|
138
|
-
createPhoneNumber({ client_id: clientId }),
|
|
139
|
-
);
|
|
140
|
-
await getScansCollection().insertOne(createScanFixture({ clientId }));
|
|
141
|
-
|
|
142
|
-
await deleteClientDataAcrossDomains(clientId, "admin@callai.co.il");
|
|
143
|
-
|
|
144
|
-
expect(
|
|
145
|
-
await getScansCollection().findOne({ clientId }),
|
|
146
|
-
).not.toBeNull();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("should not delete unrelated clients' data", async () => {
|
|
150
|
-
const targetClient = "deleteTarget";
|
|
151
|
-
const otherClient = "keepMeClient";
|
|
152
|
-
await getPhoneNumbersCollection().insertOne(
|
|
153
|
-
createPhoneNumber({ client_id: targetClient }),
|
|
154
|
-
);
|
|
155
|
-
await getPhoneNumbersCollection().insertOne(
|
|
156
|
-
createPhoneNumber({ client_id: otherClient }),
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
await deleteClientDataAcrossDomains(targetClient, "admin@callai.co.il");
|
|
160
|
-
|
|
161
|
-
expect(
|
|
162
|
-
await getPhoneNumbersCollection().findOne({ client_id: otherClient }),
|
|
163
|
-
).not.toBeNull();
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
});
|