@talkpilot/core-db 1.3.51 → 1.3.52

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.
Files changed (151) hide show
  1. package/README.md +21 -2
  2. package/dist/talkpilot/auditLogs/auditLogs.getters.d.ts +8 -0
  3. package/dist/talkpilot/auditLogs/auditLogs.getters.d.ts.map +1 -0
  4. package/dist/talkpilot/auditLogs/auditLogs.getters.js +26 -0
  5. package/dist/talkpilot/auditLogs/auditLogs.getters.js.map +1 -0
  6. package/dist/talkpilot/auditLogs/auditLogs.setters.d.ts +3 -0
  7. package/dist/talkpilot/auditLogs/auditLogs.setters.d.ts.map +1 -0
  8. package/dist/talkpilot/auditLogs/auditLogs.setters.js +9 -0
  9. package/dist/talkpilot/auditLogs/auditLogs.setters.js.map +1 -0
  10. package/dist/talkpilot/auditLogs/auditLogs.types.d.ts +12 -0
  11. package/dist/talkpilot/auditLogs/auditLogs.types.d.ts.map +1 -0
  12. package/dist/talkpilot/auditLogs/auditLogs.types.js +3 -0
  13. package/dist/talkpilot/auditLogs/auditLogs.types.js.map +1 -0
  14. package/dist/talkpilot/auditLogs/index.d.ts +3 -0
  15. package/dist/talkpilot/auditLogs/index.d.ts.map +1 -0
  16. package/dist/talkpilot/auditLogs/index.js +19 -0
  17. package/dist/talkpilot/auditLogs/index.js.map +1 -0
  18. package/dist/talkpilot/calls/calls.constants.d.ts +1 -1
  19. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.d.ts +4 -0
  20. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.d.ts.map +1 -0
  21. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.js +9 -0
  22. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.js.map +1 -0
  23. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.d.ts +3 -0
  24. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.d.ts.map +1 -0
  25. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.js +9 -0
  26. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.js.map +1 -0
  27. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.d.ts +10 -0
  28. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.d.ts.map +1 -0
  29. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.js +3 -0
  30. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.js.map +1 -0
  31. package/dist/talkpilot/clientDeletionLogs/index.d.ts +4 -0
  32. package/dist/talkpilot/clientDeletionLogs/index.d.ts.map +1 -0
  33. package/dist/talkpilot/clientDeletionLogs/index.js +20 -0
  34. package/dist/talkpilot/clientDeletionLogs/index.js.map +1 -0
  35. package/dist/talkpilot/clients/clients.constants.d.ts +3 -0
  36. package/dist/talkpilot/clients/clients.constants.d.ts.map +1 -0
  37. package/dist/talkpilot/clients/clients.constants.js +6 -0
  38. package/dist/talkpilot/clients/clients.constants.js.map +1 -0
  39. package/dist/talkpilot/clients/clients.getters.d.ts +1 -0
  40. package/dist/talkpilot/clients/clients.getters.d.ts.map +1 -1
  41. package/dist/talkpilot/clients/clients.getters.js +8 -1
  42. package/dist/talkpilot/clients/clients.getters.js.map +1 -1
  43. package/dist/talkpilot/clients/clients.lifecycle.d.ts +10 -0
  44. package/dist/talkpilot/clients/clients.lifecycle.d.ts.map +1 -0
  45. package/dist/talkpilot/clients/clients.lifecycle.js +95 -0
  46. package/dist/talkpilot/clients/clients.lifecycle.js.map +1 -0
  47. package/dist/talkpilot/clients/clients.types.d.ts +21 -0
  48. package/dist/talkpilot/clients/clients.types.d.ts.map +1 -1
  49. package/dist/talkpilot/clients/index.d.ts +2 -0
  50. package/dist/talkpilot/clients/index.d.ts.map +1 -1
  51. package/dist/talkpilot/clients/index.js +2 -0
  52. package/dist/talkpilot/clients/index.js.map +1 -1
  53. package/dist/talkpilot/flows/flows.getter.d.ts +1 -4
  54. package/dist/talkpilot/flows/flows.getter.d.ts.map +1 -1
  55. package/dist/talkpilot/flows/flows.getter.js +1 -12
  56. package/dist/talkpilot/flows/flows.getter.js.map +1 -1
  57. package/dist/talkpilot/flows/flows.schema.d.ts +0 -31
  58. package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -1
  59. package/dist/talkpilot/flows/flows.schema.js +0 -25
  60. package/dist/talkpilot/flows/flows.schema.js.map +1 -1
  61. package/dist/talkpilot/flows/flows.types.d.ts +0 -14
  62. package/dist/talkpilot/flows/flows.types.d.ts.map +1 -1
  63. package/dist/talkpilot/flows/index.d.ts +1 -1
  64. package/dist/talkpilot/flows/index.d.ts.map +1 -1
  65. package/dist/talkpilot/flows/index.js +1 -3
  66. package/dist/talkpilot/flows/index.js.map +1 -1
  67. package/dist/talkpilot/index.d.ts +1 -0
  68. package/dist/talkpilot/index.d.ts.map +1 -1
  69. package/dist/talkpilot/index.js +1 -0
  70. package/dist/talkpilot/index.js.map +1 -1
  71. package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts +11 -0
  72. package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts.map +1 -1
  73. package/dist/talkpilot/phone_numbers/phone_numbers.getter.js +60 -1
  74. package/dist/talkpilot/phone_numbers/phone_numbers.getter.js.map +1 -1
  75. package/dist/talkpilot/results/index.d.ts +3 -0
  76. package/dist/talkpilot/results/index.d.ts.map +1 -1
  77. package/dist/talkpilot/results/index.js +22 -1
  78. package/dist/talkpilot/results/index.js.map +1 -1
  79. package/dist/talkpilot/results/results.constants.d.ts +9 -0
  80. package/dist/talkpilot/results/results.constants.d.ts.map +1 -0
  81. package/dist/talkpilot/results/results.constants.js +12 -0
  82. package/dist/talkpilot/results/results.constants.js.map +1 -0
  83. package/dist/talkpilot/results/results.getter.d.ts.map +1 -1
  84. package/dist/talkpilot/results/results.getter.js +3 -2
  85. package/dist/talkpilot/results/results.getter.js.map +1 -1
  86. package/dist/talkpilot/results/results.statistics.getters.d.ts +7 -0
  87. package/dist/talkpilot/results/results.statistics.getters.d.ts.map +1 -0
  88. package/dist/talkpilot/results/results.statistics.getters.js +244 -0
  89. package/dist/talkpilot/results/results.statistics.getters.js.map +1 -0
  90. package/dist/talkpilot/results/results.statistics.types.d.ts +42 -0
  91. package/dist/talkpilot/results/results.statistics.types.d.ts.map +1 -0
  92. package/dist/talkpilot/results/results.statistics.types.js +3 -0
  93. package/dist/talkpilot/results/results.statistics.types.js.map +1 -0
  94. package/dist/test-utils/factories/index.d.ts +2 -0
  95. package/dist/test-utils/factories/index.d.ts.map +1 -1
  96. package/dist/test-utils/factories/index.js +2 -0
  97. package/dist/test-utils/factories/index.js.map +1 -1
  98. package/dist/test-utils/factories/talkpilot/clients.d.ts +14 -0
  99. package/dist/test-utils/factories/talkpilot/clients.d.ts.map +1 -0
  100. package/dist/test-utils/factories/talkpilot/clients.js +19 -0
  101. package/dist/test-utils/factories/talkpilot/clients.js.map +1 -0
  102. package/dist/test-utils/factories/talkpilot/results.d.ts +16 -0
  103. package/dist/test-utils/factories/talkpilot/results.d.ts.map +1 -0
  104. package/dist/test-utils/factories/talkpilot/results.js +40 -0
  105. package/dist/test-utils/factories/talkpilot/results.js.map +1 -0
  106. package/dist/websitalk/scanResources/scanResources.getters.d.ts +0 -1
  107. package/dist/websitalk/scanResources/scanResources.getters.d.ts.map +1 -1
  108. package/dist/websitalk/scanResources/scanResources.getters.js +1 -6
  109. package/dist/websitalk/scanResources/scanResources.getters.js.map +1 -1
  110. package/dist/websitalk/scans/scans.constants.d.ts +0 -1
  111. package/dist/websitalk/scans/scans.constants.d.ts.map +1 -1
  112. package/dist/websitalk/scans/scans.constants.js +0 -1
  113. package/dist/websitalk/scans/scans.constants.js.map +1 -1
  114. package/dist/websitalk/scans/scans.getters.d.ts +0 -1
  115. package/dist/websitalk/scans/scans.getters.d.ts.map +1 -1
  116. package/dist/websitalk/scans/scans.getters.js +1 -6
  117. package/dist/websitalk/scans/scans.getters.js.map +1 -1
  118. package/package.json +1 -1
  119. package/src/talkpilot/auditLogs/__tests__/auditLogs.spec.ts +92 -0
  120. package/src/talkpilot/auditLogs/auditLogs.getters.ts +26 -0
  121. package/src/talkpilot/auditLogs/auditLogs.types.ts +13 -0
  122. package/src/talkpilot/auditLogs/index.ts +2 -0
  123. package/src/talkpilot/clients/__tests__/clients.getters.spec.ts +33 -0
  124. package/src/talkpilot/clients/__tests__/clients.lifecycle.spec.ts +166 -0
  125. package/src/talkpilot/clients/clients.constants.ts +2 -0
  126. package/src/talkpilot/clients/clients.getters.ts +7 -0
  127. package/src/talkpilot/clients/clients.lifecycle.ts +116 -0
  128. package/src/talkpilot/clients/clients.types.ts +19 -0
  129. package/src/talkpilot/clients/index.ts +2 -0
  130. package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +0 -25
  131. package/src/talkpilot/flows/flows.getter.ts +2 -22
  132. package/src/talkpilot/flows/flows.schema.ts +0 -25
  133. package/src/talkpilot/flows/flows.types.ts +0 -22
  134. package/src/talkpilot/flows/index.ts +1 -6
  135. package/src/talkpilot/index.ts +1 -0
  136. package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +227 -13
  137. package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +76 -1
  138. package/src/talkpilot/results/__tests__/results.statistics.spec.ts +226 -0
  139. package/src/talkpilot/results/index.ts +9 -0
  140. package/src/talkpilot/results/results.constants.ts +11 -0
  141. package/src/talkpilot/results/results.getter.ts +3 -2
  142. package/src/talkpilot/results/results.statistics.getters.ts +329 -0
  143. package/src/talkpilot/results/results.statistics.types.ts +45 -0
  144. package/src/test-utils/factories/index.ts +2 -0
  145. package/src/test-utils/factories/talkpilot/clients.ts +21 -0
  146. package/src/test-utils/factories/talkpilot/results.ts +43 -0
  147. package/src/websitalk/scanResources/__tests__/scanResources.spec.ts +0 -19
  148. package/src/websitalk/scanResources/scanResources.getters.ts +0 -7
  149. package/src/websitalk/scans/__tests__/scans.spec.ts +0 -17
  150. package/src/websitalk/scans/scans.constants.ts +0 -1
  151. package/src/websitalk/scans/scans.getters.ts +0 -5
