@talkpilot/core-db 1.0.26 → 1.1.0

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 CHANGED
@@ -147,5 +147,7 @@ MIT
147
147
 
148
148
  - Added to Moked106Config this param: withNeedAttentionCalls
149
149
  - withNeedAttentionCalls?: boolean
150
-
150
+
151
+ ### 1.0.27
152
+ - Added an optional `language` field to `ClientConfig` (e.g. Hebrew/English/Russian/French/Spanish) and updated tests.
151
153
 
@@ -1,7 +1,4 @@
1
1
  import { WithId } from 'mongodb';
2
- /**
3
- * Configuration for initiating a call for short SLA
4
- */
5
2
  export type InitiateCallForShortSlaConfig = {
6
3
  active: boolean;
7
4
  max_hours: number;
@@ -11,18 +8,12 @@ export type InitiateCallForShortSlaConfig = {
11
8
  }[];
12
9
  flow_id?: string | string[];
13
10
  };
14
- /**
15
- * Moked 106 configuration structure
16
- */
17
11
  export type Moked106Config = {
18
12
  initiate_call_for_short_sla?: InitiateCallForShortSlaConfig;
19
13
  avoidSaveTickets?: boolean;
20
14
  withUploadImagesSms?: boolean;
21
15
  withNeedAttentionCalls?: boolean;
22
16
  };
23
- /**
24
- * Municipal products structure
25
- */
26
17
  export type MunicipalProduct = {
27
18
  moked_106?: Moked106Config;
28
19
  cityName: string;
@@ -34,22 +25,30 @@ export type MunicipalProduct = {
34
25
  isProductionReady?: boolean;
35
26
  municipalDisplayName?: string;
36
27
  };
37
- /**
38
- * Products structure
39
- */
40
28
  export type Products = {
41
29
  municipal?: MunicipalProduct;
42
30
  [key: string]: unknown;
43
31
  };
44
- /**
45
- * Client configuration type
46
- * @template P - Products type (defaults to Products for type safety)
47
- */
32
+ export type ClientLanguageName = 'Hebrew' | 'English' | 'Russian' | 'French' | 'Spanish' | (string & {});
33
+ export type SendGridConfig = {
34
+ emailTo: string[];
35
+ templateId?: string;
36
+ senderId?: string;
37
+ };
38
+ export type SmsConfig = {};
39
+ export type WhatsappConfig = {};
40
+ export type CommunicationsConfig = {
41
+ sendGrid?: SendGridConfig;
42
+ sms: SmsConfig;
43
+ whatsapp: WhatsappConfig;
44
+ };
48
45
  export type ClientConfig<P extends Products = Products> = {
49
46
  clientId: string;
50
47
  phoneNumber?: string;
48
+ language?: ClientLanguageName;
51
49
  products: P;
52
50
  timezone?: string;
51
+ communications?: CommunicationsConfig;
53
52
  };
54
53
  export type ClientConfigDoc<P extends Products = Products> = WithId<ClientConfig<P>>;
55
54
  //# sourceMappingURL=clientsConfig.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clientsConfig.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clientsConfig/clientsConfig.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,2BAA2B,CAAC,EAAE,6BAA6B,CAAC;IAC5D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"clientsConfig.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clientsConfig/clientsConfig.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,2BAA2B,CAAC,EAAE,6BAA6B,CAAC;IAC5D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,SAAS,GACT,SAAS,GACT,QAAQ,GACR,SAAS,GACT,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,EAAE,CAAC;AAE3B,MAAM,MAAM,cAAc,GAAG,EAAE,CAAC;AAEhC,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,QAAQ,EAAE,CAAC,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -12,6 +12,7 @@ export * from './groups';
12
12
  export * from './calls';
13
13
  export * from './clientAudioBuffers';
14
14
  export * from './clientsConfig';
15
+ export * from './backgroundToolResults';
15
16
  export { mongodbClient } from './mongodb-client';
16
17
  export declare const setDb: (d: Db) => void;
17
18
  export declare const getDb: () => Db;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAExD,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,KAAK,GAAI,GAAG,EAAE,SAE1B,CAAC;AACF,eAAO,MAAM,KAAK,QAAO,EAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ,sBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAExD,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,KAAK,GAAI,GAAG,EAAE,SAE1B,CAAC;AACF,eAAO,MAAM,KAAK,QAAO,EAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ,sBAAgB,CAAC"}
@@ -29,6 +29,7 @@ __exportStar(require("./groups"), exports);
29
29
  __exportStar(require("./calls"), exports);
30
30
  __exportStar(require("./clientAudioBuffers"), exports);
31
31
  __exportStar(require("./clientsConfig"), exports);
32
+ __exportStar(require("./backgroundToolResults"), exports);
32
33
  var mongodb_client_1 = require("./mongodb-client");
33
34
  Object.defineProperty(exports, "mongodbClient", { enumerable: true, get: function () { return mongodb_client_1.mongodbClient; } });
34
35
  let db;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qCAAwD;AAExD,0CAAwB;AACxB,4CAA0B;AAC1B,6CAA2B;AAC3B,kDAAgC;AAChC,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,0CAAwB;AACxB,kDAAgC;AAChC,2CAAyB;AACzB,0CAAwB;AACxB,uDAAqC;AACrC,kDAAgC;AAChC,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AAEtB,IAAI,EAAM,CAAC;AACJ,MAAM,KAAK,GAAG,CAAC,CAAK,EAAE,EAAE;IAC7B,EAAE,GAAG,CAAC,CAAC;AACT,CAAC,CAAC;AAFW,QAAA,KAAK,SAEhB;AACK,MAAM,KAAK,GAAG,GAAO,EAAE;IAC5B,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAHW,QAAA,KAAK,SAGhB;AAEW,QAAA,QAAQ,GAAG,kBAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/talkpilot/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qCAAwD;AAExD,0CAAwB;AACxB,4CAA0B;AAC1B,6CAA2B;AAC3B,kDAAgC;AAChC,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,0CAAwB;AACxB,kDAAgC;AAChC,2CAAyB;AACzB,0CAAwB;AACxB,uDAAqC;AACrC,kDAAgC;AAChC,0DAAwC;AACxC,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AAEtB,IAAI,EAAM,CAAC;AACJ,MAAM,KAAK,GAAG,CAAC,CAAK,EAAE,EAAE;IAC7B,EAAE,GAAG,CAAC,CAAC;AACT,CAAC,CAAC;AAFW,QAAA,KAAK,SAEhB;AACK,MAAM,KAAK,GAAG,GAAO,EAAE;IAC5B,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/C,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAHW,QAAA,KAAK,SAGhB;AAEW,QAAA,QAAQ,GAAG,kBAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Filter } from 'mongodb';
