@talkpilot/core-db 1.0.1
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 -0
- package/DEVELOPMENT.md +98 -0
- package/README.md +140 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/municipal/cities/cities.getters.d.ts +9 -0
- package/dist/municipal/cities/cities.getters.d.ts.map +1 -0
- package/dist/municipal/cities/cities.getters.js +38 -0
- package/dist/municipal/cities/cities.getters.js.map +1 -0
- package/dist/municipal/cities/cities.types.d.ts +10 -0
- package/dist/municipal/cities/cities.types.d.ts.map +1 -0
- package/dist/municipal/cities/cities.types.js +3 -0
- package/dist/municipal/cities/cities.types.js.map +1 -0
- package/dist/municipal/cities/index.d.ts +3 -0
- package/dist/municipal/cities/index.d.ts.map +1 -0
- package/dist/municipal/cities/index.js +18 -0
- package/dist/municipal/cities/index.js.map +1 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.getters.d.ts +62 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.getters.d.ts.map +1 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.getters.js +180 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.getters.js.map +1 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.types.d.ts +69 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.types.d.ts.map +1 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.types.js +3 -0
- package/dist/municipal/departmentsSubjects/departmentsSubjects.types.js.map +1 -0
- package/dist/municipal/departmentsSubjects/index.d.ts +3 -0
- package/dist/municipal/departmentsSubjects/index.d.ts.map +1 -0
- package/dist/municipal/departmentsSubjects/index.js +18 -0
- package/dist/municipal/departmentsSubjects/index.js.map +1 -0
- package/dist/municipal/index.d.ts +10 -0
- package/dist/municipal/index.d.ts.map +1 -0
- package/dist/municipal/index.js +37 -0
- package/dist/municipal/index.js.map +1 -0
- package/dist/municipal/mongodb-client.d.ts +13 -0
- package/dist/municipal/mongodb-client.d.ts.map +1 -0
- package/dist/municipal/mongodb-client.js +56 -0
- package/dist/municipal/mongodb-client.js.map +1 -0
- package/dist/municipal/streets/index.d.ts +3 -0
- package/dist/municipal/streets/index.d.ts.map +1 -0
- package/dist/municipal/streets/index.js +18 -0
- package/dist/municipal/streets/index.js.map +1 -0
- package/dist/municipal/streets/streets.getters.d.ts +21 -0
- package/dist/municipal/streets/streets.getters.d.ts.map +1 -0
- package/dist/municipal/streets/streets.getters.js +85 -0
- package/dist/municipal/streets/streets.getters.js.map +1 -0
- package/dist/municipal/streets/streets.types.d.ts +16 -0
- package/dist/municipal/streets/streets.types.d.ts.map +1 -0
- package/dist/municipal/streets/streets.types.js +3 -0
- package/dist/municipal/streets/streets.types.js.map +1 -0
- package/dist/municipal/tickets/index.d.ts +3 -0
- package/dist/municipal/tickets/index.d.ts.map +1 -0
- package/dist/municipal/tickets/index.js +18 -0
- package/dist/municipal/tickets/index.js.map +1 -0
- package/dist/municipal/tickets/tickets.getters.d.ts +44 -0
- package/dist/municipal/tickets/tickets.getters.d.ts.map +1 -0
- package/dist/municipal/tickets/tickets.getters.js +199 -0
- package/dist/municipal/tickets/tickets.getters.js.map +1 -0
- package/dist/municipal/tickets/tickets.types.d.ts +35 -0
- package/dist/municipal/tickets/tickets.types.d.ts.map +1 -0
- package/dist/municipal/tickets/tickets.types.js +3 -0
- package/dist/municipal/tickets/tickets.types.js.map +1 -0
- package/dist/talkpilot/agents/agents.getters.d.ts +9 -0
- package/dist/talkpilot/agents/agents.getters.d.ts.map +1 -0
- package/dist/talkpilot/agents/agents.getters.js +34 -0
- package/dist/talkpilot/agents/agents.getters.js.map +1 -0
- package/dist/talkpilot/agents/agents.types.d.ts +13 -0
- package/dist/talkpilot/agents/agents.types.d.ts.map +1 -0
- package/dist/talkpilot/agents/agents.types.js +3 -0
- package/dist/talkpilot/agents/agents.types.js.map +1 -0
- package/dist/talkpilot/agents/index.d.ts +3 -0
- package/dist/talkpilot/agents/index.d.ts.map +1 -0
- package/dist/talkpilot/agents/index.js +19 -0
- package/dist/talkpilot/agents/index.js.map +1 -0
- package/dist/talkpilot/calls/calls.getters.d.ts +24 -0
- package/dist/talkpilot/calls/calls.getters.d.ts.map +1 -0
- package/dist/talkpilot/calls/calls.getters.js +151 -0
- package/dist/talkpilot/calls/calls.getters.js.map +1 -0
- package/dist/talkpilot/calls/calls.types.d.ts +32 -0
- package/dist/talkpilot/calls/calls.types.d.ts.map +1 -0
- package/dist/talkpilot/calls/calls.types.js +3 -0
- package/dist/talkpilot/calls/calls.types.js.map +1 -0
- package/dist/talkpilot/calls/index.d.ts +3 -0
- package/dist/talkpilot/calls/index.d.ts.map +1 -0
- package/dist/talkpilot/calls/index.js +19 -0
- package/dist/talkpilot/calls/index.js.map +1 -0
- package/dist/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.d.ts +9 -0
- package/dist/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.d.ts.map +1 -0
- package/dist/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.js +76 -0
- package/dist/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.js.map +1 -0
- package/dist/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.d.ts +23 -0
- package/dist/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.d.ts.map +1 -0
- package/dist/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.js +3 -0
- package/dist/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.js.map +1 -0
- package/dist/talkpilot/clients/clients.getters.d.ts +5 -0
- package/dist/talkpilot/clients/clients.getters.d.ts.map +1 -0
- package/dist/talkpilot/clients/clients.getters.js +14 -0
- package/dist/talkpilot/clients/clients.getters.js.map +1 -0
- package/dist/talkpilot/clients/clients.types.d.ts +12 -0
- package/dist/talkpilot/clients/clients.types.d.ts.map +1 -0
- package/dist/talkpilot/clients/clients.types.js +3 -0
- package/dist/talkpilot/clients/clients.types.js.map +1 -0
- package/dist/talkpilot/clients/index.d.ts +3 -0
- package/dist/talkpilot/clients/index.d.ts.map +1 -0
- package/dist/talkpilot/clients/index.js +18 -0
- package/dist/talkpilot/clients/index.js.map +1 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.getters.d.ts +7 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.getters.d.ts.map +1 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.getters.js +21 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.getters.js.map +1 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.types.d.ts +53 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.types.d.ts.map +1 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.types.js +3 -0
- package/dist/talkpilot/clientsConfig/clientsConfig.types.js.map +1 -0
- package/dist/talkpilot/clientsConfig/index.d.ts +3 -0
- package/dist/talkpilot/clientsConfig/index.d.ts.map +1 -0
- package/dist/talkpilot/clientsConfig/index.js +19 -0
- package/dist/talkpilot/clientsConfig/index.js.map +1 -0
- package/dist/talkpilot/flows/flows.getter.d.ts +5 -0
- package/dist/talkpilot/flows/flows.getter.d.ts.map +1 -0
- package/dist/talkpilot/flows/flows.getter.js +13 -0
- package/dist/talkpilot/flows/flows.getter.js.map +1 -0
- package/dist/talkpilot/flows/flows.schema.d.ts +154 -0
- package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -0
- package/dist/talkpilot/flows/flows.schema.js +94 -0
- package/dist/talkpilot/flows/flows.schema.js.map +1 -0
- package/dist/talkpilot/flows/flows.types.d.ts +116 -0
- package/dist/talkpilot/flows/flows.types.d.ts.map +1 -0
- package/dist/talkpilot/flows/flows.types.js +3 -0
- package/dist/talkpilot/flows/flows.types.js.map +1 -0
- package/dist/talkpilot/flows/index.d.ts +3 -0
- package/dist/talkpilot/flows/index.d.ts.map +1 -0
- package/dist/talkpilot/flows/index.js +6 -0
- package/dist/talkpilot/flows/index.js.map +1 -0
- package/dist/talkpilot/groups/groups.getters.d.ts +8 -0
- package/dist/talkpilot/groups/groups.getters.d.ts.map +1 -0
- package/dist/talkpilot/groups/groups.getters.js +26 -0
- package/dist/talkpilot/groups/groups.getters.js.map +1 -0
- package/dist/talkpilot/groups/groups.types.d.ts +26 -0
- package/dist/talkpilot/groups/groups.types.d.ts.map +1 -0
- package/dist/talkpilot/groups/groups.types.js +3 -0
- package/dist/talkpilot/groups/groups.types.js.map +1 -0
- package/dist/talkpilot/groups/index.d.ts +3 -0
- package/dist/talkpilot/groups/index.d.ts.map +1 -0
- package/dist/talkpilot/groups/index.js +19 -0
- package/dist/talkpilot/groups/index.js.map +1 -0
- package/dist/talkpilot/groups/phone.utils.d.ts +4 -0
- package/dist/talkpilot/groups/phone.utils.d.ts.map +1 -0
- package/dist/talkpilot/groups/phone.utils.js +42 -0
- package/dist/talkpilot/groups/phone.utils.js.map +1 -0
- package/dist/talkpilot/index.d.ts +19 -0
- package/dist/talkpilot/index.d.ts.map +1 -0
- package/dist/talkpilot/index.js +46 -0
- package/dist/talkpilot/index.js.map +1 -0
- package/dist/talkpilot/leads/index.d.ts +3 -0
- package/dist/talkpilot/leads/index.d.ts.map +1 -0
- package/dist/talkpilot/leads/index.js +6 -0
- package/dist/talkpilot/leads/index.js.map +1 -0
- package/dist/talkpilot/leads/leads.getter.d.ts +4 -0
- package/dist/talkpilot/leads/leads.getter.d.ts.map +1 -0
- package/dist/talkpilot/leads/leads.getter.js +7 -0
- package/dist/talkpilot/leads/leads.getter.js.map +1 -0
- package/dist/talkpilot/leads/leads.schema.d.ts +50 -0
- package/dist/talkpilot/leads/leads.schema.d.ts.map +1 -0
- package/dist/talkpilot/leads/leads.schema.js +37 -0
- package/dist/talkpilot/leads/leads.schema.js.map +1 -0
- package/dist/talkpilot/leads/leads.types.d.ts +18 -0
- package/dist/talkpilot/leads/leads.types.d.ts.map +1 -0
- package/dist/talkpilot/leads/leads.types.js +3 -0
- package/dist/talkpilot/leads/leads.types.js.map +1 -0
- package/dist/talkpilot/mongodb-client.d.ts +13 -0
- package/dist/talkpilot/mongodb-client.d.ts.map +1 -0
- package/dist/talkpilot/mongodb-client.js +71 -0
- package/dist/talkpilot/mongodb-client.js.map +1 -0
- package/dist/talkpilot/phone_numbers/index.d.ts +3 -0
- package/dist/talkpilot/phone_numbers/index.d.ts.map +1 -0
- package/dist/talkpilot/phone_numbers/index.js +18 -0
- package/dist/talkpilot/phone_numbers/index.js.map +1 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts +8 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts.map +1 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.js +44 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.getter.js.map +1 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.schema.d.ts +29 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.schema.d.ts.map +1 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.schema.js +18 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.schema.js.map +1 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.types.d.ts +16 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.types.d.ts.map +1 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.types.js +3 -0
- package/dist/talkpilot/phone_numbers/phone_numbers.types.js.map +1 -0
- package/dist/talkpilot/plans/index.d.ts +3 -0
- package/dist/talkpilot/plans/index.d.ts.map +1 -0
- package/dist/talkpilot/plans/index.js +19 -0
- package/dist/talkpilot/plans/index.js.map +1 -0
- package/dist/talkpilot/plans/plans.getters.d.ts +10 -0
- package/dist/talkpilot/plans/plans.getters.d.ts.map +1 -0
- package/dist/talkpilot/plans/plans.getters.js +103 -0
- package/dist/talkpilot/plans/plans.getters.js.map +1 -0
- package/dist/talkpilot/plans/plans.types.d.ts +53 -0
- package/dist/talkpilot/plans/plans.types.d.ts.map +1 -0
- package/dist/talkpilot/plans/plans.types.js +29 -0
- package/dist/talkpilot/plans/plans.types.js.map +1 -0
- package/dist/talkpilot/results/index.d.ts +3 -0
- package/dist/talkpilot/results/index.d.ts.map +1 -0
- package/dist/talkpilot/results/index.js +6 -0
- package/dist/talkpilot/results/index.js.map +1 -0
- package/dist/talkpilot/results/results.getter.d.ts +7 -0
- package/dist/talkpilot/results/results.getter.d.ts.map +1 -0
- package/dist/talkpilot/results/results.getter.js +26 -0
- package/dist/talkpilot/results/results.getter.js.map +1 -0
- package/dist/talkpilot/results/results.schema.d.ts +35 -0
- package/dist/talkpilot/results/results.schema.d.ts.map +1 -0
- package/dist/talkpilot/results/results.schema.js +29 -0
- package/dist/talkpilot/results/results.schema.js.map +1 -0
- package/dist/talkpilot/results/results.types.d.ts +34 -0
- package/dist/talkpilot/results/results.types.d.ts.map +1 -0
- package/dist/talkpilot/results/results.types.js +3 -0
- package/dist/talkpilot/results/results.types.js.map +1 -0
- package/dist/talkpilot/sessions/index.d.ts +3 -0
- package/dist/talkpilot/sessions/index.d.ts.map +1 -0
- package/dist/talkpilot/sessions/index.js +6 -0
- package/dist/talkpilot/sessions/index.js.map +1 -0
- package/dist/talkpilot/sessions/sessions.getter.d.ts +7 -0
- package/dist/talkpilot/sessions/sessions.getter.d.ts.map +1 -0
- package/dist/talkpilot/sessions/sessions.getter.js +26 -0
- package/dist/talkpilot/sessions/sessions.getter.js.map +1 -0
- package/dist/talkpilot/sessions/sessions.schema.d.ts +53 -0
- package/dist/talkpilot/sessions/sessions.schema.d.ts.map +1 -0
- package/dist/talkpilot/sessions/sessions.schema.js +38 -0
- package/dist/talkpilot/sessions/sessions.schema.js.map +1 -0
- package/dist/talkpilot/sessions/sessions.types.d.ts +22 -0
- package/dist/talkpilot/sessions/sessions.types.d.ts.map +1 -0
- package/dist/talkpilot/sessions/sessions.types.js +3 -0
- package/dist/talkpilot/sessions/sessions.types.js.map +1 -0
- package/dist/talkpilot/subscriptions/index.d.ts +4 -0
- package/dist/talkpilot/subscriptions/index.d.ts.map +1 -0
- package/dist/talkpilot/subscriptions/index.js +20 -0
- package/dist/talkpilot/subscriptions/index.js.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.d.ts +13 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.d.ts.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.js +105 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.js.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.utils.d.ts +8 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.utils.d.ts.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.utils.js +27 -0
- package/dist/talkpilot/subscriptions/subscriptions.getters.utils.js.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.types.d.ts +50 -0
- package/dist/talkpilot/subscriptions/subscriptions.types.d.ts.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.types.js +14 -0
- package/dist/talkpilot/subscriptions/subscriptions.types.js.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts +4 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.js +20 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.js.map +1 -0
- package/dist/test-utils/db-utils.d.ts +4 -0
- package/dist/test-utils/db-utils.d.ts.map +1 -0
- package/dist/test-utils/db-utils.js +28 -0
- package/dist/test-utils/db-utils.js.map +1 -0
- package/dist/test-utils/factories/index.d.ts +13 -0
- package/dist/test-utils/factories/index.d.ts.map +1 -0
- package/dist/test-utils/factories/index.js +29 -0
- package/dist/test-utils/factories/index.js.map +1 -0
- package/dist/test-utils/factories/municipal/cities.d.ts +5 -0
- package/dist/test-utils/factories/municipal/cities.d.ts.map +1 -0
- package/dist/test-utils/factories/municipal/cities.js +18 -0
- package/dist/test-utils/factories/municipal/cities.js.map +1 -0
- package/dist/test-utils/factories/municipal/departmentsSubjects.d.ts +5 -0
- package/dist/test-utils/factories/municipal/departmentsSubjects.d.ts.map +1 -0
- package/dist/test-utils/factories/municipal/departmentsSubjects.js +27 -0
- package/dist/test-utils/factories/municipal/departmentsSubjects.js.map +1 -0
- package/dist/test-utils/factories/municipal/streets.d.ts +5 -0
- package/dist/test-utils/factories/municipal/streets.d.ts.map +1 -0
- package/dist/test-utils/factories/municipal/streets.js +19 -0
- package/dist/test-utils/factories/municipal/streets.js.map +1 -0
- package/dist/test-utils/factories/municipal/tickets.d.ts +5 -0
- package/dist/test-utils/factories/municipal/tickets.d.ts.map +1 -0
- package/dist/test-utils/factories/municipal/tickets.js +27 -0
- package/dist/test-utils/factories/municipal/tickets.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/agents.d.ts +5 -0
- package/dist/test-utils/factories/talkpilot/agents.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/agents.js +21 -0
- package/dist/test-utils/factories/talkpilot/agents.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/calls.d.ts +6 -0
- package/dist/test-utils/factories/talkpilot/calls.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/calls.js +39 -0
- package/dist/test-utils/factories/talkpilot/calls.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/clientAudioBuffers.d.ts +5 -0
- package/dist/test-utils/factories/talkpilot/clientAudioBuffers.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/clientAudioBuffers.js +18 -0
- package/dist/test-utils/factories/talkpilot/clientAudioBuffers.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/clientsConfig.d.ts +5 -0
- package/dist/test-utils/factories/talkpilot/clientsConfig.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/clientsConfig.js +18 -0
- package/dist/test-utils/factories/talkpilot/clientsConfig.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/flows.d.ts +14 -0
- package/dist/test-utils/factories/talkpilot/flows.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/flows.js +33 -0
- package/dist/test-utils/factories/talkpilot/flows.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/groups.d.ts +6 -0
- package/dist/test-utils/factories/talkpilot/groups.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/groups.js +34 -0
- package/dist/test-utils/factories/talkpilot/groups.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/phone_numbers.d.ts +16 -0
- package/dist/test-utils/factories/talkpilot/phone_numbers.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/phone_numbers.js +20 -0
- package/dist/test-utils/factories/talkpilot/phone_numbers.js.map +1 -0
- package/dist/test-utils/factories/talkpilot/sessions.d.ts +5 -0
- package/dist/test-utils/factories/talkpilot/sessions.d.ts.map +1 -0
- package/dist/test-utils/factories/talkpilot/sessions.js +37 -0
- package/dist/test-utils/factories/talkpilot/sessions.js.map +1 -0
- package/dist/utils/validation.d.ts +7 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +23 -0
- package/dist/utils/validation.js.map +1 -0
- package/jest.config.js +22 -0
- package/package.json +43 -0
- package/src/__tests__/setup.ts +20 -0
- package/src/index.ts +13 -0
- package/src/municipal/__tests__/validation.spec.ts +50 -0
- package/src/municipal/cities/cities.getters.ts +44 -0
- package/src/municipal/cities/cities.types.ts +11 -0
- package/src/municipal/cities/index.ts +2 -0
- package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +273 -0
- package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +76 -0
- package/src/municipal/departmentsSubjects/index.ts +11 -0
- package/src/municipal/index.ts +18 -0
- package/src/municipal/mongodb-client.ts +58 -0
- package/src/municipal/streets/index.ts +2 -0
- package/src/municipal/streets/streets.getters.ts +105 -0
- package/src/municipal/streets/streets.types.ts +18 -0
- package/src/municipal/tickets/__tests__/tickets.getters.spec.ts +30 -0
- package/src/municipal/tickets/index.ts +2 -0
- package/src/municipal/tickets/tickets.getters.ts +234 -0
- package/src/municipal/tickets/tickets.types.ts +39 -0
- package/src/talkpilot/__tests__/db.spec.ts +38 -0
- package/src/talkpilot/__tests__/mongodb-client.spec.ts +19 -0
- package/src/talkpilot/__tests__/validation.spec.ts +62 -0
- package/src/talkpilot/agents/__tests__/agents.getters.spec.ts +29 -0
- package/src/talkpilot/agents/agents.getters.ts +34 -0
- package/src/talkpilot/agents/agents.types.ts +14 -0
- package/src/talkpilot/agents/index.ts +2 -0
- package/src/talkpilot/calls/__tests__/calls.spec.ts +56 -0
- package/src/talkpilot/calls/calls.getters.ts +134 -0
- package/src/talkpilot/calls/calls.types.ts +45 -0
- package/src/talkpilot/calls/index.ts +2 -0
- package/src/talkpilot/clientAudioBuffers/__tests__/clientAudioBuffer.getters.spec.ts +78 -0
- package/src/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.ts +101 -0
- package/src/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.ts +25 -0
- package/src/talkpilot/clients/clients.getters.ts +11 -0
- package/src/talkpilot/clients/clients.types.ts +12 -0
- package/src/talkpilot/clients/index.ts +2 -0
- package/src/talkpilot/clientsConfig/__tests__/clientsConfig.spec.ts +28 -0
- package/src/talkpilot/clientsConfig/clientsConfig.getters.ts +20 -0
- package/src/talkpilot/clientsConfig/clientsConfig.types.ts +55 -0
- package/src/talkpilot/clientsConfig/index.ts +2 -0
- package/src/talkpilot/flows/flows.getter.ts +11 -0
- package/src/talkpilot/flows/flows.schema.ts +90 -0
- package/src/talkpilot/flows/flows.types.ts +151 -0
- package/src/talkpilot/flows/index.ts +2 -0
- package/src/talkpilot/groups/__tests__/groups.spec.ts +83 -0
- package/src/talkpilot/groups/__tests__/phone.utils.spec.ts +32 -0
- package/src/talkpilot/groups/groups.getters.ts +27 -0
- package/src/talkpilot/groups/groups.types.ts +29 -0
- package/src/talkpilot/groups/index.ts +2 -0
- package/src/talkpilot/groups/phone.utils.ts +40 -0
- package/src/talkpilot/index.ts +27 -0
- package/src/talkpilot/leads/index.ts +2 -0
- package/src/talkpilot/leads/leads.getter.ts +5 -0
- package/src/talkpilot/leads/leads.schema.ts +33 -0
- package/src/talkpilot/leads/leads.types.ts +20 -0
- package/src/talkpilot/mongodb-client.ts +78 -0
- package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +43 -0
- package/src/talkpilot/phone_numbers/index.ts +2 -0
- package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +47 -0
- package/src/talkpilot/phone_numbers/phone_numbers.schema.ts +14 -0
- package/src/talkpilot/phone_numbers/phone_numbers.types.ts +15 -0
- package/src/talkpilot/plans/index.ts +2 -0
- package/src/talkpilot/plans/plans.getters.ts +121 -0
- package/src/talkpilot/plans/plans.types.ts +84 -0
- package/src/talkpilot/results/index.ts +2 -0
- package/src/talkpilot/results/results.getter.ts +26 -0
- package/src/talkpilot/results/results.schema.ts +25 -0
- package/src/talkpilot/results/results.types.ts +32 -0
- package/src/talkpilot/sessions/__tests__/sessions.spec.ts +43 -0
- package/src/talkpilot/sessions/index.ts +2 -0
- package/src/talkpilot/sessions/sessions.getter.ts +28 -0
- package/src/talkpilot/sessions/sessions.schema.ts +34 -0
- package/src/talkpilot/sessions/sessions.types.ts +28 -0
- package/src/talkpilot/subscriptions/__tests__/subscriptions.getters.utils.spec.ts +42 -0
- package/src/talkpilot/subscriptions/index.ts +3 -0
- package/src/talkpilot/subscriptions/subscriptions.getters.ts +147 -0
- package/src/talkpilot/subscriptions/subscriptions.getters.utils.ts +26 -0
- package/src/talkpilot/subscriptions/subscriptions.types.ts +65 -0
- package/src/test-utils/db-utils.ts +24 -0
- package/src/test-utils/factories/index.ts +12 -0
- package/src/test-utils/factories/municipal/cities.ts +16 -0
- package/src/test-utils/factories/municipal/departmentsSubjects.ts +29 -0
- package/src/test-utils/factories/municipal/streets.ts +17 -0
- package/src/test-utils/factories/municipal/tickets.ts +27 -0
- package/src/test-utils/factories/talkpilot/agents.ts +19 -0
- package/src/test-utils/factories/talkpilot/calls.ts +37 -0
- package/src/test-utils/factories/talkpilot/clientAudioBuffers.ts +18 -0
- package/src/test-utils/factories/talkpilot/clientsConfig.ts +19 -0
- package/src/test-utils/factories/talkpilot/flows.ts +31 -0
- package/src/test-utils/factories/talkpilot/groups.ts +33 -0
- package/src/test-utils/factories/talkpilot/phone_numbers.ts +20 -0
- package/src/test-utils/factories/talkpilot/sessions.ts +35 -0
- package/src/utils/validation.ts +23 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { CityName, getDb, ObjectId, Ticket } from '../index';
|
|
2
|
+
import type { SubjectStatsItem } from './tickets.types';
|
|
3
|
+
import { Collection, Filter, ObjectId as MongoObjectId } from 'mongodb';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate a new ticket ID as a string
|
|
7
|
+
* @returns A new ObjectId as a string
|
|
8
|
+
*/
|
|
9
|
+
export const generateTicketId = (): string => {
|
|
10
|
+
return new ObjectId().toString();
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const getTicketsCollection = (): Collection<Ticket> => {
|
|
14
|
+
return getDb().collection<Ticket>('tickets');
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const findTickets = async (filter: Filter<Ticket> = {}): Promise<Ticket[]> => {
|
|
18
|
+
return await getTicketsCollection().find(filter).toArray();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const findTicketsByCallSid = async (callSid: string): Promise<Ticket[]> => {
|
|
22
|
+
return await getTicketsCollection().find({ callSid }).toArray();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const getTicketById = async (ticketId: string): Promise<Ticket | null> => {
|
|
26
|
+
const ticket = await getTicketsCollection().findOne({ _id: new ObjectId(ticketId) });
|
|
27
|
+
return ticket ? ticket : null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const createTicket = async (
|
|
31
|
+
ticketData: Omit<Ticket, '_id' | 'createdAt' | 'updatedAt'>,
|
|
32
|
+
ticketId?: string
|
|
33
|
+
): Promise<MongoObjectId> => {
|
|
34
|
+
const ticket: Ticket = {
|
|
35
|
+
_id: ticketId ? new ObjectId(ticketId) : new ObjectId(),
|
|
36
|
+
...ticketData,
|
|
37
|
+
createdAt: new Date(),
|
|
38
|
+
updatedAt: new Date(),
|
|
39
|
+
};
|
|
40
|
+
const { insertedId } = await getTicketsCollection().insertOne(ticket);
|
|
41
|
+
return insertedId;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const updateTicket = async (
|
|
45
|
+
ticketId: string,
|
|
46
|
+
data: Partial<Omit<Ticket, '_id' | 'createdAt' | 'updatedAt'>>
|
|
47
|
+
): Promise<Ticket | null> => {
|
|
48
|
+
const result = await getTicketsCollection().findOneAndUpdate(
|
|
49
|
+
{ _id: new ObjectId(ticketId) },
|
|
50
|
+
{ $set: { ...data, updatedAt: new Date() } },
|
|
51
|
+
{ returnDocument: 'after' }
|
|
52
|
+
);
|
|
53
|
+
return result || null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const deleteTicket = async (ticketId: string): Promise<boolean> => {
|
|
57
|
+
const result = await getTicketsCollection().deleteOne({ _id: new ObjectId(ticketId) });
|
|
58
|
+
return result.deletedCount > 0;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Count tickets by city and date range (createdAt converted to given timezone).
|
|
63
|
+
* Used as "open" tickets count when status is not available.
|
|
64
|
+
*/
|
|
65
|
+
export async function getTicketsCountByCityAndDateRange(
|
|
66
|
+
cityName: string,
|
|
67
|
+
startStr: string,
|
|
68
|
+
endStr: string,
|
|
69
|
+
timezone: string
|
|
70
|
+
): Promise<number> {
|
|
71
|
+
const doc = await getTicketsCollection()
|
|
72
|
+
.aggregate<{ n: number }>([
|
|
73
|
+
{ $match: { cityName } },
|
|
74
|
+
{
|
|
75
|
+
$addFields: {
|
|
76
|
+
dateLocal: {
|
|
77
|
+
$dateToString: { format: '%Y-%m-%d', date: '$createdAt', timezone },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{ $match: { dateLocal: { $gte: startStr, $lte: endStr } } },
|
|
82
|
+
{ $count: 'n' },
|
|
83
|
+
])
|
|
84
|
+
.next();
|
|
85
|
+
return doc?.n ?? 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Count of tickets by department (subject) from departmentsSubjects. Different departments (subject_id) are grouped, and sub-subjects are unified under their department.
|
|
90
|
+
* Date filter: createdAt in [startStr, endStr] (in the given timezone). Fallback to "Unclassified" when no match is found in the lookup.
|
|
91
|
+
*/
|
|
92
|
+
export async function getTicketsSubjectStats(
|
|
93
|
+
cityName: string,
|
|
94
|
+
startStr: string,
|
|
95
|
+
endStr: string,
|
|
96
|
+
timezone: string
|
|
97
|
+
): Promise<SubjectStatsItem[]> {
|
|
98
|
+
const coll = getTicketsCollection();
|
|
99
|
+
const rows = await coll
|
|
100
|
+
.aggregate<{ _id: string; subject: string; count: number }>([
|
|
101
|
+
{ $match: { cityName } },
|
|
102
|
+
{
|
|
103
|
+
$addFields: {
|
|
104
|
+
dateLocal: {
|
|
105
|
+
$dateToString: { format: '%Y-%m-%d', date: '$createdAt', timezone },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{ $match: { dateLocal: { $gte: startStr, $lte: endStr } } },
|
|
110
|
+
{
|
|
111
|
+
$addFields: {
|
|
112
|
+
effectiveSubjectId: {
|
|
113
|
+
$ifNull: [
|
|
114
|
+
'$externalCallFields.event_subject_id',
|
|
115
|
+
{
|
|
116
|
+
$ifNull: [
|
|
117
|
+
'$externalCallFields.event_sub_subject_id',
|
|
118
|
+
'$externalCallFields.event_sub_subject_id2',
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
$lookup: {
|
|
127
|
+
from: 'departmentsSubjects',
|
|
128
|
+
let: { sid: '$effectiveSubjectId', c: cityName },
|
|
129
|
+
pipeline: [
|
|
130
|
+
{
|
|
131
|
+
$match: {
|
|
132
|
+
$expr: {
|
|
133
|
+
$and: [
|
|
134
|
+
{ $eq: ['$cityName', '$$c'] },
|
|
135
|
+
{
|
|
136
|
+
$or: [
|
|
137
|
+
{ $eq: ['$subject_id', { $ifNull: ['$$sid', ''] }] },
|
|
138
|
+
{ $eq: ['$sub_subject_id', { $ifNull: ['$$sid', ''] }] },
|
|
139
|
+
{ $eq: ['$sub_subject_id2', { $ifNull: ['$$sid', ''] }] },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{ $limit: 1 },
|
|
147
|
+
],
|
|
148
|
+
as: 'subj',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
$addFields: {
|
|
153
|
+
subject_id: {
|
|
154
|
+
$cond: {
|
|
155
|
+
if: { $gt: [{ $size: '$subj' }, 0] },
|
|
156
|
+
then: { $ifNull: [{ $arrayElemAt: ['$subj.subject_id', 0] }, ''] },
|
|
157
|
+
else: '',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
subject: {
|
|
161
|
+
$cond: {
|
|
162
|
+
if: { $gt: [{ $size: '$subj' }, 0] },
|
|
163
|
+
then: { $ifNull: [{ $arrayElemAt: ['$subj.subjectName', 0] }, 'Unclassified'] },
|
|
164
|
+
else: 'Unclassified',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{ $group: { _id: '$subject_id', subject: { $first: '$subject' }, count: { $sum: 1 } } },
|
|
170
|
+
{ $sort: { count: -1 } },
|
|
171
|
+
])
|
|
172
|
+
.toArray();
|
|
173
|
+
|
|
174
|
+
const total = rows.reduce((s: number, r: any) => s + r.count, 0);
|
|
175
|
+
return rows.map((r: any) => ({
|
|
176
|
+
subject_name: r.subject,
|
|
177
|
+
subject_id: r._id,
|
|
178
|
+
count: r.count,
|
|
179
|
+
percentage: total > 0 ? Math.round((r.count / total) * 100) : 0,
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export const findTicketByQuery = async (query: Partial<Ticket>) => {
|
|
184
|
+
return await getTicketsCollection().findOne(query);
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Update ticket files by external call number
|
|
188
|
+
*/
|
|
189
|
+
export const updateTicketFilesByCallNumber = async (params: {
|
|
190
|
+
cityName: CityName;
|
|
191
|
+
callNumber: string;
|
|
192
|
+
image1?: string;
|
|
193
|
+
image2?: string;
|
|
194
|
+
image3?: string;
|
|
195
|
+
}): Promise<boolean> => {
|
|
196
|
+
const { cityName, callNumber, image1, image2, image3 } = params;
|
|
197
|
+
|
|
198
|
+
const update: any = {};
|
|
199
|
+
if (image1) update['externalCallFields.image1'] = image1;
|
|
200
|
+
if (image2) update['externalCallFields.image2'] = image2;
|
|
201
|
+
if (image3) update['externalCallFields.image3'] = image3;
|
|
202
|
+
|
|
203
|
+
const result = await getTicketsCollection().updateOne(
|
|
204
|
+
{
|
|
205
|
+
cityName: cityName,
|
|
206
|
+
'externalCallFields.call_number': callNumber,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
$set: {
|
|
210
|
+
...update,
|
|
211
|
+
updatedAt: new Date(),
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
return result.matchedCount > 0;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Remove guestJwt from ticket by external call number
|
|
221
|
+
*/
|
|
222
|
+
export const clearGuestJwtByCallNumber = async (params: {
|
|
223
|
+
cityName: CityName;
|
|
224
|
+
callNumber: string;
|
|
225
|
+
}): Promise<boolean> => {
|
|
226
|
+
const { cityName, callNumber } = params;
|
|
227
|
+
|
|
228
|
+
const result = await getTicketsCollection().updateOne(
|
|
229
|
+
{ cityName, 'externalCallFields.call_number': callNumber },
|
|
230
|
+
{ $unset: { guestJwt: '' }, $set: { updatedAt: new Date() } }
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return result.matchedCount > 0;
|
|
234
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ObjectId, WithId } from 'mongodb';
|
|
2
|
+
import { CityName } from '../departmentsSubjects/departmentsSubjects.types';
|
|
3
|
+
|
|
4
|
+
export type Ticket = {
|
|
5
|
+
_id: ObjectId;
|
|
6
|
+
createdAt: Date;
|
|
7
|
+
updatedAt: Date;
|
|
8
|
+
callSid?: string;
|
|
9
|
+
cityName: CityName;
|
|
10
|
+
externalCallFields: {
|
|
11
|
+
// Request fields
|
|
12
|
+
first_name?: string;
|
|
13
|
+
last_name?: string;
|
|
14
|
+
event_description?: string;
|
|
15
|
+
street?: string;
|
|
16
|
+
house_number?: string;
|
|
17
|
+
event_subject_id?: string;
|
|
18
|
+
event_sub_subject_id?: string;
|
|
19
|
+
event_sub_subject_id2?: string | null;
|
|
20
|
+
// Response fields (only if external call was successful)
|
|
21
|
+
call_number?: string;
|
|
22
|
+
status?: number; // Response status from Bina API (1 = success)
|
|
23
|
+
error?: string; // Error message from Bina API if any
|
|
24
|
+
image1?: string;
|
|
25
|
+
image2?: string;
|
|
26
|
+
image3?: string;
|
|
27
|
+
};
|
|
28
|
+
guestJwt?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type TicketDoc = WithId<Ticket>;
|
|
32
|
+
|
|
33
|
+
/** Call count by department (subject). */
|
|
34
|
+
export type SubjectStatsItem = {
|
|
35
|
+
subject_name: string;
|
|
36
|
+
subject_id: string;
|
|
37
|
+
count: number;
|
|
38
|
+
percentage: number;
|
|
39
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getFlowsCollection,
|
|
3
|
+
getSessionsCollection,
|
|
4
|
+
getResultsCollection,
|
|
5
|
+
getLeadsCollection,
|
|
6
|
+
getPhoneNumbersCollection,
|
|
7
|
+
getClientsCollection,
|
|
8
|
+
ObjectId,
|
|
9
|
+
getPlansCollection,
|
|
10
|
+
getSubscriptionsCollection,
|
|
11
|
+
} from '../index';
|
|
12
|
+
|
|
13
|
+
import { ObjectId as MongoObjectId } from 'mongodb';
|
|
14
|
+
|
|
15
|
+
describe('talkpilot core/db', () => {
|
|
16
|
+
it.each([
|
|
17
|
+
['flows', getFlowsCollection],
|
|
18
|
+
['sessions', getSessionsCollection],
|
|
19
|
+
['results', getResultsCollection],
|
|
20
|
+
['leads', getLeadsCollection],
|
|
21
|
+
['phone_numbers', getPhoneNumbersCollection],
|
|
22
|
+
['clients', getClientsCollection],
|
|
23
|
+
['plans', getPlansCollection],
|
|
24
|
+
['subscriptions', getSubscriptionsCollection],
|
|
25
|
+
])('%s collection helper returns a "%s" collection', (name, getter) => {
|
|
26
|
+
expect(getter().collectionName).toBe(name);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('ObjectId re-export behaves like mongodb.ObjectId', () => {
|
|
30
|
+
expect(ObjectId).toBe(MongoObjectId);
|
|
31
|
+
|
|
32
|
+
const id = new ObjectId();
|
|
33
|
+
|
|
34
|
+
expect(id).toBeInstanceOf(MongoObjectId);
|
|
35
|
+
expect(ObjectId.isValid(id)).toBe(true);
|
|
36
|
+
expect(id.toHexString()).toHaveLength(24);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { mongodbClient } from '../mongodb-client';
|
|
2
|
+
import { getDb } from '../index';
|
|
3
|
+
|
|
4
|
+
describe('MongoDBClient', () => {
|
|
5
|
+
it('should have a connected database instance from global setup', () => {
|
|
6
|
+
const db = getDb();
|
|
7
|
+
expect(db).toBeDefined();
|
|
8
|
+
expect(db.databaseName).toBe('test'); // Based on our setup.ts
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should report as connected', async () => {
|
|
12
|
+
// Note: mongodbClient.connect() was called in global setup
|
|
13
|
+
// but through setDb, not necessarily through the client singleton instance
|
|
14
|
+
// since initTestDb calls setDb directly.
|
|
15
|
+
|
|
16
|
+
// In a real scenario, you'd use the client.
|
|
17
|
+
expect(true).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { mongodbClient } from '../mongodb-client';
|
|
2
|
+
import { MongoClient } from 'mongodb';
|
|
3
|
+
|
|
4
|
+
describe('MongoDBClient Validation', () => {
|
|
5
|
+
const originalEnv = process.env;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
process.env = { ...originalEnv };
|
|
9
|
+
delete process.env.MONGO_URI;
|
|
10
|
+
delete process.env.MONGODB_URI;
|
|
11
|
+
delete process.env.MONGODB_DB_NAME;
|
|
12
|
+
|
|
13
|
+
// Force reset singleton state
|
|
14
|
+
(mongodbClient as any).client = null;
|
|
15
|
+
(mongodbClient as any).db = null;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterAll(async () => {
|
|
19
|
+
process.env = originalEnv;
|
|
20
|
+
// Ensure we are disconnected
|
|
21
|
+
await mongodbClient.disconnect();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should throw error if no URI is provided', async () => {
|
|
25
|
+
await expect(mongodbClient.connect()).rejects.toThrow(
|
|
26
|
+
"[core-db] Configuration Error: 'MONGO_URI' is missing"
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should throw error if an invalid URI format is provided', async () => {
|
|
31
|
+
await expect(mongodbClient.connect('not-a-mongo-uri')).rejects.toThrow(
|
|
32
|
+
"[core-db] Connection Error: The provided MongoDB URI is invalid"
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should throw error if URI is valid but database name is missing', async () => {
|
|
37
|
+
// We mock the actual MongoClient connection so it doesn't try to hit a real network
|
|
38
|
+
const connectSpy = jest.spyOn(MongoClient.prototype, 'connect').mockResolvedValue({} as any);
|
|
39
|
+
|
|
40
|
+
const uriWithoutDb = 'mongodb://127.0.0.1:27017';
|
|
41
|
+
await expect(mongodbClient.connect(uriWithoutDb)).rejects.toThrow(
|
|
42
|
+
"[core-db] Database name not specified"
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
connectSpy.mockRestore();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should succeed when valid URI and DB name are provided', async () => {
|
|
49
|
+
const mockDb = { databaseName: 'my-db' };
|
|
50
|
+
const connectSpy = jest.spyOn(MongoClient.prototype, 'connect').mockResolvedValue({} as any);
|
|
51
|
+
const dbSpy = jest.spyOn(MongoClient.prototype, 'db').mockReturnValue(mockDb as any);
|
|
52
|
+
|
|
53
|
+
const validUri = 'mongodb://127.0.0.1:27017/my-db';
|
|
54
|
+
await mongodbClient.connect(validUri);
|
|
55
|
+
|
|
56
|
+
expect(mongodbClient.getDb()).toBeDefined();
|
|
57
|
+
expect(mongodbClient.getDb().databaseName).toBe('my-db');
|
|
58
|
+
|
|
59
|
+
connectSpy.mockRestore();
|
|
60
|
+
dbSpy.mockRestore();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { findAgents } from '../agents.getters';
|
|
2
|
+
import { setDb } from '../../index';
|
|
3
|
+
import { Db, Collection } from 'mongodb';
|
|
4
|
+
import { createAgent } from '../../../test-utils/factories';
|
|
5
|
+
|
|
6
|
+
describe('agents getters', () => {
|
|
7
|
+
let mockDb: Partial<Db>;
|
|
8
|
+
let mockCollection: Partial<Collection>;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
const mockAgent = createAgent({ name: 'Agent Smith' });
|
|
12
|
+
mockCollection = {
|
|
13
|
+
find: jest.fn().mockReturnValue({
|
|
14
|
+
toArray: jest.fn().mockResolvedValue([mockAgent]),
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
mockDb = {
|
|
18
|
+
collection: jest.fn().mockReturnValue(mockCollection),
|
|
19
|
+
};
|
|
20
|
+
setDb(mockDb as Db);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('findAgents should return agents', async () => {
|
|
24
|
+
const result = await findAgents();
|
|
25
|
+
|
|
26
|
+
expect(mockDb.collection).toHaveBeenCalledWith('agents');
|
|
27
|
+
expect(result[0].name).toBe('Agent Smith');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getDb, Agent, ObjectId } from '../index';
|
|
2
|
+
|
|
3
|
+
export const getAgentsCollection = () => {
|
|
4
|
+
return getDb().collection<Agent>('agents');
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const findAgents = async (filter: any = {}) => {
|
|
8
|
+
return getAgentsCollection().find(filter).toArray();
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const findAgentById = (agentId: string) => {
|
|
12
|
+
return getAgentsCollection().findOne({ _id: new ObjectId(agentId) });
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const findAgentsByClientId = (clientId: string) => {
|
|
16
|
+
return getAgentsCollection().find({ clientId }).toArray();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const createAgent = async (agent: Agent) => {
|
|
20
|
+
const { insertedId } = await getAgentsCollection().insertOne(agent);
|
|
21
|
+
return findAgentById(String(insertedId));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const updateAgent = (agentId: string, data: Partial<Agent>) => {
|
|
25
|
+
return getAgentsCollection().findOneAndUpdate(
|
|
26
|
+
{ _id: new ObjectId(agentId) },
|
|
27
|
+
{ $set: data },
|
|
28
|
+
{ returnDocument: 'after' }
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const removeAgent = (agentId: string) => {
|
|
33
|
+
return getAgentsCollection().deleteOne({ _id: new ObjectId(agentId) });
|
|
34
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { WithId } from 'mongodb';
|
|
2
|
+
|
|
3
|
+
export type Agent = {
|
|
4
|
+
name: string;
|
|
5
|
+
language: string;
|
|
6
|
+
voice: string;
|
|
7
|
+
instructions: string;
|
|
8
|
+
labels: string[];
|
|
9
|
+
clientId: string;
|
|
10
|
+
role: string;
|
|
11
|
+
gender: 'male' | 'female';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AgentDoc = WithId<Agent>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCallDoc,
|
|
3
|
+
getCallsByFlow,
|
|
4
|
+
getCallsByClient,
|
|
5
|
+
getCallsByPhoneNumber,
|
|
6
|
+
getCallByCallSid,
|
|
7
|
+
} from '../calls.getters';
|
|
8
|
+
import { ObjectId } from 'mongodb';
|
|
9
|
+
import { createOutGoingCallDoc } from '../../../test-utils/factories';
|
|
10
|
+
|
|
11
|
+
describe('db.calls', () => {
|
|
12
|
+
it('should return calls by flow', async () => {
|
|
13
|
+
const flowId = new ObjectId();
|
|
14
|
+
const call1 = createOutGoingCallDoc({ flowId });
|
|
15
|
+
const call2 = createOutGoingCallDoc({ flowId });
|
|
16
|
+
|
|
17
|
+
await createCallDoc(call1);
|
|
18
|
+
await createCallDoc(call2);
|
|
19
|
+
|
|
20
|
+
const result = await getCallsByFlow(flowId);
|
|
21
|
+
|
|
22
|
+
expect(result.length).toBe(2);
|
|
23
|
+
expect(result).toMatchObject([
|
|
24
|
+
{ callSid: call1.callSid },
|
|
25
|
+
{ callSid: call2.callSid }
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should get call by callSid', async () => {
|
|
30
|
+
const call = createOutGoingCallDoc();
|
|
31
|
+
await createCallDoc(call);
|
|
32
|
+
|
|
33
|
+
const result = await getCallByCallSid(call.callSid);
|
|
34
|
+
|
|
35
|
+
expect(result).toBeDefined();
|
|
36
|
+
expect(result?.callSid).toBe(call.callSid);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should get calls by client', async () => {
|
|
40
|
+
const call = createOutGoingCallDoc();
|
|
41
|
+
await createCallDoc(call);
|
|
42
|
+
|
|
43
|
+
const result = await getCallsByClient(call.clientId);
|
|
44
|
+
|
|
45
|
+
expect(result.some(c => c.callSid === call.callSid)).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should get calls by phone number', async () => {
|
|
49
|
+
const call = createOutGoingCallDoc();
|
|
50
|
+
await createCallDoc(call);
|
|
51
|
+
|
|
52
|
+
const result = await getCallsByPhoneNumber(call.customerPhoneNumber);
|
|
53
|
+
|
|
54
|
+
expect(result.some(c => c.callSid === call.callSid)).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { getDb, Call, CallDoc, CallUpdateParams } from '../index';
|
|
2
|
+
import type { CallsByHour } from './calls.types';
|
|
3
|
+
import { ObjectId } from 'mongodb';
|
|
4
|
+
import * as process from 'node:process';
|
|
5
|
+
|
|
6
|
+
export const getCallsCollection = () => {
|
|
7
|
+
return getDb().collection<Call>('calls');
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getCallByCallSid = (callSid: string) => {
|
|
11
|
+
return getCallsCollection().findOne({ callSid });
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const getCallsByPhoneNumber = (phoneNumber: string) => {
|
|
15
|
+
return getCallsCollection().find({ customerPhoneNumber: phoneNumber }).toArray();
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const getCallsByClient = (clientId: string) => {
|
|
19
|
+
return getCallsCollection().find({ clientId }).toArray();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const getCallsByFlow = (flowId: ObjectId) => {
|
|
23
|
+
return getCallsCollection().find({ flowId }).toArray();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const createCallDoc = (call: Omit<Call, 'createdAt' | 'updatedAt' | 'env'>) => {
|
|
27
|
+
return getCallsCollection().insertOne({
|
|
28
|
+
...call,
|
|
29
|
+
createdAt: new Date(),
|
|
30
|
+
updatedAt: new Date(),
|
|
31
|
+
env: process.env.ENV ?? 'unknown',
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const updateCallByCallSid = async (
|
|
36
|
+
callSid: string,
|
|
37
|
+
updates: CallUpdateParams
|
|
38
|
+
): Promise<CallDoc | null> => {
|
|
39
|
+
const result = await getCallsCollection().findOneAndUpdate(
|
|
40
|
+
{ callSid: callSid },
|
|
41
|
+
{
|
|
42
|
+
$set: {
|
|
43
|
+
...updates,
|
|
44
|
+
updatedAt: new Date(),
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{ returnDocument: 'after' }
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Aggregate calls stats for a date range (createdAt in [startStr, endStr] in timezone).
|
|
55
|
+
* completed = agentHungUp=true or status='completed'.
|
|
56
|
+
*/
|
|
57
|
+
export async function getCallsStatsForDateRange(
|
|
58
|
+
clientId: string,
|
|
59
|
+
startStr: string,
|
|
60
|
+
endStr: string,
|
|
61
|
+
timezone: string
|
|
62
|
+
): Promise<{ count: number; totalLen: number; completed: number }> {
|
|
63
|
+
const coll = getCallsCollection();
|
|
64
|
+
const out = await coll
|
|
65
|
+
.aggregate<{ _id: null; count: number; totalLen: number; completed: number }>([
|
|
66
|
+
// 1. Restrict to the given client
|
|
67
|
+
{ $match: { clientId } },
|
|
68
|
+
// 2. Derive dateLocal (createdAt as YYYY-MM-DD in timezone) and isCompleted (agentHungUp or status='completed')
|
|
69
|
+
{
|
|
70
|
+
$addFields: {
|
|
71
|
+
dateLocal: {
|
|
72
|
+
$dateToString: { format: '%Y-%m-%d', date: '$createdAt', timezone },
|
|
73
|
+
},
|
|
74
|
+
isCompleted: {
|
|
75
|
+
$or: [{ $eq: ['$agentHungUp', true] }, { $eq: ['$status', 'completed'] }],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
// 3. Keep only documents with dateLocal in [startStr, endStr] (inclusive)
|
|
80
|
+
{ $match: { dateLocal: { $gte: startStr, $lte: endStr } } },
|
|
81
|
+
// 4. Single group: count, totalLen, completed
|
|
82
|
+
{
|
|
83
|
+
$group: {
|
|
84
|
+
_id: null,
|
|
85
|
+
count: { $sum: 1 },
|
|
86
|
+
totalLen: { $sum: '$callLength' },
|
|
87
|
+
completed: { $sum: { $cond: ['$isCompleted', 1, 0] } },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
])
|
|
91
|
+
.next();
|
|
92
|
+
return {
|
|
93
|
+
count: out?.count ?? 0,
|
|
94
|
+
totalLen: out?.totalLen ?? 0,
|
|
95
|
+
completed: out?.completed ?? 0,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Aggregate calls by hour for a given date (createdAt converted to given timezone). Hour format "HH:mm".
|
|
101
|
+
*/
|
|
102
|
+
export async function getCallsHourlyAggregation(
|
|
103
|
+
clientId: string,
|
|
104
|
+
dateStr: string,
|
|
105
|
+
timezone: string
|
|
106
|
+
): Promise<CallsByHour[]> {
|
|
107
|
+
const coll = getCallsCollection();
|
|
108
|
+
const rows = await coll
|
|
109
|
+
.aggregate<{ _id: number; calls: number }>([
|
|
110
|
+
// 1. Restrict to the given client
|
|
111
|
+
{ $match: { clientId } },
|
|
112
|
+
// 2. Derive dateLocal (createdAt as YYYY-MM-DD in timezone) and hour (0–23 from createdAt in timezone)
|
|
113
|
+
{
|
|
114
|
+
$addFields: {
|
|
115
|
+
dateLocal: {
|
|
116
|
+
$dateToString: { format: '%Y-%m-%d', date: '$createdAt', timezone },
|
|
117
|
+
},
|
|
118
|
+
hour: { $hour: { date: '$createdAt', timezone } },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
// 3. Keep only the requested date
|
|
122
|
+
{ $match: { dateLocal: dateStr } },
|
|
123
|
+
// 4. Group by hour, sum calls per hour
|
|
124
|
+
{ $group: { _id: '$hour', calls: { $sum: 1 } } },
|
|
125
|
+
// 5. Order by hour ascending (0..23)
|
|
126
|
+
{ $sort: { _id: 1 } },
|
|
127
|
+
])
|
|
128
|
+
.toArray();
|
|
129
|
+
|
|
130
|
+
return rows.map((r: any) => ({
|
|
131
|
+
hour: `${String(r._id).padStart(2, '0')}:00`,
|
|
132
|
+
calls: r.calls,
|
|
133
|
+
}));
|
|
134
|
+
}
|