package/README.md CHANGED
@@ -37,6 +37,7 @@ L1:# @talkpilot/core-db
37
37
  - **TalkPilot domain** – Imports like `findAgents`, `getFlows`, `findCalls`, and `vectorSearchCalls` live in `src/talkpilot`. These functions are the canonical access pattern for call history, session metadata, and provider configs.
38
38
  - **Municipal domain** – Helpers such as `findStreets`, `getMunicipalCities`, `findDepartmentSubjects`, and `createTicket` live under `src/municipal` and feed MIS workflows (street hints, subject matching, Ash Bina tickets).
39
39
  - **Configuration domain** – `getPromptByName`, `findPrompts`, `getAllPrompts`, and `getPromptsByProduct` live under `src/configuration` and back MIS's `moked_106` prompt lookups (defaults, overridable per-client via `clientConfig.toolsPrompts`).
40
+ - **Websitalk domain** (`scans`, `websiteUrls`) – ⚠️ **Not included in `clientExistsInAnyCollection`/`deleteClientDataAcrossDomains`.** Those collections hold the client's URLs, which an external website-talk API uses as a lookup key to clean up its own Mongo collections *and* other, non-Mongo data stores tied to the client. Deleting a client fully requires calling that external API separately — see the warning on `deleteClientDataAcrossDomains` in `src/talkpilot/clients/clients.lifecycle.ts`.
40
41
 