2
+ import { Subscription, SimpleSubscriptionFilter } from '../index';
3
+ export declare const buildSimpleQuery: (filter: SimpleSubscriptionFilter) => Filter<Subscription>;
4
+ //# sourceMappingURL=subscriptions.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.utils.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/subscriptions/subscriptions.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAA6B,MAAM,UAAU,CAAC;AAE7F,eAAO,MAAM,gBAAgB,GAAI,QAAQ,wBAAwB,KAAG,MAAM,CAAC,YAAY,CAetF,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildSimpleQuery = void 0;
4
+ const mongodb_1 = require("mongodb");
5
+ const index_1 = require("../index");
6
+ const buildSimpleQuery = (filter) => {
7
+ const query = {};
8
+ if (filter._id) {
9
+ query._id = new mongodb_1.ObjectId(filter._id);
10
+ }
11
+ index_1.simpleFields.forEach((field) => {
12
+ const val = filter[field];
13
+ if (val !== undefined) {
14
+ query[field] = val;
15
+ }
16
+ });
17
+ return query;
18
+ };
19
+ exports.buildSimpleQuery = buildSimpleQuery;
20
+ //# sourceMappingURL=subscriptions.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.utils.js","sourceRoot":"","sources":["../../../src/talkpilot/subscriptions/subscriptions.utils.ts"],"names":[],"mappings":";;;AAAA,qCAA2C;AAC3C,oCAA6F;AAEtF,MAAM,gBAAgB,GAAG,CAAC,MAAgC,EAAwB,EAAE;IACzF,MAAM,KAAK,GAAyB,EAAE,CAAC;IAEvC,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,KAAK,CAAC,GAAG,GAAG,IAAI,kBAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,oBAAY,CAAC,OAAO,CAAC,CAAC,KAAkB,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,KAAK,CAAC,KAAK,CAAC,GAAG,GAAU,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAfW,QAAA,gBAAgB,oBAe3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talkpilot/core-db",
3
- "version": "1.0.26",
3
+ "version": "1.1.0",
4
4
  "description": "Core database package for centralized connections and ORM integration.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,136 @@
