@talkpilot/core-db 1.3.89 → 1.3.90
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/README.md +0 -72
- package/dist/talkpilot/calls/calls.constants.d.ts +1 -11
- package/dist/talkpilot/calls/calls.constants.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.constants.js +1 -11
- package/dist/talkpilot/calls/calls.constants.js.map +1 -1
- package/dist/talkpilot/calls/calls.getters.d.ts +1 -8
- package/dist/talkpilot/calls/calls.getters.d.ts.map +1 -1
- package/dist/talkpilot/calls/calls.getters.js +1 -216
- package/dist/talkpilot/calls/calls.getters.js.map +1 -1
- package/dist/talkpilot/calls/calls.types.d.ts +0 -45
- package/dist/talkpilot/calls/calls.types.d.ts.map +1 -1
- package/dist/talkpilot/clients/clients.getters.d.ts +0 -6
- package/dist/talkpilot/clients/clients.getters.d.ts.map +1 -1
- package/dist/talkpilot/clients/clients.getters.js +1 -62
- package/dist/talkpilot/clients/clients.getters.js.map +1 -1
- package/dist/talkpilot/clients/clients.types.d.ts +0 -53
- 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/flows/flows.schema.d.ts +9 -0
- package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -1
- package/dist/talkpilot/flows/flows.schema.js +7 -0
- package/dist/talkpilot/flows/flows.schema.js.map +1 -1
- package/dist/talkpilot/flows/flows.types.d.ts +3 -0
- package/dist/talkpilot/flows/flows.types.d.ts.map +1 -1
- package/dist/talkpilot/index.d.ts +0 -1
- package/dist/talkpilot/index.d.ts.map +1 -1
- package/dist/talkpilot/index.js +0 -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 -70
- 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/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/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/dist/websitalk/scanResources/scanResources.getters.d.ts.map +1 -1
- package/dist/websitalk/scanResources/scanResources.getters.js +1 -2
- package/dist/websitalk/scanResources/scanResources.getters.js.map +1 -1
- package/dist/websitalk/scanResources/scanResources.utils.d.ts +1 -1
- package/dist/websitalk/scanResources/scanResources.utils.d.ts.map +1 -1
- package/dist/websitalk/scanResources/scanResources.utils.js +3 -3
- package/dist/websitalk/scanResources/scanResources.utils.js.map +1 -1
- package/package.json +1 -1
- package/src/talkpilot/calls/calls.constants.ts +0 -14
- package/src/talkpilot/calls/calls.getters.ts +0 -320
- package/src/talkpilot/calls/calls.types.ts +0 -52
- package/src/talkpilot/clients/clients.getters.ts +2 -91
- package/src/talkpilot/clients/clients.types.ts +0 -58
- package/src/talkpilot/clients/index.ts +0 -2
- package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +11 -0
- package/src/talkpilot/flows/flows.schema.ts +7 -0
- package/src/talkpilot/flows/flows.types.ts +1 -0
- package/src/talkpilot/index.ts +0 -1
- package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +13 -284
- package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +1 -89
- package/src/talkpilot/phone_numbers/phone_numbers.types.ts +0 -6
- package/src/test-utils/factories/index.ts +0 -2
- package/src/websitalk/scanResources/scanResources.getters.ts +6 -2
- package/src/websitalk/scanResources/scanResources.utils.ts +3 -2
- 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.types.d.ts +0 -11
- package/dist/talkpilot/auditLogs/auditLogs.types.d.ts.map +0 -1
- package/dist/talkpilot/auditLogs/auditLogs.types.js +0 -3
- 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 +0 -19
- package/dist/talkpilot/auditLogs/index.js.map +0 -1
- package/dist/talkpilot/clients/clients.constants.d.ts +0 -4
- package/dist/talkpilot/clients/clients.constants.d.ts.map +0 -1
- package/dist/talkpilot/clients/clients.constants.js +0 -7
- 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 -109
- package/dist/talkpilot/clients/clients.lifecycle.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/dist/utils/regex.utils.d.ts +0 -2
- package/dist/utils/regex.utils.d.ts.map +0 -1
- package/dist/utils/regex.utils.js +0 -6
- package/dist/utils/regex.utils.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 -559
- package/src/talkpilot/clients/__tests__/clients.getters.spec.ts +0 -224
- package/src/talkpilot/clients/__tests__/clients.lifecycle.spec.ts +0 -194
- package/src/talkpilot/clients/clients.constants.ts +0 -4
- package/src/talkpilot/clients/clients.lifecycle.ts +0 -132
- package/src/test-utils/factories/talkpilot/clients.ts +0 -21
- package/src/test-utils/factories/talkpilot/results.ts +0 -43
- package/src/utils/regex.utils.ts +0 -2
|
@@ -5,7 +5,6 @@ const mongodb_1 = require("mongodb");
|
|
|
5
5
|
const index_1 = require("../index");
|
|
6
6
|
const scanResources_constants_1 = require("./scanResources.constants");
|
|
7
7
|
const scanResources_utils_1 = require("./scanResources.utils");
|
|
8
|
-
const regex_utils_1 = require("../../utils/regex.utils");
|
|
9
8
|
const getScanResourcesCollection = () => (0, index_1.getDb)().collection(scanResources_constants_1.SCAN_RESOURCES_COLLECTION);
|
|
10
9
|
exports.getScanResourcesCollection = getScanResourcesCollection;
|
|
11
10
|
const getScanKpiCounts = async (scanId) => {
|
|
@@ -54,7 +53,7 @@ const getScanPages = async (query) => {
|
|
|
54
53
|
filter._id = { $gt: (0, scanResources_utils_1.decodeCursor)(query.cursor) };
|
|
55
54
|
}
|
|
56
55
|
if (query.search) {
|
|
57
|
-
const searchPattern = (0,
|
|
56
|
+
const searchPattern = (0, scanResources_utils_1.escapeRegex)(query.search);
|
|
58
57
|
filter.$or = [
|
|
59
58
|
{ url: { $regex: searchPattern, $options: "i" } },
|
|
60
59
|
{ title: { $regex: searchPattern, $options: "i" } },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanResources.getters.js","sourceRoot":"","sources":["../../../src/websitalk/scanResources/scanResources.getters.ts"],"names":[],"mappings":";;;AAAA,qCAAuD;AACvD,oCAAiC;AACjC,uEAOmC;AAUnC,+
|
|
1
|
+
{"version":3,"file":"scanResources.getters.js","sourceRoot":"","sources":["../../../src/websitalk/scanResources/scanResources.getters.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ObjectId } from "mongodb";
|
|
2
2
|
import type { BoardColumn, UrlTaskStatus } from "./scanResources.types";
|
|
3
|
-
export { escapeRegex } from "../../utils/regex.utils";
|
|
4
3
|
export declare const boardColumn: (status: UrlTaskStatus) => BoardColumn;
|
|
5
4
|
export declare const statusesForColumn: (column: BoardColumn) => readonly UrlTaskStatus[];
|
|
6
5
|
export declare const encodeCursor: (id: ObjectId) => string;
|
|
7
6
|
export declare const decodeCursor: (cursor: string) => ObjectId;
|
|
7
|
+
export declare const escapeRegex: (text: string) => string;
|
|
8
8
|
//# sourceMappingURL=scanResources.utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanResources.utils.d.ts","sourceRoot":"","sources":["../../../src/websitalk/scanResources/scanResources.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"scanResources.utils.d.ts","sourceRoot":"","sources":["../../../src/websitalk/scanResources/scanResources.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAcxE,eAAO,MAAM,WAAW,GAAI,QAAQ,aAAa,KAAG,WAC1B,CAAC;AAE3B,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,WAAW,KAClB,SAAS,aAAa,EAAmC,CAAC;AAE7D,eAAO,MAAM,YAAY,GAAI,IAAI,QAAQ,KAAG,MACM,CAAC;AAEnD,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,QACiB,CAAC;AAEhE,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,MACE,CAAC"}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.escapeRegex = exports.decodeCursor = exports.encodeCursor = exports.statusesForColumn = exports.boardColumn = void 0;
|
|
4
4
|
const mongodb_1 = require("mongodb");
|
|
5
5
|
const scanResources_constants_1 = require("./scanResources.constants");
|
|
6
|
-
var regex_utils_1 = require("../../utils/regex.utils");
|
|
7
|
-
Object.defineProperty(exports, "escapeRegex", { enumerable: true, get: function () { return regex_utils_1.escapeRegex; } });
|
|
8
6
|
const STATUS_TO_COLUMN = Object.entries(scanResources_constants_1.BOARD_COLUMN_STATUSES).reduce((acc, [column, statuses]) => {
|
|
9
7
|
for (const status of statuses) {
|
|
10
8
|
acc[status] = column;
|
|
@@ -19,4 +17,6 @@ const encodeCursor = (id) => Buffer.from(id.toHexString()).toString("base64");
|
|
|
19
17
|
exports.encodeCursor = encodeCursor;
|
|
20
18
|
const decodeCursor = (cursor) => new mongodb_1.ObjectId(Buffer.from(cursor, "base64").toString("utf-8"));
|
|
21
19
|
exports.decodeCursor = decodeCursor;
|
|
20
|
+
const escapeRegex = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
21
|
+
exports.escapeRegex = escapeRegex;
|
|
22
22
|
//# sourceMappingURL=scanResources.utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanResources.utils.js","sourceRoot":"","sources":["../../../src/websitalk/scanResources/scanResources.utils.ts"],"names":[],"mappings":";;;AAAA,qCAAmC;AACnC,uEAAkE;AAGlE,
|
|
1
|
+
{"version":3,"file":"scanResources.utils.js","sourceRoot":"","sources":["../../../src/websitalk/scanResources/scanResources.utils.ts"],"names":[],"mappings":";;;AAAA,qCAAmC;AACnC,uEAAkE;AAGlE,MAAM,gBAAgB,GAAuC,MAAM,CAAC,OAAO,CACzE,+CAAqB,CACtB,CAAC,MAAM,CACN,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE;IAC1B,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,MAAqB,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,EACD,EAAwC,CACzC,CAAC;AAEK,MAAM,WAAW,GAAG,CAAC,MAAqB,EAAe,EAAE,CAChE,gBAAgB,CAAC,MAAM,CAAC,CAAC;AADd,QAAA,WAAW,eACG;AAEpB,MAAM,iBAAiB,GAAG,CAC/B,MAAmB,EACO,EAAE,CAAC,+CAAqB,CAAC,MAAM,CAAC,CAAC;AAFhD,QAAA,iBAAiB,qBAE+B;AAEtD,MAAM,YAAY,GAAG,CAAC,EAAY,EAAU,EAAE,CACnD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AADtC,QAAA,YAAY,gBAC0B;AAE5C,MAAM,YAAY,GAAG,CAAC,MAAc,EAAY,EAAE,CACvD,IAAI,kBAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AADnD,QAAA,YAAY,gBACuC;AAEzD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE,CAClD,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AADjC,QAAA,WAAW,eACsB"}
|
package/package.json
CHANGED
|
@@ -16,18 +16,6 @@ export const FINAL_STATUSES = [
|
|
|
16
16
|
"canceled",
|
|
17
17
|
] as const;
|
|
18
18
|
|
|
19
|
-
/** sessionId used for calls that arrived without an existing session (incoming calls). */
|
|
20
|
-
export const INCOMING_SESSION_ID = "incomingCall";
|
|
21
|
-
|
|
22
|
-
/** sessionId used in the per-session breakdown for calls with no session that are not incoming. */
|
|
23
|
-
export const UNKNOWN_SESSION_ID = "unknownSession";
|
|
24
|
-
|
|
25
|
-
/** Twilio call statuses considered "currently active" for the live calls summary. */
|
|
26
|
-
export const ACTIVE_STATUSES = ["in-progress"];
|
|
27
|
-
|
|
28
|
-
/** Lookback window for the "active calls right now" summary. */
|
|
29
|
-
export const ACTIVE_CALLS_WINDOW_MS = 2 * 60 * 60 * 1000;
|
|
30
|
-
|
|
31
19
|
/** Hours in a single day. */
|
|
32
20
|
export const HOURS_PER_DAY = 24;
|
|
33
21
|
|
|
@@ -60,8 +48,6 @@ export const CallStatusValues = {
|
|
|
60
48
|
|
|
61
49
|
export const ALL_CALL_STATUSES = Object.values(CallStatusValues);
|
|
62
50
|
|
|
63
|
-
/** All statuses shown in the breakdown tables — kept separate so CallStatusValues stays untouched. */
|
|
64
|
-
export const ALL_STATUSES_FOR_BREAKDOWN = [...ALL_CALL_STATUSES, "queued"] as const;
|
|
65
51
|
/** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
|
|
66
52
|
export const CallEndedByValues = {
|
|
67
53
|
System: "system",
|
|
@@ -4,39 +4,22 @@ import {
|
|
|
4
4
|
CallQueryOptions,
|
|
5
5
|
CallUpdateParams,
|
|
6
6
|
getDb,
|
|
7
|
-
getClientsCollection,
|
|
8
7
|
} from "../index";
|
|
9
8
|
import type {
|
|
10
9
|
CountOpts,
|
|
11
10
|
DateRange,
|
|
12
11
|
ToolExecution,
|
|
13
12
|
CallStatus,
|
|
14
|
-
ActiveCallsSummary,
|
|
15
|
-
TodayCallsSummary,
|
|
16
|
-
ClientCallStatsPage,
|
|
17
|
-
ClientCallStatsParams,
|
|
18
|
-
SessionCallStats,
|
|
19
|
-
StatsDateRangeParams,
|
|
20
13
|
CallEndedBy,
|
|
21
14
|
} from "./calls.types";
|
|
22
15
|
import {
|
|
23
16
|
TOOL_EXECUTIONS_DEFAULT_LIMIT,
|
|
24
17
|
TOOL_EXECUTIONS_DEFAULT_SKIP,
|
|
25
|
-
ACTIVE_STATUSES,
|
|
26
|
-
ACTIVE_CALLS_WINDOW_MS,
|
|
27
|
-
INCOMING_SESSION_ID,
|
|
28
|
-
UNKNOWN_SESSION_ID,
|
|
29
|
-
ALL_STATUSES_FOR_BREAKDOWN,
|
|
30
18
|
} from "./calls.constants";
|
|
31
19
|
import { Filter, ObjectId } from "mongodb";
|
|
32
20
|
import * as process from "node:process";
|
|
33
21
|
import { applyQueryOptions } from "../utils/query.utils";
|
|
34
22
|
import { DashboardHeatmapMetric } from "./dashboard/calls.dashboard.types";
|
|
35
|
-
import {
|
|
36
|
-
formatYmdInTz,
|
|
37
|
-
startOfCalendarDayInTz,
|
|
38
|
-
endOfCalendarDayInTz,
|
|
39
|
-
} from "../../utils/date.utils";
|
|
40
23
|
|
|
41
24
|
export const getCallsCollection = () => {
|
|
42
25
|
return getDb().collection<Call>("calls");
|
|
@@ -310,306 +293,3 @@ export async function getCallsHourlyAggregation(
|
|
|
310
293
|
calls: r.calls,
|
|
311
294
|
}));
|
|
312
295
|
}
|
|
313
|
-
|
|
314
|
-
type StatusCountFields = { [K in (typeof ALL_STATUSES_FOR_BREAKDOWN)[number]]: number };
|
|
315
|
-
|
|
316
|
-
// One $sum/$cond accumulator per status in ALL_STATUSES_FOR_BREAKDOWN.
|
|
317
|
-
const buildStatusCountFields = (field: string) =>
|
|
318
|
-
Object.fromEntries(
|
|
319
|
-
ALL_STATUSES_FOR_BREAKDOWN.map((status) => [
|
|
320
|
-
status,
|
|
321
|
-
{ $sum: { $cond: [{ $eq: [field, status] }, 1, 0] } },
|
|
322
|
-
]),
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const extractStatusCounts = (row: StatusCountFields): Record<string, number> =>
|
|
326
|
-
Object.fromEntries(ALL_STATUSES_FOR_BREAKDOWN.map((status) => [status, row[status] ?? 0]));
|
|
327
|
-
|
|
328
|
-
const dateRangeFilter = (
|
|
329
|
-
dateFrom: string | undefined,
|
|
330
|
-
dateTo: string | undefined,
|
|
331
|
-
timezone: string,
|
|
332
|
-
): { start: Date; end: Date } => {
|
|
333
|
-
const today = formatYmdInTz(new Date(), timezone);
|
|
334
|
-
return {
|
|
335
|
-
start: startOfCalendarDayInTz(dateFrom ?? today, timezone),
|
|
336
|
-
end: endOfCalendarDayInTz(dateTo ?? today, timezone),
|
|
337
|
-
};
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
const buildCallsStatsMatch = ({
|
|
341
|
-
dateFrom,
|
|
342
|
-
dateTo,
|
|
343
|
-
clientId,
|
|
344
|
-
clientIds,
|
|
345
|
-
timezone = "UTC",
|
|
346
|
-
}: StatsDateRangeParams) => {
|
|
347
|
-
const range = dateFrom || dateTo ? dateRangeFilter(dateFrom, dateTo, timezone) : null;
|
|
348
|
-
const clientConditions = [
|
|
349
|
-
...(clientId ? [{ clientId }] : []),
|
|
350
|
-
...(clientIds ? [{ clientId: { $in: clientIds } }] : []),
|
|
351
|
-
];
|
|
352
|
-
return {
|
|
353
|
-
...(range ? { createdAt: { $gte: range.start, $lte: range.end } } : {}),
|
|
354
|
-
...(clientConditions.length > 0 ? { $and: clientConditions } : {}),
|
|
355
|
-
};
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
export const findClientIdsWithCalls = async ({
|
|
359
|
-
dateFrom,
|
|
360
|
-
dateTo,
|
|
361
|
-
timezone = "UTC",
|
|
362
|
-
}: StatsDateRangeParams): Promise<string[]> =>
|
|
363
|
-
getCallsCollection().distinct("clientId", buildCallsStatsMatch({ dateFrom, dateTo, timezone }));
|
|
364
|
-
|
|
365
|
-
export const aggregateActiveCallsSummary = async (
|
|
366
|
-
clientId?: string,
|
|
367
|
-
): Promise<ActiveCallsSummary> => {
|
|
368
|
-
const coll = getCallsCollection();
|
|
369
|
-
const twoHoursAgo = new Date(Date.now() - ACTIVE_CALLS_WINDOW_MS);
|
|
370
|
-
|
|
371
|
-
const match = {
|
|
372
|
-
status: { $in: ACTIVE_STATUSES },
|
|
373
|
-
updatedAt: { $gte: twoHoursAgo },
|
|
374
|
-
...(clientId ? { clientId } : {}),
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
const facetResult = await coll
|
|
378
|
-
.aggregate<{
|
|
379
|
-
counts: { total: number; incoming: number; outgoing: number }[];
|
|
380
|
-
activeClients: { _id: string }[];
|
|
381
|
-
}>([
|
|
382
|
-
{ $match: match },
|
|
383
|
-
{
|
|
384
|
-
$facet: {
|
|
385
|
-
counts: [
|
|
386
|
-
{
|
|
387
|
-
$group: {
|
|
388
|
-
_id: null,
|
|
389
|
-
total: { $sum: 1 },
|
|
390
|
-
incoming: { $sum: { $cond: ["$isIncomingCall", 1, 0] } },
|
|
391
|
-
outgoing: { $sum: { $cond: ["$isOutgoingCall", 1, 0] } },
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
],
|
|
395
|
-
activeClients: [{ $group: { _id: "$clientId" } }],
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
])
|
|
399
|
-
.next();
|
|
400
|
-
|
|
401
|
-
const counts = facetResult?.counts?.[0];
|
|
402
|
-
|
|
403
|
-
return {
|
|
404
|
-
total: counts?.total ?? 0,
|
|
405
|
-
incoming: counts?.incoming ?? 0,
|
|
406
|
-
outgoing: counts?.outgoing ?? 0,
|
|
407
|
-
activeClientIds: (facetResult?.activeClients ?? []).map((d) => d._id || "Unknown"),
|
|
408
|
-
};
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
export const aggregateTodayCallsSummary = async ({
|
|
412
|
-
dateFrom,
|
|
413
|
-
dateTo,
|
|
414
|
-
clientId,
|
|
415
|
-
timezone = "UTC",
|
|
416
|
-
}: StatsDateRangeParams): Promise<TodayCallsSummary> => {
|
|
417
|
-
const coll = getCallsCollection();
|
|
418
|
-
const match = buildCallsStatsMatch({ dateFrom, dateTo, clientId, timezone });
|
|
419
|
-
|
|
420
|
-
const facetResult = await coll
|
|
421
|
-
.aggregate<{
|
|
422
|
-
byStatus: { _id: string; count: number }[];
|
|
423
|
-
byType: { _id: string; count: number }[];
|
|
424
|
-
total: { count: number }[];
|
|
425
|
-
totalSeconds: { seconds: number }[];
|
|
426
|
-
}>([
|
|
427
|
-
{ $match: match },
|
|
428
|
-
{
|
|
429
|
-
$facet: {
|
|
430
|
-
byStatus: [{ $group: { _id: "$status", count: { $sum: 1 } } }],
|
|
431
|
-
byType: [
|
|
432
|
-
{
|
|
433
|
-
$group: {
|
|
434
|
-
_id: { $cond: ["$isIncomingCall", "incoming", "outgoing"] },
|
|
435
|
-
count: { $sum: 1 },
|
|
436
|
-
},
|
|
437
|
-
},
|
|
438
|
-
],
|
|
439
|
-
total: [{ $group: { _id: null, count: { $sum: 1 } } }],
|
|
440
|
-
totalSeconds: [{ $group: { _id: null, seconds: { $sum: "$callLength" } } }],
|
|
441
|
-
},
|
|
442
|
-
},
|
|
443
|
-
])
|
|
444
|
-
.next();
|
|
445
|
-
|
|
446
|
-
const byStatus: Record<string, number> = {};
|
|
447
|
-
(facetResult?.byStatus ?? []).forEach((s) => {
|
|
448
|
-
byStatus[s._id] = s.count;
|
|
449
|
-
});
|
|
450
|
-
const byType: Record<string, number> = {};
|
|
451
|
-
(facetResult?.byType ?? []).forEach((t) => {
|
|
452
|
-
byType[t._id] = t.count;
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
const totalSeconds = facetResult?.totalSeconds?.[0]?.seconds ?? 0;
|
|
456
|
-
|
|
457
|
-
return {
|
|
458
|
-
total: facetResult?.total?.[0]?.count ?? 0,
|
|
459
|
-
incoming: byType.incoming ?? 0,
|
|
460
|
-
outgoing: byType.outgoing ?? 0,
|
|
461
|
-
completed: byStatus.completed ?? 0,
|
|
462
|
-
failed: byStatus.failed ?? 0,
|
|
463
|
-
busy: byStatus.busy ?? 0,
|
|
464
|
-
noAnswer: byStatus["no-answer"] ?? 0,
|
|
465
|
-
totalMinutes: Math.ceil(totalSeconds / 60),
|
|
466
|
-
};
|
|
467
|
-
};
|
|
468
|
-
|
|
469
|
-
export const aggregateClientCallStats = async ({
|
|
470
|
-
dateFrom,
|
|
471
|
-
dateTo,
|
|
472
|
-
clientId,
|
|
473
|
-
clientIds,
|
|
474
|
-
timezone = "UTC",
|
|
475
|
-
skip = 0,
|
|
476
|
-
limit,
|
|
477
|
-
}: ClientCallStatsParams): Promise<ClientCallStatsPage> => {
|
|
478
|
-
const [result] = await getCallsCollection()
|
|
479
|
-
.aggregate<{
|
|
480
|
-
rows: ({
|
|
481
|
-
_id: string;
|
|
482
|
-
totalCalls: number;
|
|
483
|
-
totalSeconds: number;
|
|
484
|
-
lastCallDate: Date;
|
|
485
|
-
} & StatusCountFields)[];
|
|
486
|
-
total: { count: number }[];
|
|
487
|
-
}>([
|
|
488
|
-
{ $match: buildCallsStatsMatch({ dateFrom, dateTo, clientId, clientIds, timezone }) },
|
|
489
|
-
{
|
|
490
|
-
$group: {
|
|
491
|
-
_id: "$clientId",
|
|
492
|
-
totalCalls: { $sum: 1 },
|
|
493
|
-
...buildStatusCountFields("$status"),
|
|
494
|
-
totalSeconds: { $sum: "$callLength" },
|
|
495
|
-
lastCallDate: { $max: "$createdAt" },
|
|
496
|
-
},
|
|
497
|
-
},
|
|
498
|
-
{
|
|
499
|
-
$lookup: {
|
|
500
|
-
from: getClientsCollection().collectionName,
|
|
501
|
-
localField: "_id",
|
|
502
|
-
foreignField: "clientId",
|
|
503
|
-
as: "client",
|
|
504
|
-
},
|
|
505
|
-
},
|
|
506
|
-
{ $match: { "client.0": { $exists: true } } },
|
|
507
|
-
{ $project: { client: 0 } },
|
|
508
|
-
{ $sort: { totalCalls: -1, _id: 1 } },
|
|
509
|
-
{
|
|
510
|
-
$facet: {
|
|
511
|
-
rows: [{ $skip: skip }, ...(limit ? [{ $limit: limit }] : [])],
|
|
512
|
-
total: [{ $count: "count" }],
|
|
513
|
-
},
|
|
514
|
-
},
|
|
515
|
-
])
|
|
516
|
-
.toArray();
|
|
517
|
-
|
|
518
|
-
return {
|
|
519
|
-
rows: (result?.rows ?? []).map((r) => ({
|
|
520
|
-
clientId: r._id,
|
|
521
|
-
totalCalls: r.totalCalls,
|
|
522
|
-
statusCounts: extractStatusCounts(r),
|
|
523
|
-
totalMinutes: Math.ceil((r.totalSeconds || 0) / 60),
|
|
524
|
-
lastCallDate: r.lastCallDate,
|
|
525
|
-
})),
|
|
526
|
-
total: result?.total[0]?.count ?? 0,
|
|
527
|
-
};
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
export const aggregateSessionCallStats = async ({
|
|
531
|
-
dateFrom,
|
|
532
|
-
dateTo,
|
|
533
|
-
clientId,
|
|
534
|
-
timezone = "UTC",
|
|
535
|
-
}: StatsDateRangeParams): Promise<SessionCallStats[]> => {
|
|
536
|
-
const coll = getCallsCollection();
|
|
537
|
-
const match = buildCallsStatsMatch({ dateFrom, dateTo, clientId, timezone });
|
|
538
|
-
|
|
539
|
-
const sessionGroupKey = {
|
|
540
|
-
$cond: [
|
|
541
|
-
{ $eq: ["$isIncomingCall", true] },
|
|
542
|
-
INCOMING_SESSION_ID,
|
|
543
|
-
{ $ifNull: ["$sessionId", UNKNOWN_SESSION_ID] },
|
|
544
|
-
],
|
|
545
|
-
};
|
|
546
|
-
|
|
547
|
-
const rows = await coll
|
|
548
|
-
.aggregate<
|
|
549
|
-
{
|
|
550
|
-
_id: ObjectId | string;
|
|
551
|
-
sessionDoc: { session_name: string }[];
|
|
552
|
-
totalCalls: number;
|
|
553
|
-
} & StatusCountFields
|
|
554
|
-
>([
|
|
555
|
-
{ $match: match },
|
|
556
|
-
{
|
|
557
|
-
$group: {
|
|
558
|
-
_id: sessionGroupKey,
|
|
559
|
-
totalCalls: { $sum: 1 },
|
|
560
|
-
...buildStatusCountFields("$status"),
|
|
561
|
-
},
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
$lookup: {
|
|
565
|
-
from: "sessions",
|
|
566
|
-
localField: "_id",
|
|
567
|
-
foreignField: "_id",
|
|
568
|
-
as: "sessionDoc",
|
|
569
|
-
},
|
|
570
|
-
},
|
|
571
|
-
{ $sort: { totalCalls: -1 } },
|
|
572
|
-
])
|
|
573
|
-
.toArray();
|
|
574
|
-
|
|
575
|
-
return rows.map((r) => ({
|
|
576
|
-
sessionId: r._id.toString(),
|
|
577
|
-
// No session, or a deleted/unnamed one, has no name to look up: that is "Unknown".
|
|
578
|
-
sessionName:
|
|
579
|
-
r._id === INCOMING_SESSION_ID
|
|
580
|
-
? "Incoming Call"
|
|
581
|
-
: r.sessionDoc[0]?.session_name || "Unknown",
|
|
582
|
-
totalCalls: r.totalCalls,
|
|
583
|
-
statusCounts: extractStatusCounts(r),
|
|
584
|
-
}));
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
export const findLastCallDatesByClientIds = async (
|
|
588
|
-
clientIds: string[],
|
|
589
|
-
): Promise<Map<string, Date>> => {
|
|
590
|
-
if (clientIds.length === 0) return new Map();
|
|
591
|
-
|
|
592
|
-
const rows = await getCallsCollection()
|
|
593
|
-
.aggregate<{ _id: string; lastCallDate: Date }>([
|
|
594
|
-
{ $match: { clientId: { $in: clientIds } } },
|
|
595
|
-
{ $group: { _id: "$clientId", lastCallDate: { $max: "$createdAt" } } },
|
|
596
|
-
])
|
|
597
|
-
.toArray();
|
|
598
|
-
|
|
599
|
-
return new Map(rows.map((r) => [r._id, r.lastCallDate]));
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
export const findClientIdsByCallSids = async (
|
|
603
|
-
callSids: string[],
|
|
604
|
-
): Promise<Map<string, string>> => {
|
|
605
|
-
if (callSids.length === 0) return new Map();
|
|
606
|
-
|
|
607
|
-
const docs = await getCallsCollection()
|
|
608
|
-
.find(
|
|
609
|
-
{ callSid: { $in: callSids } },
|
|
610
|
-
{ projection: { _id: 0, clientId: 1, callSid: 1 } },
|
|
611
|
-
)
|
|
612
|
-
.toArray();
|
|
613
|
-
|
|
614
|
-
return new Map(docs.map((d) => [d.callSid, d.clientId]));
|
|
615
|
-
};
|
|
@@ -166,55 +166,3 @@ export type DateRange = {
|
|
|
166
166
|
since?: Date;
|
|
167
167
|
until?: Date;
|
|
168
168
|
};
|
|
169
|
-
|
|
170
|
-
export type StatsDateRangeParams = {
|
|
171
|
-
dateFrom?: string;
|
|
172
|
-
dateTo?: string;
|
|
173
|
-
clientId?: string;
|
|
174
|
-
/** Restricts to these clients. Combined with clientId, both must match. */
|
|
175
|
-
clientIds?: string[];
|
|
176
|
-
timezone?: string;
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export type ClientCallStatsParams = StatsDateRangeParams & {
|
|
180
|
-
skip?: number;
|
|
181
|
-
limit?: number;
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
export type ActiveCallsSummary = {
|
|
185
|
-
total: number;
|
|
186
|
-
incoming: number;
|
|
187
|
-
outgoing: number;
|
|
188
|
-
activeClientIds: string[];
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
export type TodayCallsSummary = {
|
|
192
|
-
total: number;
|
|
193
|
-
incoming: number;
|
|
194
|
-
outgoing: number;
|
|
195
|
-
completed: number;
|
|
196
|
-
failed: number;
|
|
197
|
-
busy: number;
|
|
198
|
-
noAnswer: number;
|
|
199
|
-
totalMinutes: number;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
export type ClientCallStats = {
|
|
203
|
-
clientId: string;
|
|
204
|
-
totalCalls: number;
|
|
205
|
-
statusCounts: Record<string, number>;
|
|
206
|
-
totalMinutes: number;
|
|
207
|
-
lastCallDate: Date;
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
export type ClientCallStatsPage = {
|
|
211
|
-
rows: ClientCallStats[];
|
|
212
|
-
total: number;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
export type SessionCallStats = {
|
|
216
|
-
sessionId: string;
|
|
217
|
-
sessionName: string;
|
|
218
|
-
totalCalls: number;
|
|
219
|
-
statusCounts: Record<string, number>;
|
|
220
|
-
};
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import { getDb,
|
|
2
|
-
import { Collection
|
|
3
|
-
import { applyQueryOptions } from "../utils/query.utils";
|
|
4
|
-
import { escapeRegex } from "../../utils/regex.utils";
|
|
5
|
-
import {
|
|
6
|
-
BackofficeRole,
|
|
7
|
-
ClientsPage,
|
|
8
|
-
ClientsPageParams,
|
|
9
|
-
ClientsPageRow,
|
|
10
|
-
} from "./clients.types";
|
|
1
|
+
import { getDb, Client } from "../index";
|
|
2
|
+
import { Collection } from "mongodb";
|
|
11
3
|
|
|
12
4
|
export const getClientsCollection = (): Collection<Client> => {
|
|
13
5
|
return getDb().collection<Client>("clients");
|
|
@@ -23,86 +15,5 @@ export const getClientByAPIKey = async (
|
|
|
23
15
|
return client ? client : null;
|
|
24
16
|
};
|
|
25
17
|
|
|
26
|
-
export const getAllClientIds = async (): Promise<string[]> => {
|
|
27
|
-
const docs = await getClientsCollection()
|
|
28
|
-
.find({}, { projection: { clientId: 1 } })
|
|
29
|
-
.toArray();
|
|
30
|
-
return docs.map((c) => c.clientId);
|
|
31
|
-
};
|
|
32
18
|
export const getClientByClientId = (clientId: string): Promise<Client | null> =>
|
|
33
19
|
getClientsCollection().findOne({ clientId });
|
|
34
|
-
|
|
35
|
-
export const getBackofficeRole = async (
|
|
36
|
-
clientId: string,
|
|
37
|
-
): Promise<BackofficeRole | null> => {
|
|
38
|
-
const client = await getClientsCollection().findOne(
|
|
39
|
-
{ clientId },
|
|
40
|
-
{ projection: { "roles.backoffice": 1 } },
|
|
41
|
-
);
|
|
42
|
-
const flags = client?.roles?.backoffice;
|
|
43
|
-
if (flags?.admin) return "admin";
|
|
44
|
-
if (flags?.viewer) return "viewer";
|
|
45
|
-
return null;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const setBackofficeRole = async (
|
|
49
|
-
clientId: string,
|
|
50
|
-
role: BackofficeRole | null,
|
|
51
|
-
): Promise<boolean> => {
|
|
52
|
-
const { matchedCount } = await getClientsCollection().updateOne(
|
|
53
|
-
{ clientId },
|
|
54
|
-
{
|
|
55
|
-
$set: {
|
|
56
|
-
"roles.backoffice.admin": role === "admin",
|
|
57
|
-
"roles.backoffice.viewer": role === "viewer",
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
);
|
|
61
|
-
return matchedCount > 0;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const countBackofficeAdmins = (): Promise<number> =>
|
|
65
|
-
getClientsCollection().countDocuments({ "roles.backoffice.admin": true });
|
|
66
|
-
|
|
67
|
-
export const findClientsPage = async ({
|
|
68
|
-
skip,
|
|
69
|
-
limit,
|
|
70
|
-
clientId,
|
|
71
|
-
clientIds,
|
|
72
|
-
excludeClientIds,
|
|
73
|
-
search,
|
|
74
|
-
}: ClientsPageParams): Promise<ClientsPage> => {
|
|
75
|
-
const conditions: Filter<Client>[] = [];
|
|
76
|
-
if (clientId) {
|
|
77
|
-
conditions.push({ clientId });
|
|
78
|
-
}
|
|
79
|
-
if (clientIds) {
|
|
80
|
-
conditions.push({ clientId: { $in: clientIds } });
|
|
81
|
-
}
|
|
82
|
-
if (excludeClientIds) {
|
|
83
|
-
conditions.push({ clientId: { $nin: excludeClientIds } });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const text = search?.trim();
|
|
87
|
-
if (text) {
|
|
88
|
-
const pattern = new RegExp(escapeRegex(text), "i");
|
|
89
|
-
const clientIdsByPhone = await getPhoneNumbersCollection().distinct("client_id", {
|
|
90
|
-
phone_number: pattern,
|
|
91
|
-
});
|
|
92
|
-
conditions.push({
|
|
93
|
-
$or: [{ clientId: pattern }, { clientId: { $in: clientIdsByPhone } }],
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const filter: Filter<Client> =
|
|
98
|
-
conditions.length > 0 ? { $and: conditions } : {};
|
|
99
|
-
const collection = getClientsCollection();
|
|
100
|
-
const [clients, total] = await Promise.all([
|
|
101
|
-
applyQueryOptions(
|
|
102
|
-
collection.find<ClientsPageRow>(filter, { projection: { clientId: 1, credits: 1 } }),
|
|
103
|
-
{ sort: { createdAt: -1, _id: -1 }, skip, limit },
|
|
104
|
-
).toArray(),
|
|
105
|
-
collection.countDocuments(filter),
|
|
106
|
-
]);
|
|
107
|
-
return { clients, total };
|
|
108
|
-
};
|