41
42
  ## Environment variables
42
43
 
@@ -177,8 +178,7 @@ Refer to `DEVELOPMENT.md` for the full walkthrough, token instructions, and fact
177
178
  | 1.3.40 | Live scan progress for WebsiteTalk (CP-1527): `scanResources` module with KPI counts, board pagination, and page detail; terminal snapshot fields on `Scan`. |
178
179
  | 1.3.47 | Added optional `accountOwnerEmail` field to `WebsiteTalkProduct` (CP-1715): the recipient for the end-of-call summary email, set once from the client's login email and editable in Settings. |
179
180
  | 1.3.48 | Fixed `getScanPages` search (CP-1726): user search input was passed unescaped into MongoDB's `$regex`, so a URL/title containing regex-special characters (e.g. `?`) failed to match even when the document existed. Added `escapeRegex()` and applied it before building the `url`/`title` `$regex` filter. No API changes. |
180
- | 1.3.49 | Internal tools configuration on flows (CP-1723): `Flow.internalTools` keyed by tool name (`enabled`, optional `maxCalls`, per-parameter `description`/`value` overrides) with matching `$jsonSchema` validator, plus `createFlow` / `updateFlowById` mutators and the `FlowUpdateParams` type so consumers stop writing to the `flows` collection directly. |
181
-
181
+ | 1.3.52 | Client-lifecycle support for the TalkPilot Dashboard (PE-869): `clientExistsInAnyCollection`/`deleteClientDataAcrossDomains` (dynamic scan across talkpilot/municipal domains only, no hardcoded collection list; `auditLogs` is excluded so a client's own deletion record survives its deletion), new `auditLogs` collection & `insertAuditLog`/`findAuditLogs`/`countAuditLogs`, `getAllClientCredits` on `clients`. Added `results` statistics getters for the dashboard: `aggregateActiveCallsSummary`, `aggregateTodayCallsSummary`, `aggregateClientCallStats`, `aggregateSessionCallStats`, and `findClientIdsByCallSids` (for backOffice-server). On `phone_numbers`: fixed `getClientPhones`/`getAllClientPhoneMappings` to deduplicate append-only history records instead of returning raw duplicate rows per client; added `getDistinctClientPhonePairs`, `findClientsByPhoneNumbers`, and `deletePhoneNumberRecords` (removes every record for a phone number, across all clients, once it's released back to Twilio). website-talk (`scans`/`websiteUrls`) is intentionally NOT touched by `deleteClientDataAcrossDomains` — see the Websitalk domain note above; callers must call the external website-talk deletion API separately. No breaking changes. |
182
182
  ### 1.1.9
183
183
 
184
184
  1. `npm run build`.
@@ -766,6 +766,25 @@ No — purely additive.
766
766
 
767
767
  No API changes. **WTIS** (the only current consumer of `getScanPages`) should upgrade to 1.3.48 or later to pick up the fix.
768
768
 
769
+ ### 1.3.52 — Client-lifecycle support for the TalkPilot Dashboard (PE-869)
770
+
771
+ Adds centralized client deletion across the talkpilot/municipal domains, with an audit trail, plus supporting getters for the client-management dashboard.
772
+
773
+ **Added**
774
+
775
+ | Area | What |
776
+ | --- | --- |
777
+ | `clients` | `clientExistsInAnyCollection` / `deleteClientDataAcrossDomains` — dynamically scan and delete a client's data across every talkpilot/municipal collection (no hardcoded collection list). `auditLogs` is always excluded, so a client's own deletion record survives its own deletion. `getAllClientCredits`. |
778
+ | `auditLogs` (new collection) | `insertAuditLog`, `findAuditLogs` (paginated), `countAuditLogs`. |
779
+ | `results` | `aggregateActiveCallsSummary`, `aggregateTodayCallsSummary`, `aggregateClientCallStats`, `aggregateSessionCallStats` — call-volume/status dashboards. `findClientIdsByCallSids` — resolves clientId per callSid, added for backOffice-server. |
780
+ | `phone_numbers` | Fixed `getClientPhones`/`getAllClientPhoneMappings` to deduplicate append-only history records. Added `getDistinctClientPhonePairs`, `findClientsByPhoneNumbers`, `deletePhoneNumberRecords` (clears every record for a number once released back to Twilio). |
781
+
782
+ ⚠️ website-talk (`scans`/`websiteUrls`) is intentionally **not** touched by `deleteClientDataAcrossDomains` — see the Websitalk domain note above. Callers must call the external website-talk deletion API separately for a full client delete.
783
+
784
+ **Do I need to update my app?**
785
+
786
+ No — purely additive, no breaking changes. Consumers opt in by importing the new getters above.
787
+
769
788
  ## 🛠 CI/CD & deployment