1
+ import {
2
+ getBackgroundToolResultsCollection,
3
+ upsertBackgroundToolResult,
4
+ findBackgroundToolResult,
5
+ findBackgroundToolResultsByCallSid,
6
+ } from '../backgroundToolResults.getters';
7
+ import { BackgroundToolStatus } from '../backgroundToolResults.types';
8
+
9
+ describe('backgroundToolResults getters', () => {
10
+ it('should return the "backgroundToolResults" collection', () => {
11
+ const collection = getBackgroundToolResultsCollection();
12
+ expect(collection.collectionName).toBe('backgroundToolResults');
13
+ });
14
+
15
+ it('should create a new background tool result with correct fields and default TTL', async () => {
16
+ const callSid = 'CA-background-call-1';
17
+ const toolName = 'exampleTool';
18
+ const status: BackgroundToolStatus = 'pending';
19
+ const result = null;
20
+
21
+ const before = new Date();
22
+ const doc = await upsertBackgroundToolResult({ callSid, toolName, status, result });
23
+ const after = new Date();
24
+
25
+ expect(doc).not.toBeNull();
26
+ expect(doc?.callSid).toBe(callSid);
27
+ expect(doc?.toolName).toBe(toolName);
28
+ expect(doc?.status).toBe(status);
29
+ expect(doc?.result).toBe(result);
30
+ expect(doc?.createdAt).toBeInstanceOf(Date);
31
+ expect(doc?.updatedAt).toBeInstanceOf(Date);
32
+ expect(doc?.expiredAt).toBeInstanceOf(Date);
33
+
34
+ const createdAt = doc!.createdAt.getTime();
35
+ const expiredAt = doc!.expiredAt.getTime();
36
+ const ttlMs = expiredAt - createdAt;
37
+
38
+ expect(ttlMs).toBeGreaterThanOrEqual(60 * 60_000 - 1000);
39
+ expect(ttlMs).toBeLessThanOrEqual(60 * 60_000 + 1000);
40
+
41
+ expect(doc!.createdAt.getTime()).toBeGreaterThanOrEqual(before.getTime());
42
+ expect(doc!.updatedAt.getTime()).toBeLessThanOrEqual(after.getTime());
43
+ });
44
+
45
+ it('should upsert by callSid + toolName and keep createdAt while updating other fields', async () => {
46
+ const callSid = 'CA-background-call-2';
47
+ const toolName = 'aggregationTool';
48
+
49
+ const first = await upsertBackgroundToolResult({
50
+ callSid,
51
+ toolName,
52
+ status: 'pending',
53
+ result: null,
54
+ });
55
+
56
+ expect(first).not.toBeNull();
57
+
58
+ const firstCreatedAt = first!.createdAt;
59
+ const firstUpdatedAt = first!.updatedAt;
60
+ const firstExpiredAt = first!.expiredAt;
61
+
62
+ const customTtlMs = 5 * 60_000;
63
+ const secondResultPayload = { value: 42 };
64
+
65
+ const second = await upsertBackgroundToolResult({
66
+ callSid,
67
+ toolName,
68
+ status: 'success',
69
+ result: secondResultPayload,
70
+ ttlMs: customTtlMs,
71
+ });
72
+
73
+ expect(second).not.toBeNull();
74
+ expect(second!._id.toHexString()).toBe(first!._id.toHexString());
75
+ expect(second!.callSid).toBe(callSid);
76
+ expect(second!.toolName).toBe(toolName);
77
+ expect(second!.status).toBe('success');
78
+ expect(second!.result).toEqual(secondResultPayload);
79
+
80
+ expect(second!.createdAt.getTime()).toBe(firstCreatedAt.getTime());
81
+
82
+ expect(second!.updatedAt.getTime()).toBeGreaterThanOrEqual(firstUpdatedAt.getTime());
83
+ expect(second!.expiredAt.getTime()).not.toBe(firstExpiredAt.getTime());
84
+
85
+ const ttlMs = second!.expiredAt.getTime() - second!.updatedAt.getTime();
86
+ expect(ttlMs).toBeGreaterThanOrEqual(customTtlMs - 1000);
87
+ expect(ttlMs).toBeLessThanOrEqual(customTtlMs + 1000);
88
+ });
89
+
90
+ it('should find background tool result by callSid and toolName', async () => {
91
+ const callSid = 'CA-background-call-3';
92
+ const toolName = 'fetchUserData';
93
+
94
+ await upsertBackgroundToolResult({
95
+ callSid,
96
+ toolName,
97
+ status: 'success',
98
+ result: { foo: 'bar' },
99
+ });
100
+
101
+ const found = await findBackgroundToolResult(callSid, toolName);
102
+ expect(found).not.toBeNull();
103
+ expect(found?.callSid).toBe(callSid);
104
+ expect(found?.toolName).toBe(toolName);
105
+ });
106
+
107
+ it('should return null when background tool result does not exist', async () => {
108
+ const found = await findBackgroundToolResult('non-existing-callSid', 'nonExistingTool');
109
+ expect(found).toBeNull();
110
+ });
111
+
112
+ it('should return all background tool results for a callSid ordered by createdAt', async () => {
113
+ const callSid = 'CA-background-call-4';
114
+
115
+ await upsertBackgroundToolResult({
116
+ callSid,
117
+ toolName: 'toolA',
118
+ status: 'pending',
119
+ result: null,
120
+ });
121
+
122
+ await new Promise((resolve) => setTimeout(resolve, 10));
123
+
124
+ await upsertBackgroundToolResult({
125
+ callSid,
126
+ toolName: 'toolB',
127
+ status: 'success',
128
+ result: { ok: true },
129
+ });
130
+
131
+ const results = await findBackgroundToolResultsByCallSid(callSid);
132
+ expect(results).toHaveLength(2);
133
+ expect(results[0].createdAt.getTime()).toBeLessThanOrEqual(results[1].createdAt.getTime());
134
+ });
135
+ });
136
+
@@ -0,0 +1,65 @@
1
+ import { Collection } from 'mongodb';
2
+ import { getDb } from '../index';
3
+ import {
4
+ BackgroundToolResult,
5
+ BackgroundToolResultDoc,
6
+ UpsertBackgroundToolResultInput,
7
+ } from './backgroundToolResults.types';
8
+
9
+ const getBackgroundToolResultsCollection = (): Collection<BackgroundToolResult> => {
10
+ return getDb().collection<BackgroundToolResult>('backgroundToolResults');
11
+ };
12
+
13
+ const upsertBackgroundToolResult = async (
14
+ input: UpsertBackgroundToolResultInput
15
+ ): Promise<BackgroundToolResultDoc | null> => {
16
+ const collection = getBackgroundToolResultsCollection();
17
+ const now = new Date();
18
+ const ttlMs = input.ttlMs ?? 60 * 60_000;
19
+ const expiredAt = new Date(now.getTime() + ttlMs);
20
+
21
+ const filter = { callSid: input.callSid, toolName: input.toolName };
22
+
23
+ await collection.updateOne(
24
+ filter,
25
+ {
26
+ $set: {
27
+ result: input.result,
28
+ status: input.status,
29
+ updatedAt: now,
30
+ expiredAt,
31
+ },
32
+ $setOnInsert: {
33
+ callSid: input.callSid,
34
+ toolName: input.toolName,
35
+ createdAt: now,
36
+ },
37
+ },
38
+ { upsert: true }
39
+ );
40
+
41
+ return collection.findOne(filter);
42
+ };
43
+
44
+ const findBackgroundToolResult = async (
45
+ callSid: string,
46
+ toolName: string
47
+ ): Promise<BackgroundToolResultDoc | null> => {
48
+ const collection = getBackgroundToolResultsCollection();
49
+ return collection.findOne({ callSid, toolName });
50
+ };
51
+
52
+ const findBackgroundToolResultsByCallSid = async (
53
+ callSid: string
54
+ ): Promise<BackgroundToolResultDoc[]> => {
55
+ const collection = getBackgroundToolResultsCollection();
56
+ return collection.find({ callSid }).sort({ createdAt: 1 }).toArray();
57
+ };
58
+
59
+ export {
60
+ getBackgroundToolResultsCollection,
61
+ upsertBackgroundToolResult,
62
+ findBackgroundToolResult,
63
+ findBackgroundToolResultsByCallSid,
64
+ };
65
+
@@ -0,0 +1,24 @@
1
+ import { WithId } from 'mongodb';
2
+
3
+ export type BackgroundToolStatus = 'success' | 'pending' | 'error';
4
+
5
+ export interface BackgroundToolResult {
6
+ callSid: string;
7
+ toolName: string;
8
+ result: unknown | null;
9
+ status: BackgroundToolStatus;
10
+ createdAt: Date;
11
+ updatedAt: Date;
12
+ expiredAt: Date;
13
+ }
14
+
15
+ export type BackgroundToolResultDoc = WithId<BackgroundToolResult>;
16
+
17
+ export interface UpsertBackgroundToolResultInput {
18
+ callSid: string;
19
+ toolName: string;
20
+ result: unknown | null;
21
+ status: BackgroundToolStatus;
22
+ ttlMs?: number;
23
+ }
24
+
@@ -0,0 +1,2 @@
1
+ export * from './backgroundToolResults.getters';
2
+ export type * from './backgroundToolResults.types';
@@ -7,6 +7,7 @@ describe('db.clientsConfig', () => {
7
7
  const clientId = 'test-client-id';
8
8
  const clientConfig = createClientConfig({
9
9
  clientId,
10
+ language: 'Hebrew',
10
11
  products: { feature1: true, feature2: false } as any,
11
12
  });
12
13
 
@@ -16,6 +17,7 @@ describe('db.clientsConfig', () => {
16
17
 
17
18
  expect(result).toMatchObject({
18
19
  clientId,
20
+ language: 'Hebrew',
19
21
  products: { feature1: true, feature2: false },
20
22
  });
21
23
  });
@@ -24,5 +26,38 @@ describe('db.clientsConfig', () => {
24
26
  const result = await getClientConfig('non-existent-client');
25
27
  expect(result).toBeNull();
26
28
  });
29
+
30
+ it('should support communications config', async () => {
31
+ const clientId = 'communications-test';
32
+ const clientConfig = createClientConfig({
33
+ clientId,
34
+ communications: {
35
+ sendGrid: {
36
+ emailTo: ['test@example.com'],
37
+ templateId: 'temp-123',
38
+ senderId: 'sender-123',
39
+ },
40
+ sms: {},
41
+ whatsapp: {},
42
+ },
43
+ });
44
+
45
+ await createClientConfigDoc(clientConfig);
46
+
47
+ const result = await getClientConfig(clientId);
48
+
49
+ expect(result).toMatchObject({
50
+ clientId,
51
+ communications: {
52
+ sendGrid: {
53
+ emailTo: ['test@example.com'],
54
+ templateId: 'temp-123',
55
+ senderId: 'sender-123',
56
+ },
57
+ sms: {},
58
+ whatsapp: {},
59
+ },
60
+ });
61
+ });
27
62
  });
28
63
  });
@@ -1,8 +1,5 @@
1
1
  import { WithId } from 'mongodb';
2
2
 
3
- /**
4
- * Configuration for initiating a call for short SLA
5
- */
6
3
  export type InitiateCallForShortSlaConfig = {
7
4
  active: boolean;
8
5
  max_hours: number;
@@ -10,9 +7,6 @@ export type InitiateCallForShortSlaConfig = {
10
7
  flow_id?: string | string[];
11
8
  };
12
9
 
13
- /**
14
- * Moked 106 configuration structure
15
- */
16
10
  export type Moked106Config = {
17
11
  initiate_call_for_short_sla?: InitiateCallForShortSlaConfig;
18
12
  avoidSaveTickets?: boolean;
@@ -20,9 +14,6 @@ export type Moked106Config = {
20
14
  withNeedAttentionCalls?: boolean;
21
15
  };
22
16
 
23
- /**
24
- * Municipal products structure
25
- */
26
17
  export type MunicipalProduct = {
27
18
  moked_106?: Moked106Config;
28
19
  cityName: string;
@@ -35,23 +26,42 @@ export type MunicipalProduct = {
35
26
  municipalDisplayName?: string;
36
27
  };
37
28
 
38
- /**
39
- * Products structure
40
- */
41
29
  export type Products = {
42
30
  municipal?: MunicipalProduct;
43
- [key: string]: unknown; // Allow other products
31
+ [key: string]: unknown;
32
+ };
33
+
34
+ export type ClientLanguageName =
35
+ | 'Hebrew'
36
+ | 'English'
37
+ | 'Russian'
38
+ | 'French'
39
+ | 'Spanish'
40
+ | (string & {});
41
+
42
+ export type SendGridConfig = {
43
+ emailTo: string[];
44
+ templateId?: string;
45
+ senderId?: string;
46
+ };
47
+
48
+ export type SmsConfig = {};
49
+
50
+ export type WhatsappConfig = {};
51
+
52
+ export type CommunicationsConfig = {
53
+ sendGrid?: SendGridConfig;
54
+ sms: SmsConfig;
55
+ whatsapp: WhatsappConfig;
44
56
  };
45
57
 
46
- /**
47
- * Client configuration type
48
- * @template P - Products type (defaults to Products for type safety)
49
- */
50
58
  export type ClientConfig<P extends Products = Products> = {
51
59
  clientId: string;
52
60
  phoneNumber?: string;
61
+ language?: ClientLanguageName;
53
62
  products: P;
54
63
  timezone?: string;
64
+ communications?: CommunicationsConfig;
55
65
  };
56
66
 
57
67
  export type ClientConfigDoc<P extends Products = Products> = WithId<ClientConfig<P>>;
@@ -13,6 +13,7 @@ export * from './groups';
13
13
  export * from './calls';
14
14
  export * from './clientAudioBuffers';
15
15
  export * from './clientsConfig';
16
+ export * from './backgroundToolResults';
16
17
  export { mongodbClient } from './mongodb-client';
17
18
 
18
19
  let db: Db;