770
789
 
771
790
  - This package is consumed by Cloud Build-based services (TalkPilot Server, MIS, CIS) as a dependency when Docker images are built. Keep `dist/` in sync with your builds because the compiled artifact is what downstream services install.
@@ -0,0 +1,8 @@
1
+ import { Collection } from "mongodb";
2
+ import { QueryOptions } from "../utils/query.utils";
3
+ import { AuditLogDoc, AuditLogEntry } from "./auditLogs.types";
4
+ export declare const getAuditLogsCollection: () => Collection<AuditLogEntry>;
5
+ export declare const insertAuditLog: (entry: AuditLogEntry) => Promise<void>;
6
+ export declare const findAuditLogs: (options: Pick<QueryOptions, "skip"> & Required<Pick<QueryOptions, "limit">>) => Promise<AuditLogDoc[]>;
7
+ export declare const countAuditLogs: () => Promise<number>;
8
+ //# sourceMappingURL=auditLogs.getters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLogs.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/auditLogs.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAqB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE/D,eAAO,MAAM,sBAAsB,QAAO,UAAU,CAAC,aAAa,CAEjE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,OAAO,aAAa,KAAG,OAAO,CAAC,IAAI,CAEvE,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,SAAS,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,KAC1E,OAAO,CAAC,WAAW,EAAE,CAMvB,CAAC;AAEF,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,MAAM,CAErD,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.countAuditLogs = exports.findAuditLogs = exports.insertAuditLog = exports.getAuditLogsCollection = void 0;
4
+ const index_1 = require("../index");
5
+ const query_utils_1 = require("../utils/query.utils");
6
+ const getAuditLogsCollection = () => {
7
+ return (0, index_1.getDb)().collection("auditLogs");
8
+ };
9
+ exports.getAuditLogsCollection = getAuditLogsCollection;
10
+ const insertAuditLog = async (entry) => {
11
+ await (0, exports.getAuditLogsCollection)().insertOne(entry);
12
+ };
13
+ exports.insertAuditLog = insertAuditLog;
14
+ const findAuditLogs = async (options) => {
15
+ const cursor = (0, exports.getAuditLogsCollection)().find({});
16
+ return (0, query_utils_1.applyQueryOptions)(cursor, {
17
+ sort: { timestamp: -1 },
18
+ ...options,
19
+ }).toArray();
20
+ };
21
+ exports.findAuditLogs = findAuditLogs;
22
+ const countAuditLogs = async () => {
23
+ return (0, exports.getAuditLogsCollection)().countDocuments({});
24
+ };
25
+ exports.countAuditLogs = countAuditLogs;
26
+ //# sourceMappingURL=auditLogs.getters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLogs.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/auditLogs.getters.ts"],"names":[],"mappings":";;;AACA,oCAAiC;AACjC,sDAAuE;AAGhE,MAAM,sBAAsB,GAAG,GAA8B,EAAE;IACpE,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAgB,WAAW,CAAC,CAAC;AACxD,CAAC,CAAC;AAFW,QAAA,sBAAsB,0BAEjC;AAEK,MAAM,cAAc,GAAG,KAAK,EAAE,KAAoB,EAAiB,EAAE;IAC1E,MAAM,IAAA,8BAAsB,GAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC,CAAC;AAFW,QAAA,cAAc,kBAEzB;AAEK,MAAM,aAAa,GAAG,KAAK,EAChC,OAA2E,EACnD,EAAE;IAC1B,MAAM,MAAM,GAAG,IAAA,8BAAsB,GAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,OAAO,IAAA,+BAAiB,EAAC,MAAM,EAAE;QAC/B,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE;QACvB,GAAG,OAAO;KACX,CAAC,CAAC,OAAO,EAAE,CAAC;AACf,CAAC,CAAC;AARW,QAAA,aAAa,iBAQxB;AAEK,MAAM,cAAc,GAAG,KAAK,IAAqB,EAAE;IACxD,OAAO,IAAA,8BAAsB,GAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC;AAFW,QAAA,cAAc,kBAEzB"}
@@ -0,0 +1,3 @@
1
+ import { AuditLogEntry } from "./auditLogs.types";
2
+ export declare const insertAuditLog: (entry: AuditLogEntry) => Promise<void>;
3
+ //# sourceMappingURL=auditLogs.setters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLogs.setters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/auditLogs.setters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,eAAO,MAAM,cAAc,GAAU,OAAO,aAAa,KAAG,OAAO,CAAC,IAAI,CAEvE,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.insertAuditLog = void 0;
4
+ const auditLogs_getters_1 = require("./auditLogs.getters");
5
+ const insertAuditLog = async (entry) => {
6
+ await (0, auditLogs_getters_1.getAuditLogsCollection)().insertOne(entry);
7
+ };
8
+ exports.insertAuditLog = insertAuditLog;
9
+ //# sourceMappingURL=auditLogs.setters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLogs.setters.js","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/auditLogs.setters.ts"],"names":[],"mappings":";;;AAAA,2DAA6D;AAGtD,MAAM,cAAc,GAAG,KAAK,EAAE,KAAoB,EAAiB,EAAE;IAC1E,MAAM,IAAA,0CAAsB,GAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC,CAAC;AAFW,QAAA,cAAc,kBAEzB"}
@@ -0,0 +1,12 @@
1
+ import { WithId } from "mongodb";
2
+ export type AuditLogEntry = {
3
+ clientId: string;
4
+ adminEmail: string;
5
+ action: "delete";
6
+ timestamp: Date;
7
+ env?: string;
8
+ allSucceeded?: boolean;
9
+ failedCollections?: string[];
10
+ };
11
+ export type AuditLogDoc = WithId<AuditLogEntry>;
12
+ //# sourceMappingURL=auditLogs.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLogs.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/auditLogs.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=auditLogs.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLogs.types.js","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/auditLogs.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export * from "./auditLogs.types";
2
+ export * from "./auditLogs.getters";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./auditLogs.types"), exports);
18
+ __exportStar(require("./auditLogs.getters"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/talkpilot/auditLogs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,sDAAoC"}
@@ -31,5 +31,5 @@ export declare const CallStatusValues: {
31
31
  readonly Failed: "failed";
32
32
  readonly Canceled: "canceled";
33
33
  };
34
- export declare const ALL_CALL_STATUSES: ("in-progress" | "answered" | "no-answer" | "completed" | "busy" | "failed" | "canceled" | "initiated" | "ringing")[];
34
+ export declare const ALL_CALL_STATUSES: ("in-progress" | "completed" | "failed" | "no-answer" | "busy" | "answered" | "canceled" | "initiated" | "ringing")[];
35
35
  //# sourceMappingURL=calls.constants.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { Collection } from "mongodb";
2
+ import { ClientDeletionLogEntry } from "./clientDeletionLogs.types";
3
+ export declare const getClientDeletionLogsCollection: () => Collection<ClientDeletionLogEntry>;
4
+ //# sourceMappingURL=clientDeletionLogs.getters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientDeletionLogs.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,eAAO,MAAM,+BAA+B,QACtC,UAAU,CAAC,sBAAsB,CAEpC,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getClientDeletionLogsCollection = void 0;
4
+ const index_1 = require("../index");
5
+ const getClientDeletionLogsCollection = () => {
6
+ return (0, index_1.getDb)().collection("clientDeletionLogs");
7
+ };
8
+ exports.getClientDeletionLogsCollection = getClientDeletionLogsCollection;
9
+ //# sourceMappingURL=clientDeletionLogs.getters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientDeletionLogs.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.ts"],"names":[],"mappings":";;;AACA,oCAAiC;AAG1B,MAAM,+BAA+B,GAC1C,GAAuC,EAAE;IACvC,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAyB,oBAAoB,CAAC,CAAC;AAC1E,CAAC,CAAC;AAHS,QAAA,+BAA+B,mCAGxC"}
@@ -0,0 +1,3 @@
1
+ import { ClientDeletionLogEntry } from "./clientDeletionLogs.types";
2
+ export declare const insertAuditLog: (entry: ClientDeletionLogEntry) => Promise<void>;
3
+ //# sourceMappingURL=clientDeletionLogs.setters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientDeletionLogs.setters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,eAAO,MAAM,cAAc,GACzB,OAAO,sBAAsB,KAC5B,OAAO,CAAC,IAAI,CAEd,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.insertAuditLog = void 0;
4
+ const clientDeletionLogs_getters_1 = require("./clientDeletionLogs.getters");
5
+ const insertAuditLog = async (entry) => {
6
+ await (0, clientDeletionLogs_getters_1.getClientDeletionLogsCollection)().insertOne(entry);
7
+ };
8
+ exports.insertAuditLog = insertAuditLog;
9
+ //# sourceMappingURL=clientDeletionLogs.setters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientDeletionLogs.setters.js","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.ts"],"names":[],"mappings":";;;AAAA,6EAA+E;AAGxE,MAAM,cAAc,GAAG,KAAK,EACjC,KAA6B,EACd,EAAE;IACjB,MAAM,IAAA,4DAA+B,GAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC,CAAC;AAJW,QAAA,cAAc,kBAIzB"}
@@ -0,0 +1,10 @@
1
+ import { WithId } from "mongodb";
2
+ export type ClientDeletionLogEntry = {
3
+ clientId: string;
4
+ adminEmail: string;
5
+ action: "delete";
6
+ timestamp: Date;
7
+ env?: string;
8
+ };
9
+ export type ClientDeletionLogDoc = WithId<ClientDeletionLogEntry>;
10
+ //# sourceMappingURL=clientDeletionLogs.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientDeletionLogs.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/clientDeletionLogs.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=clientDeletionLogs.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientDeletionLogs.types.js","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/clientDeletionLogs.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export * from "./clientDeletionLogs.types";
2
+ export * from "./clientDeletionLogs.getters";
3
+ export * from "./clientDeletionLogs.setters";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,8BAA8B,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./clientDeletionLogs.types"), exports);
18
+ __exportStar(require("./clientDeletionLogs.getters"), exports);
19
+ __exportStar(require("./clientDeletionLogs.setters"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/talkpilot/clientDeletionLogs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6DAA2C;AAC3C,+DAA6C;AAC7C,+DAA6C"}
@@ -0,0 +1,3 @@
1
+ /** Collections to always skip during client deletion — e.g. auditLogs, which must survive it. */
2
+ export declare const DELETE_DENYLIST: string[];
3
+ //# sourceMappingURL=clients.constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.constants.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.constants.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,eAAO,MAAM,eAAe,EAAE,MAAM,EAAkB,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DELETE_DENYLIST = void 0;
4
+ /** Collections to always skip during client deletion — e.g. auditLogs, which must survive it. */
5
+ exports.DELETE_DENYLIST = ["auditLogs"];
6
+ //# sourceMappingURL=clients.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.constants.js","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.constants.ts"],"names":[],"mappings":";;;AAAA,iGAAiG;AACpF,QAAA,eAAe,GAAa,CAAC,WAAW,CAAC,CAAC"}
@@ -2,4 +2,5 @@ import { Client } from "../index";
2
2
  import { Collection } from "mongodb";
3
3
  export declare const getClientsCollection: () => Collection<Client>;
4
4
  export declare const getClientByAPIKey: (apiKey: string) => Promise<Client | null>;
5
+ export declare const getAllClientCredits: () => Promise<Map<string, number>>;
5
6
  //# sourceMappingURL=clients.getters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clients.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,eAAO,MAAM,oBAAoB,QAAO,UAAU,CAAC,MAAM,CAExD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAMvB,CAAC"}
1
+ {"version":3,"file":"clients.getters.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,eAAO,MAAM,oBAAoB,QAAO,UAAU,CAAC,MAAM,CAExD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAMvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAa,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAKvE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getClientByAPIKey = exports.getClientsCollection = void 0;
3
+ exports.getAllClientCredits = exports.getClientByAPIKey = exports.getClientsCollection = void 0;
4
4
  const index_1 = require("../index");
5
5
  const getClientsCollection = () => {
6
6
  return (0, index_1.getDb)().collection("clients");
@@ -14,4 +14,11 @@ const getClientByAPIKey = async (apiKey) => {
14
14
  return client ? client : null;
15
15
  };
16
16
  exports.getClientByAPIKey = getClientByAPIKey;
17
+ const getAllClientCredits = async () => {
18
+ const docs = await (0, exports.getClientsCollection)()
19
+ .find({}, { projection: { clientId: 1, credits: 1 } })
20
+ .toArray();
21
+ return new Map(docs.map((c) => [c.clientId, c.credits ?? 0]));
22
+ };
23
+ exports.getAllClientCredits = getAllClientCredits;
17
24
  //# sourceMappingURL=clients.getters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clients.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.getters.ts"],"names":[],"mappings":";;;AAAA,oCAAyC;AAGlC,MAAM,oBAAoB,GAAG,GAAuB,EAAE;IAC3D,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAS,SAAS,CAAC,CAAC;AAC/C,CAAC,CAAC;AAFW,QAAA,oBAAoB,wBAE/B;AAEK,MAAM,iBAAiB,GAAG,KAAK,EACpC,MAAc,EACU,EAAE;IAC1B,MAAM,MAAM,GAAG,MAAM,IAAA,4BAAoB,GAAE,CAAC,OAAO,CAAC;QAClD,MAAM;QACN,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC,CAAC;AARW,QAAA,iBAAiB,qBAQ5B"}
1
+ {"version":3,"file":"clients.getters.js","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.getters.ts"],"names":[],"mappings":";;;AAAA,oCAAyC;AAGlC,MAAM,oBAAoB,GAAG,GAAuB,EAAE;IAC3D,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAS,SAAS,CAAC,CAAC;AAC/C,CAAC,CAAC;AAFW,QAAA,oBAAoB,wBAE/B;AAEK,MAAM,iBAAiB,GAAG,KAAK,EACpC,MAAc,EACU,EAAE;IAC1B,MAAM,MAAM,GAAG,MAAM,IAAA,4BAAoB,GAAE,CAAC,OAAO,CAAC;QAClD,MAAM;QACN,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC,CAAC;AARW,QAAA,iBAAiB,qBAQ5B;AAEK,MAAM,mBAAmB,GAAG,KAAK,IAAkC,EAAE;IAC1E,MAAM,IAAI,GAAG,MAAM,IAAA,4BAAoB,GAAE;SACtC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;SACrD,OAAO,EAAE,CAAC;IACb,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC,CAAC;AALW,QAAA,mBAAmB,uBAK9B"}
@@ -0,0 +1,10 @@
1
+ import { DeleteClientDataSummary } from "./clients.types";
2
+ export declare const clientExistsInAnyCollection: (clientId: string) => Promise<boolean>;
3
+ /**
4
+ * Deletes a client's data across talkpilot/municipal collections and logs the action.
5
+ *
6
+ * ⚠️ Does NOT delete website-talk data — `scans`/`websiteUrls` are the lookup key an
7
+ * external API needs to clean up that domain. Callers must invoke that API separately.
8
+ */
9
+ export declare const deleteClientDataAcrossDomains: (clientId: string, adminEmail: string) => Promise<DeleteClientDataSummary>;
10
+ //# sourceMappingURL=clients.lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.lifecycle.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.lifecycle.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,uBAAuB,EACxB,MAAM,iBAAiB,CAAC;AAoBzB,eAAO,MAAM,2BAA2B,GACtC,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAMjB,CAAC;AAgCF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GACxC,UAAU,MAAM,EAChB,YAAY,MAAM,KACjB,OAAO,CAAC,uBAAuB,CAsCjC,CAAC"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteClientDataAcrossDomains = exports.clientExistsInAnyCollection = void 0;
4
+ const index_1 = require("../index");
5
+ const municipal_1 = require("../../municipal");
6
+ const clients_constants_1 = require("./clients.constants");
7
+ // Skips websitalk on purpose — see the warning on `deleteClientDataAcrossDomains` below.
8
+ const findClientMatchInDb = async (db, clientId) => {
9
+ const collections = await db.listCollections().toArray();
10
+ return Promise.all(collections
11
+ .filter((c) => !clients_constants_1.DELETE_DENYLIST.includes(c.name))
12
+ .map(async (c) => {
13
+ const doc = await db
14
+ .collection(c.name)
15
+ .findOne({ $or: [{ clientId }, { client_id: clientId }] });
16
+ return { collectionName: c.name, matched: !!doc };
17
+ }));
18
+ };
19
+ const clientExistsInAnyCollection = async (clientId) => {
20
+ const [talkpilotResults, municipalResults] = await Promise.all([
21
+ findClientMatchInDb((0, index_1.getDb)(), clientId),
22
+ findClientMatchInDb((0, municipal_1.getDb)(), clientId),
23
+ ]);
24
+ return [...talkpilotResults, ...municipalResults].some((r) => r.matched);
25
+ };
26
+ exports.clientExistsInAnyCollection = clientExistsInAnyCollection;
27
+ const deleteClientFromDb = async (db, clientId) => {
28
+ const collections = await db.listCollections().toArray();
29
+ return Promise.all(collections
30
+ .filter((c) => !clients_constants_1.DELETE_DENYLIST.includes(c.name))
31
+ .map(async (c) => {
32
+ try {
33
+ const result = await db
34
+ .collection(c.name)
35
+ .deleteMany({ $or: [{ clientId }, { client_id: clientId }] });
36
+ return {
37
+ collectionName: c.name,
38
+ deletedCount: result.deletedCount,
39
+ success: true,
40
+ };
41
+ }
42
+ catch (error) {
43
+ return {
44
+ collectionName: c.name,
45
+ deletedCount: 0,
46
+ success: false,
47
+ error: error instanceof Error ? error.message : String(error),
48
+ };
49
+ }
50
+ }));
51
+ };
52
+ /**
53
+ * Deletes a client's data across talkpilot/municipal collections and logs the action.
54
+ *
55
+ * ⚠️ Does NOT delete website-talk data — `scans`/`websiteUrls` are the lookup key an
56
+ * external API needs to clean up that domain. Callers must invoke that API separately.
57
+ */
58
+ const deleteClientDataAcrossDomains = async (clientId, adminEmail) => {
59
+ const exists = await (0, exports.clientExistsInAnyCollection)(clientId);
60
+ if (!exists) {
61
+ return {
62
+ clientId,
63
+ deleted: false,
64
+ reason: "Client does not exist in any collection",
65
+ };
66
+ }
67
+ const [talkpilotResults, municipalResults] = await Promise.all([
68
+ deleteClientFromDb((0, index_1.getDb)(), clientId),
69
+ deleteClientFromDb((0, municipal_1.getDb)(), clientId),
70
+ ]);
71
+ const results = [...talkpilotResults, ...municipalResults];
72
+ const allSucceeded = results.every((r) => r.success);
73
+ await (0, index_1.insertAuditLog)({
74
+ clientId,
75
+ adminEmail,
76
+ action: "delete",
77
+ timestamp: new Date(),
78
+ allSucceeded,
79
+ ...(allSucceeded
80
+ ? {}
81
+ : {
82
+ failedCollections: results
83
+ .filter((r) => !r.success)
84
+ .map((r) => r.collectionName),
85
+ }),
86
+ });
87
+ return {
88
+ clientId,
89
+ deleted: true,
90
+ results,
91
+ allSucceeded,
92
+ };
93
+ };
94
+ exports.deleteClientDataAcrossDomains = deleteClientDataAcrossDomains;
95
+ //# sourceMappingURL=clients.lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.lifecycle.js","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.lifecycle.ts"],"names":[],"mappings":"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"}
@@ -15,4 +15,25 @@ export type Client = {
15
15
  export type ClientDoc = Client & {
16
16
  _id: ObjectId;
17
17
  };
18
+ export type CollectionMatch = {
19
+ collectionName: string;
20
+ matched: boolean;
21
+ };
22
+ export type CollectionDeleteResult = {
23
+ collectionName: string;
24
+ deletedCount: number;
25
+ success: boolean;
26
+ error?: string;
27
+ };
28
+ /** Discriminated union: `deleted` tells you which shape you got without guessing. */
29
+ export type DeleteClientDataSummary = {
30
+ clientId: string;
31
+ deleted: false;
32
+ reason: string;
33
+ } | {
34
+ clientId: string;
35
+ deleted: true;
36
+ results: CollectionDeleteResult[];
37
+ allSucceeded: boolean;
38
+ };
18
39
  //# sourceMappingURL=clients.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clients.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE3I,MAAM,MAAM,MAAM,GAAG;IACnB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"clients.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/clients.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE3I,MAAM,MAAM,MAAM,GAAG;IACnB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEnD,MAAM,MAAM,eAAe,GAAG;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,sBAAsB,GAAG;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qFAAqF;AACrF,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpD;IACE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC"}
@@ -1,5 +1,7 @@
1
+ export * from "./clients.constants";
1
2
  export * from "./clients.getters";
2
3
  export * from "./clients.types";
3
4
  export * from "./clients.quota.getters";
4
5
  export * from "./clients.quota.types";
6
+ export * from "./clients.lifecycle";
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/clients/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
@@ -14,8 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./clients.constants"), exports);
17
18
  __exportStar(require("./clients.getters"), exports);
18
19
  __exportStar(require("./clients.types"), exports);
19
20
  __exportStar(require("./clients.quota.getters"), exports);
20
21
  __exportStar(require("./clients.quota.types"), exports);
22
+ __exportStar(require("./clients.lifecycle"), exports);
21
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/talkpilot/clients/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,kDAAgC;AAChC,0DAAwC;AACxC,wDAAsC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/talkpilot/clients/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,oDAAkC;AAClC,kDAAgC;AAChC,0DAAwC;AACxC,wDAAsC;AACtC,sDAAoC"}
@@ -1,8 +1,5 @@
1
1
  import type { Collection, ObjectId, WithId } from "mongodb";
2
- import type { Flow, FlowUpdateParams } from "./flows.types";
2
+ import type { Flow } from "./flows.types";
3
3
  export declare const getFlowsCollection: () => Collection<Flow>;
4
4
  export declare const findFlowById: (flowId: ObjectId, clientId: string) => Promise<WithId<Flow> | null>;
5
- export declare const createFlow: (flow: Flow) => Promise<WithId<Flow>>;
6
- /** Returns false when no flow matches the id for this client. */
7
- export declare const updateFlowById: (flowId: ObjectId, clientId: string, update: FlowUpdateParams) => Promise<boolean>;
8
5
  //# sourceMappingURL=flows.getter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"flows.getter.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/flows/flows.getter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAc,MAAM,EAAE,MAAM,SAAS,CAAC;AAExE,OAAO,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE5D,eAAO,MAAM,kBAAkB,QAAO,UAAU,CAAC,IAAI,CAEpD,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,QAAQ,QAAQ,EAChB,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAE7B,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,MAAM,IAAI,KAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAKjE,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,cAAc,GACzB,QAAQ,QAAQ,EAChB,UAAU,MAAM,EAChB,QAAQ,gBAAgB,KACvB,OAAO,CAAC,OAAO,CAMjB,CAAC"}
1
+ {"version":3,"file":"flows.getter.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/flows/flows.getter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,eAAO,MAAM,kBAAkB,QAAO,UAAU,CAAC,IAAI,CAEpD,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,QAAQ,QAAQ,EAChB,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAE7B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateFlowById = exports.createFlow = exports.findFlowById = exports.getFlowsCollection = void 0;
3
+ exports.findFlowById = exports.getFlowsCollection = void 0;
4
4
  const index_1 = require("../index");
5
5
  const getFlowsCollection = () => {
6
6
  return (0, index_1.getDb)().collection("flows");
@@ -10,15 +10,4 @@ const findFlowById = (flowId, clientId) => {
10
10
  return (0, exports.getFlowsCollection)().findOne({ _id: flowId, clientId });
11
11
  };
12
12
  exports.findFlowById = findFlowById;
13
- const createFlow = async (flow) => {
14
- const { insertedId } = await (0, exports.getFlowsCollection)().insertOne(flow);
15
- return { ...flow, _id: insertedId };
16
- };
17
- exports.createFlow = createFlow;
18
- /** Returns false when no flow matches the id for this client. */
19
- const updateFlowById = async (flowId, clientId, update) => {
20
- const { matchedCount } = await (0, exports.getFlowsCollection)().updateOne({ _id: flowId, clientId }, { $set: { ...update, updatedAt: new Date() } });
21
- return matchedCount > 0;
22
- };
23
- exports.updateFlowById = updateFlowById;
24
13
  //# sourceMappingURL=flows.getter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"flows.getter.js","sourceRoot":"","sources":["../../../src/talkpilot/flows/flows.getter.ts"],"names":[],"mappings":";;;AACA,oCAAiC;AAG1B,MAAM,kBAAkB,GAAG,GAAqB,EAAE;IACvD,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAO,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAC;AAFW,QAAA,kBAAkB,sBAE7B;AAEK,MAAM,YAAY,GAAG,CAC1B,MAAgB,EAChB,QAAgB,EACc,EAAE;IAChC,OAAO,IAAA,0BAAkB,GAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC;AALW,QAAA,YAAY,gBAKvB;AAEK,MAAM,UAAU,GAAG,KAAK,EAAE,IAAU,EAAyB,EAAE;IACpE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,0BAAkB,GAAE,CAAC,SAAS,CACzD,IAAwB,CACzB,CAAC;IACF,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC,CAAC;AALW,QAAA,UAAU,cAKrB;AAEF,iEAAiE;AAC1D,MAAM,cAAc,GAAG,KAAK,EACjC,MAAgB,EAChB,QAAgB,EAChB,MAAwB,EACN,EAAE;IACpB,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,IAAA,0BAAkB,GAAE,CAAC,SAAS,CAC3D,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,EACzB,EAAE,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,EAAE,CAC/C,CAAC;IACF,OAAO,YAAY,GAAG,CAAC,CAAC;AAC1B,CAAC,CAAC;AAVW,QAAA,cAAc,kBAUzB"}
1
+ {"version":3,"file":"flows.getter.js","sourceRoot":"","sources":["../../../src/talkpilot/flows/flows.getter.ts"],"names":[],"mappings":";;;AACA,oCAAiC;AAG1B,MAAM,kBAAkB,GAAG,GAAqB,EAAE;IACvD,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAO,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAC;AAFW,QAAA,kBAAkB,sBAE7B;AAEK,MAAM,YAAY,GAAG,CAC1B,MAAgB,EAChB,QAAgB,EACc,EAAE;IAChC,OAAO,IAAA,0BAAkB,GAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC;AALW,QAAA,YAAY,gBAKvB"}