@twentyhq/call-recorder 1.0.1 → 1.0.2

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 (237) hide show
  1. package/manifest.json +297 -0
  2. package/package.json +2 -2
  3. package/src/front-components/calendar-event-recording.front-component.mjs +269 -0
  4. package/src/front-components/calendar-event-recording.front-component.mjs.map +7 -0
  5. package/src/logic-functions/process-recall-webhook.mjs +1744 -0
  6. package/src/logic-functions/process-recall-webhook.mjs.map +7 -0
  7. package/src/logic-functions/recall-webhook.mjs +391 -0
  8. package/src/logic-functions/recall-webhook.mjs.map +7 -0
  9. package/src/logic-functions/reconcile-call-recorder-calendar-event.mjs +1602 -0
  10. package/src/logic-functions/reconcile-call-recorder-calendar-event.mjs.map +7 -0
  11. package/src/logic-functions/reconcile-stale-bot-state.mjs +2268 -0
  12. package/src/logic-functions/reconcile-stale-bot-state.mjs.map +7 -0
  13. package/.env.example +0 -5
  14. package/.nvmrc +0 -1
  15. package/.oxlintrc.json +0 -20
  16. package/AGENTS.md +0 -67
  17. package/CLAUDE.md +0 -67
  18. package/README.md +0 -24
  19. package/SETUP.md +0 -95
  20. package/src/__tests__/global-setup.ts +0 -100
  21. package/src/__tests__/schema.integration-test.ts +0 -104
  22. package/src/application-config.ts +0 -96
  23. package/src/constants/__tests__/call-recording-field-universal-identifiers.test.ts +0 -19
  24. package/src/constants/app-description.ts +0 -2
  25. package/src/constants/app-display-name.ts +0 -1
  26. package/src/constants/application-universal-identifier.ts +0 -2
  27. package/src/constants/calendar-event-reconciliation-logic-function-universal-identifier.ts +0 -2
  28. package/src/constants/calendar-event-record-page-layout-universal-identifier.ts +0 -2
  29. package/src/constants/calendar-event-recording-front-component-universal-identifier.ts +0 -2
  30. package/src/constants/calendar-event-recording-page-layout-tab-universal-identifier.ts +0 -2
  31. package/src/constants/calendar-event-recording-page-layout-widget-universal-identifier.ts +0 -2
  32. package/src/constants/call-recorder-everyone-left-timeout-seconds-app-variable-universal-identifier.ts +0 -2
  33. package/src/constants/call-recorder-failure-reason-on-call-recording-field-universal-identifier.ts +0 -2
  34. package/src/constants/call-recorder-join-early-minutes-app-variable-universal-identifier.ts +0 -2
  35. package/src/constants/call-recorder-name-app-variable-universal-identifier.ts +0 -2
  36. package/src/constants/call-recorder-noone-joined-timeout-seconds-app-variable-universal-identifier.ts +0 -2
  37. package/src/constants/call-recorder-preference-off-option-id.ts +0 -2
  38. package/src/constants/call-recorder-preference-on-calendar-event-field-universal-identifier.ts +0 -2
  39. package/src/constants/call-recorder-preference-on-calendar-event-view-field-universal-identifier.ts +0 -2
  40. package/src/constants/call-recorder-preference-on-option-id.ts +0 -2
  41. package/src/constants/call-recorder-preference.ts +0 -4
  42. package/src/constants/call-recorder-waiting-room-timeout-seconds-app-variable-universal-identifier.ts +0 -2
  43. package/src/constants/call-recording-audio-field-universal-identifier.ts +0 -2
  44. package/src/constants/call-recording-video-field-universal-identifier.ts +0 -2
  45. package/src/constants/default-role-universal-identifier.ts +0 -2
  46. package/src/constants/process-recall-webhook-logic-function-universal-identifier.ts +0 -2
  47. package/src/constants/recall-webhook-logic-function-universal-identifier.ts +0 -2
  48. package/src/constants/stale-bot-state-logic-function-universal-identifier.ts +0 -2
  49. package/src/default-role.ts +0 -69
  50. package/src/fields/call-recorder-failure-reason-on-call-recording.field.ts +0 -22
  51. package/src/fields/call-recorder-preference-on-calendar-event.field.ts +0 -41
  52. package/src/front-components/calendar-event-recording.front-component.tsx +0 -13
  53. package/src/front-components/components/CalendarEventRecording.tsx +0 -39
  54. package/src/front-components/components/CalendarEventRecordingBody.tsx +0 -96
  55. package/src/front-components/components/CalendarEventRecordingContent.tsx +0 -111
  56. package/src/front-components/components/RecordingTranscript.tsx +0 -92
  57. package/src/front-components/components/RecordingVideoPlayer.tsx +0 -52
  58. package/src/front-components/components/TranscriptEntryList.tsx +0 -61
  59. package/src/front-components/components/TranscriptEntryListItem.tsx +0 -115
  60. package/src/front-components/components/TranscriptErrorBox.tsx +0 -48
  61. package/src/front-components/components/TranscriptSpeakerAvatar.tsx +0 -141
  62. package/src/front-components/components/TranscriptSpeakerChip.tsx +0 -51
  63. package/src/front-components/constants/recording-theme-css-variables.ts +0 -40
  64. package/src/front-components/hooks/use-calendar-event-participants.ts +0 -172
  65. package/src/front-components/hooks/use-calendar-event-recording.ts +0 -155
  66. package/src/front-components/types/calendar-event-participant-by-speaker-name.type.ts +0 -6
  67. package/src/front-components/types/calendar-event-recording-participant.type.ts +0 -7
  68. package/src/front-components/types/transcript-entry.type.ts +0 -13
  69. package/src/front-components/utils/__tests__/find-active-transcript-entry-index.test.ts +0 -66
  70. package/src/front-components/utils/__tests__/format-transcript-timestamp.test.ts +0 -29
  71. package/src/front-components/utils/__tests__/get-speaker-name-match-keys.test.ts +0 -22
  72. package/src/front-components/utils/__tests__/parse-transcript-entries.test.ts +0 -162
  73. package/src/front-components/utils/build-calendar-event-participant-by-speaker-name.util.ts +0 -45
  74. package/src/front-components/utils/find-active-transcript-entry-index.util.ts +0 -77
  75. package/src/front-components/utils/format-transcript-timestamp.util.ts +0 -16
  76. package/src/front-components/utils/get-absolute-avatar-url.util.ts +0 -48
  77. package/src/front-components/utils/get-calendar-event-participant-for-speaker-name.util.ts +0 -24
  78. package/src/front-components/utils/get-speaker-name-match-keys.util.ts +0 -64
  79. package/src/front-components/utils/get-video-file-extension.util.ts +0 -23
  80. package/src/front-components/utils/parse-transcript-entries.util.ts +0 -85
  81. package/src/logic-functions/__tests__/process-recall-webhook.test.ts +0 -62
  82. package/src/logic-functions/__tests__/recall-webhook.test.ts +0 -180
  83. package/src/logic-functions/constants/call-recorder-everyone-left-timeout-seconds-env-var-name.ts +0 -2
  84. package/src/logic-functions/constants/call-recorder-everyone-left-timeout-seconds.ts +0 -1
  85. package/src/logic-functions/constants/call-recorder-join-early-minutes-env-var-name.ts +0 -2
  86. package/src/logic-functions/constants/call-recorder-name-env-var-name.ts +0 -1
  87. package/src/logic-functions/constants/call-recorder-noone-joined-timeout-seconds-env-var-name.ts +0 -2
  88. package/src/logic-functions/constants/call-recorder-noone-joined-timeout-seconds.ts +0 -1
  89. package/src/logic-functions/constants/call-recorder-recording-retention-hours-env-var-name.ts +0 -2
  90. package/src/logic-functions/constants/call-recorder-waiting-room-timeout-seconds-env-var-name.ts +0 -2
  91. package/src/logic-functions/constants/call-recorder-waiting-room-timeout-seconds.ts +0 -1
  92. package/src/logic-functions/constants/call-recording-micro-credits-per-hour.ts +0 -1
  93. package/src/logic-functions/constants/call-recording-request-status.ts +0 -5
  94. package/src/logic-functions/constants/call-recording-status.ts +0 -9
  95. package/src/logic-functions/constants/default-call-recorder-join-early-minutes.ts +0 -1
  96. package/src/logic-functions/constants/default-call-recorder-name.ts +0 -1
  97. package/src/logic-functions/constants/default-call-recorder-recording-retention-hours.ts +0 -2
  98. package/src/logic-functions/constants/default-recall-region.ts +0 -1
  99. package/src/logic-functions/constants/milliseconds-per-minute.ts +0 -1
  100. package/src/logic-functions/constants/non-terminal-call-recording-statuses.ts +0 -8
  101. package/src/logic-functions/constants/recall-api-key-env-var-name.ts +0 -1
  102. package/src/logic-functions/constants/recall-api-max-attempts.ts +0 -1
  103. package/src/logic-functions/constants/recall-api-retry-delay-ms.ts +0 -1
  104. package/src/logic-functions/constants/recall-bot-automatic-leave.ts +0 -74
  105. package/src/logic-functions/constants/recall-bot-everyone-left-min-activate-after-seconds.ts +0 -1
  106. package/src/logic-functions/constants/recall-bot-recording-config.ts +0 -34
  107. package/src/logic-functions/constants/recall-region-env-var-name.ts +0 -1
  108. package/src/logic-functions/constants/recall-webhook-secret-env-var-name.ts +0 -1
  109. package/src/logic-functions/constants/restricted-field-placeholder.ts +0 -3
  110. package/src/logic-functions/constants/stale-bot-state-cron-pattern.ts +0 -1
  111. package/src/logic-functions/constants/twenty-page-size.ts +0 -1
  112. package/src/logic-functions/data/__tests__/complete-call-recording-ingestion.test.ts +0 -55
  113. package/src/logic-functions/data/__tests__/fetch-all-nodes.test.ts +0 -43
  114. package/src/logic-functions/data/__tests__/get-current-workspace-id.test.ts +0 -38
  115. package/src/logic-functions/data/__tests__/strip-restricted-field-value.test.ts +0 -22
  116. package/src/logic-functions/data/complete-call-recording-ingestion.util.ts +0 -24
  117. package/src/logic-functions/data/create-call-recording.util.ts +0 -41
  118. package/src/logic-functions/data/fetch-all-nodes.util.ts +0 -44
  119. package/src/logic-functions/data/fetch-calendar-events-by-filter.util.ts +0 -80
  120. package/src/logic-functions/data/fetch-calendar-events-by-ids.util.ts +0 -20
  121. package/src/logic-functions/data/fetch-calendar-events-by-starts-at-values.util.ts +0 -19
  122. package/src/logic-functions/data/find-call-recordings-by-calendar-event-ids.util.ts +0 -17
  123. package/src/logic-functions/data/find-call-recordings-by-filter.util.ts +0 -102
  124. package/src/logic-functions/data/find-call-recordings-by-ids.util.ts +0 -17
  125. package/src/logic-functions/data/find-open-scheduled-call-recordings.util.ts +0 -14
  126. package/src/logic-functions/data/get-current-workspace-id.util.ts +0 -36
  127. package/src/logic-functions/data/strip-restricted-field-value.util.ts +0 -6
  128. package/src/logic-functions/data/update-call-recording.util.ts +0 -24
  129. package/src/logic-functions/domain/__tests__/build-call-recorder-policy-result.test.ts +0 -47
  130. package/src/logic-functions/domain/__tests__/compute-call-recording-charge.test.ts +0 -71
  131. package/src/logic-functions/domain/__tests__/compute-call-recording-id-for-meeting.test.ts +0 -37
  132. package/src/logic-functions/domain/__tests__/compute-real-meeting-key.test.ts +0 -88
  133. package/src/logic-functions/domain/__tests__/is-call-recording-ingestion-complete.test.ts +0 -59
  134. package/src/logic-functions/domain/__tests__/is-call-recording-status-downgrade.test.ts +0 -37
  135. package/src/logic-functions/domain/__tests__/resolve-call-recorder-policy-result.test.ts +0 -120
  136. package/src/logic-functions/domain/__tests__/should-complete-call-recording-ingestion.test.ts +0 -102
  137. package/src/logic-functions/domain/aggregate-call-recorder-policy-results-by-meeting.util.ts +0 -42
  138. package/src/logic-functions/domain/build-call-recorder-policy-result.util.ts +0 -53
  139. package/src/logic-functions/domain/build-failed-transcript-marker.util.ts +0 -13
  140. package/src/logic-functions/domain/build-pending-transcript-marker.util.ts +0 -13
  141. package/src/logic-functions/domain/build-recall-routing-metadata.util.ts +0 -12
  142. package/src/logic-functions/domain/build-transcript-failure-reason.util.ts +0 -7
  143. package/src/logic-functions/domain/compute-call-recording-charge.util.ts +0 -41
  144. package/src/logic-functions/domain/compute-call-recording-id-for-meeting.util.ts +0 -16
  145. package/src/logic-functions/domain/compute-real-meeting-key.util.ts +0 -48
  146. package/src/logic-functions/domain/compute-recall-bot-join-at.util.ts +0 -34
  147. package/src/logic-functions/domain/is-call-recording-ingestion-complete.util.ts +0 -19
  148. package/src/logic-functions/domain/is-call-recording-status-downgrade.util.ts +0 -37
  149. package/src/logic-functions/domain/is-recall-recording-done-signal.util.ts +0 -13
  150. package/src/logic-functions/domain/map-recall-status-code-to-call-recording-status.util.ts +0 -26
  151. package/src/logic-functions/domain/parse-transcript-marker.util.ts +0 -29
  152. package/src/logic-functions/domain/resolve-call-recorder-policy-result.util.ts +0 -72
  153. package/src/logic-functions/domain/should-complete-call-recording-ingestion.util.ts +0 -32
  154. package/src/logic-functions/flows/__tests__/charge-completed-call-recording.test.ts +0 -45
  155. package/src/logic-functions/flows/__tests__/complete-and-charge-call-recording.test.ts +0 -61
  156. package/src/logic-functions/flows/__tests__/converge-diverged-call-recordings.test.ts +0 -727
  157. package/src/logic-functions/flows/__tests__/download-transcript.test.ts +0 -74
  158. package/src/logic-functions/flows/__tests__/handle-recall-webhook.test.ts +0 -1301
  159. package/src/logic-functions/flows/__tests__/heal-call-recordings-missing-bot.test.ts +0 -225
  160. package/src/logic-functions/flows/__tests__/ingest-call-recording-media.test.ts +0 -153
  161. package/src/logic-functions/flows/__tests__/reap-orphaned-call-recorders.test.ts +0 -425
  162. package/src/logic-functions/flows/__tests__/reconcile-call-recorder.test.ts +0 -1007
  163. package/src/logic-functions/flows/cancel-call-recording-request.util.ts +0 -46
  164. package/src/logic-functions/flows/charge-completed-call-recording.util.ts +0 -31
  165. package/src/logic-functions/flows/complete-and-charge-call-recording.util.ts +0 -29
  166. package/src/logic-functions/flows/converge-diverged-call-recordings-result.type.ts +0 -8
  167. package/src/logic-functions/flows/converge-diverged-call-recordings.util.ts +0 -447
  168. package/src/logic-functions/flows/download-transcript.util.ts +0 -67
  169. package/src/logic-functions/flows/ensure-call-recorder.util.ts +0 -73
  170. package/src/logic-functions/flows/handle-recall-webhook.util.ts +0 -672
  171. package/src/logic-functions/flows/heal-call-recordings-missing-bot.util.ts +0 -82
  172. package/src/logic-functions/flows/ingest-call-recording-media.util.ts +0 -128
  173. package/src/logic-functions/flows/persist-call-recording-progress.util.ts +0 -58
  174. package/src/logic-functions/flows/reap-orphaned-call-recorders.util.ts +0 -183
  175. package/src/logic-functions/flows/reconcile-call-recorder.util.ts +0 -495
  176. package/src/logic-functions/flows/reconcile-call-recording-transcript-artifact-result.type.ts +0 -11
  177. package/src/logic-functions/flows/reconcile-call-recording-transcript-artifact.util.ts +0 -182
  178. package/src/logic-functions/flows/reschedule-call-recording-bot.util.ts +0 -69
  179. package/src/logic-functions/process-recall-webhook.ts +0 -23
  180. package/src/logic-functions/recall-api/__tests__/extract-recall-bot-convergence.test.ts +0 -153
  181. package/src/logic-functions/recall-api/__tests__/extract-recall-media-urls.test.ts +0 -67
  182. package/src/logic-functions/recall-api/__tests__/recall-bot-api.test.ts +0 -744
  183. package/src/logic-functions/recall-api/__tests__/verify-recall-webhook-signature.test.ts +0 -122
  184. package/src/logic-functions/recall-api/cancel-recall-bot.util.ts +0 -28
  185. package/src/logic-functions/recall-api/create-async-recall-transcript.util.ts +0 -47
  186. package/src/logic-functions/recall-api/eject-recall-bot.util.ts +0 -28
  187. package/src/logic-functions/recall-api/extract-recall-bot-convergence.util.ts +0 -149
  188. package/src/logic-functions/recall-api/extract-recall-bot-id.util.ts +0 -10
  189. package/src/logic-functions/recall-api/extract-recall-media-urls.util.ts +0 -30
  190. package/src/logic-functions/recall-api/extract-twenty-workspace-id-from-recall-webhook.util.ts +0 -8
  191. package/src/logic-functions/recall-api/get-recall-api-config.util.ts +0 -59
  192. package/src/logic-functions/recall-api/get-recall-bot.util.ts +0 -42
  193. package/src/logic-functions/recall-api/get-recall-recording.util.ts +0 -31
  194. package/src/logic-functions/recall-api/get-recall-webhook-bot-metadata.util.ts +0 -18
  195. package/src/logic-functions/recall-api/list-recall-transcripts.util.ts +0 -141
  196. package/src/logic-functions/recall-api/list-scheduled-recall-bots.util.ts +0 -106
  197. package/src/logic-functions/recall-api/normalize-recall-timestamp.util.ts +0 -14
  198. package/src/logic-functions/recall-api/parse-recall-webhook-event.util.ts +0 -88
  199. package/src/logic-functions/recall-api/recall-bot-api-request.util.ts +0 -165
  200. package/src/logic-functions/recall-api/recall-transcript-summary.type.ts +0 -5
  201. package/src/logic-functions/recall-api/reschedule-recall-bot.util.ts +0 -56
  202. package/src/logic-functions/recall-api/retrieve-recall-transcript.util.ts +0 -71
  203. package/src/logic-functions/recall-api/schedule-recall-bot.util.ts +0 -68
  204. package/src/logic-functions/recall-api/verify-recall-webhook-signature.util.ts +0 -109
  205. package/src/logic-functions/recall-webhook.ts +0 -90
  206. package/src/logic-functions/reconcile-call-recorder-calendar-event.ts +0 -178
  207. package/src/logic-functions/reconcile-stale-bot-state.ts +0 -106
  208. package/src/logic-functions/types/calendar-event-record.type.ts +0 -5
  209. package/src/logic-functions/types/call-recorder-policy-calendar-event-input.type.ts +0 -10
  210. package/src/logic-functions/types/call-recorder-policy-input.type.ts +0 -9
  211. package/src/logic-functions/types/call-recorder-policy-not-required-reason.type.ts +0 -5
  212. package/src/logic-functions/types/call-recorder-policy-required-reason.type.ts +0 -1
  213. package/src/logic-functions/types/call-recorder-policy-result-for-calendar-event.type.ts +0 -9
  214. package/src/logic-functions/types/call-recorder-policy-result-for-meeting.type.ts +0 -6
  215. package/src/logic-functions/types/call-recorder-policy-result.type.ts +0 -12
  216. package/src/logic-functions/types/call-recorder-reconciliation-result.type.ts +0 -16
  217. package/src/logic-functions/types/call-recording-media-file.type.ts +0 -1
  218. package/src/logic-functions/types/call-recording-record.type.ts +0 -15
  219. package/src/logic-functions/types/call-recording-update-fields.type.ts +0 -20
  220. package/src/logic-functions/types/files-field-value.type.ts +0 -1
  221. package/src/logic-functions/types/meeting-recording.type.ts +0 -7
  222. package/src/logic-functions/types/recall-bot-operation-result.type.ts +0 -19
  223. package/src/logic-functions/types/recall-routing-metadata.type.ts +0 -4
  224. package/src/logic-functions/types/removed-call-recorder-occurrence.type.ts +0 -6
  225. package/src/logic-functions/types/transcript-marker.type.ts +0 -6
  226. package/src/logic-functions/utils/as-record.util.ts +0 -6
  227. package/src/logic-functions/utils/get-application-variable-value.util.ts +0 -3
  228. package/src/logic-functions/utils/get-record-at-path.util.ts +0 -10
  229. package/src/logic-functions/utils/get-string.util.ts +0 -4
  230. package/src/logic-functions/utils/get-unique-sorted-ids.util.ts +0 -8
  231. package/src/logic-functions/utils/is-non-empty-string.util.ts +0 -5
  232. package/src/page-layouts/calendar-event-recording-tab.ts +0 -33
  233. package/src/view-fields/call-recorder-preference-on-calendar-event.view-field.ts +0 -27
  234. package/tsconfig.json +0 -42
  235. package/tsconfig.spec.json +0 -9
  236. package/vitest.config.ts +0 -31
  237. package/vitest.unit.config.ts +0 -14
@@ -0,0 +1,1744 @@
1
+ import { createRequire as __createRequire } from 'module';
2
+ const require = __createRequire(import.meta.url);
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJS = (cb, mod) => function __require() {
10
+ try {
11
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
12
+ } catch (e2) {
13
+ throw mod = 0, e2;
14
+ }
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // node_modules/@sniptt/guards/build/guards/primitives.js
34
+ var require_primitives = __commonJS({
35
+ "node_modules/@sniptt/guards/build/guards/primitives.js"(exports) {
36
+ "use strict";
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.isSymbol = exports.isBigInt = exports.isString = exports.isNumber = exports.isBoolean = exports.isUndefined = void 0;
39
+ var isUndefined17 = (term) => {
40
+ return typeof term === "undefined";
41
+ };
42
+ exports.isUndefined = isUndefined17;
43
+ var isBoolean = (term) => {
44
+ return typeof term === "boolean";
45
+ };
46
+ exports.isBoolean = isBoolean;
47
+ var isNumber = (term) => {
48
+ return typeof term === "number" && !Number.isNaN(term);
49
+ };
50
+ exports.isNumber = isNumber;
51
+ var isString4 = (term) => {
52
+ return typeof term === "string";
53
+ };
54
+ exports.isString = isString4;
55
+ var isBigInt = (term) => {
56
+ return typeof term === "bigint";
57
+ };
58
+ exports.isBigInt = isBigInt;
59
+ var isSymbol = (term) => {
60
+ return typeof term === "symbol";
61
+ };
62
+ exports.isSymbol = isSymbol;
63
+ }
64
+ });
65
+
66
+ // node_modules/@sniptt/guards/build/guards/structural.js
67
+ var require_structural = __commonJS({
68
+ "node_modules/@sniptt/guards/build/guards/structural.js"(exports) {
69
+ "use strict";
70
+ Object.defineProperty(exports, "__esModule", { value: true });
71
+ exports.isDate = exports.isWeakSet = exports.isWeakMap = exports.isSet = exports.isMap = exports.isArray = exports.isObject = exports.isFunction = exports.isNull = void 0;
72
+ var isNull5 = (term) => {
73
+ return term === null;
74
+ };
75
+ exports.isNull = isNull5;
76
+ var isFunction = (term) => {
77
+ return typeof term === "function";
78
+ };
79
+ exports.isFunction = isFunction;
80
+ var isObject2 = (term) => {
81
+ return !exports.isNull(term) && typeof term === "object";
82
+ };
83
+ exports.isObject = isObject2;
84
+ var isArray4 = (term) => {
85
+ return Array.isArray(term);
86
+ };
87
+ exports.isArray = isArray4;
88
+ var isMap = (term) => {
89
+ return term instanceof Map;
90
+ };
91
+ exports.isMap = isMap;
92
+ var isSet = (term) => {
93
+ return term instanceof Set;
94
+ };
95
+ exports.isSet = isSet;
96
+ var isWeakMap = (term) => {
97
+ return term instanceof WeakMap;
98
+ };
99
+ exports.isWeakMap = isWeakMap;
100
+ var isWeakSet = (term) => {
101
+ return term instanceof WeakSet;
102
+ };
103
+ exports.isWeakSet = isWeakSet;
104
+ var isDate = (term) => {
105
+ return term instanceof Date;
106
+ };
107
+ exports.isDate = isDate;
108
+ }
109
+ });
110
+
111
+ // node_modules/@sniptt/guards/build/guards/convenience.js
112
+ var require_convenience = __commonJS({
113
+ "node_modules/@sniptt/guards/build/guards/convenience.js"(exports) {
114
+ "use strict";
115
+ Object.defineProperty(exports, "__esModule", { value: true });
116
+ exports.isNegativeInteger = exports.isNonNegativeInteger = exports.isPositiveInteger = exports.isInteger = exports.isNumberOrNaN = exports.isNonEmptyString = exports.isNonEmptyArray = exports.isObjectOrNull = void 0;
117
+ var primitives_1 = require_primitives();
118
+ var structural_1 = require_structural();
119
+ var isObjectOrNull = (term) => {
120
+ return typeof term === "object";
121
+ };
122
+ exports.isObjectOrNull = isObjectOrNull;
123
+ var isNonEmptyArray3 = (term) => {
124
+ return structural_1.isArray(term) && term.length > 0;
125
+ };
126
+ exports.isNonEmptyArray = isNonEmptyArray3;
127
+ var isNonEmptyString2 = (term) => {
128
+ return primitives_1.isString(term) && term.length > 0;
129
+ };
130
+ exports.isNonEmptyString = isNonEmptyString2;
131
+ var isNumberOrNaN = (term) => {
132
+ return typeof term === "number";
133
+ };
134
+ exports.isNumberOrNaN = isNumberOrNaN;
135
+ var isInteger = (term) => {
136
+ return primitives_1.isNumber(term) && Number.isInteger(term);
137
+ };
138
+ exports.isInteger = isInteger;
139
+ var isPositiveInteger = (term) => {
140
+ return exports.isInteger(term) && term > 0;
141
+ };
142
+ exports.isPositiveInteger = isPositiveInteger;
143
+ var isNonNegativeInteger = (term) => {
144
+ return exports.isInteger(term) && term >= 0;
145
+ };
146
+ exports.isNonNegativeInteger = isNonNegativeInteger;
147
+ var isNegativeInteger = (term) => {
148
+ return exports.isInteger(term) && term < 0;
149
+ };
150
+ exports.isNegativeInteger = isNegativeInteger;
151
+ }
152
+ });
153
+
154
+ // node_modules/@sniptt/guards/build/index.js
155
+ var require_build = __commonJS({
156
+ "node_modules/@sniptt/guards/build/index.js"(exports) {
157
+ "use strict";
158
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
159
+ if (k2 === void 0) k2 = k;
160
+ Object.defineProperty(o, k2, { enumerable: true, get: function() {
161
+ return m[k];
162
+ } });
163
+ }) : (function(o, m, k, k2) {
164
+ if (k2 === void 0) k2 = k;
165
+ o[k2] = m[k];
166
+ }));
167
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
168
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
169
+ }) : function(o, v) {
170
+ o["default"] = v;
171
+ });
172
+ var __importStar = exports && exports.__importStar || function(mod) {
173
+ if (mod && mod.__esModule) return mod;
174
+ var result = {};
175
+ if (mod != null) {
176
+ for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
177
+ }
178
+ __setModuleDefault(result, mod);
179
+ return result;
180
+ };
181
+ var __exportStar = exports && exports.__exportStar || function(m, exports2) {
182
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
183
+ };
184
+ Object.defineProperty(exports, "__esModule", { value: true });
185
+ exports.structural = exports.primitives = exports.convenience = void 0;
186
+ exports.convenience = __importStar(require_convenience());
187
+ __exportStar(require_convenience(), exports);
188
+ exports.primitives = __importStar(require_primitives());
189
+ __exportStar(require_primitives(), exports);
190
+ exports.structural = __importStar(require_structural());
191
+ __exportStar(require_structural(), exports);
192
+ }
193
+ });
194
+
195
+ // src/logic-functions/process-recall-webhook.ts
196
+ import { CoreApiClient } from "twenty-client-sdk/core";
197
+
198
+ // twenty-sdk-define-stub:__twenty-sdk-define-stub__
199
+ var __defineFactoryStub = (config) => ({
200
+ success: true,
201
+ config,
202
+ errors: []
203
+ });
204
+ var __anyHandler = {
205
+ get(_target, prop) {
206
+ if (prop === "__esModule") return true;
207
+ if (prop === Symbol.toPrimitive) return () => "";
208
+ if (typeof prop === "symbol") return void 0;
209
+ return new Proxy(() => void 0, __anyHandler);
210
+ },
211
+ apply() {
212
+ return new Proxy(() => void 0, __anyHandler);
213
+ }
214
+ };
215
+ var __anyStub = new Proxy(() => void 0, __anyHandler);
216
+ var defineLogicFunction = __defineFactoryStub;
217
+
218
+ // src/constants/process-recall-webhook-logic-function-universal-identifier.ts
219
+ var PROCESS_RECALL_WEBHOOK_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER = "13d9c427-447e-494a-8d3c-1af5d0bacb82";
220
+
221
+ // src/logic-functions/flows/handle-recall-webhook.util.ts
222
+ var import_guards20 = __toESM(require_build());
223
+
224
+ // src/logic-functions/domain/build-failed-transcript-marker.util.ts
225
+ var buildFailedTranscriptMarker = ({
226
+ recallTranscriptId,
227
+ subCode
228
+ }) => ({
229
+ recallTranscriptId,
230
+ status: "FAILED",
231
+ subCode
232
+ });
233
+
234
+ // src/logic-functions/domain/build-transcript-failure-reason.util.ts
235
+ var import_guards = __toESM(require_build());
236
+ var buildTranscriptFailureReason = (subCode) => {
237
+ return (0, import_guards.isNull)(subCode) ? "transcript_failed" : `transcript_failed:${subCode}`;
238
+ };
239
+
240
+ // src/logic-functions/flows/download-transcript.util.ts
241
+ var import_guards7 = __toESM(require_build());
242
+
243
+ // src/logic-functions/recall-api/retrieve-recall-transcript.util.ts
244
+ var import_guards6 = __toESM(require_build());
245
+
246
+ // src/logic-functions/utils/as-record.util.ts
247
+ var import_guards2 = __toESM(require_build());
248
+ var asRecord = (value) => (0, import_guards2.isObject)(value) && !(0, import_guards2.isArray)(value) ? value : void 0;
249
+
250
+ // src/logic-functions/recall-api/get-recall-api-config.util.ts
251
+ var import_guards4 = __toESM(require_build());
252
+
253
+ // src/logic-functions/constants/call-recorder-name-env-var-name.ts
254
+ var CALL_RECORDER_NAME_ENV_VAR_NAME = "CALL_RECORDER_NAME";
255
+
256
+ // src/logic-functions/constants/default-call-recorder-name.ts
257
+ var DEFAULT_CALL_RECORDER_NAME = "Twenty.com";
258
+
259
+ // src/logic-functions/constants/default-recall-region.ts
260
+ var DEFAULT_RECALL_REGION = "eu-central-1";
261
+
262
+ // src/logic-functions/constants/recall-api-key-env-var-name.ts
263
+ var RECALL_API_KEY_ENV_VAR_NAME = "RECALL_API_KEY";
264
+
265
+ // src/logic-functions/constants/recall-region-env-var-name.ts
266
+ var RECALL_REGION_ENV_VAR_NAME = "RECALL_REGION";
267
+
268
+ // src/logic-functions/utils/get-application-variable-value.util.ts
269
+ var getApplicationVariableValue = (key) => process.env[key];
270
+
271
+ // src/logic-functions/utils/is-non-empty-string.util.ts
272
+ var import_guards3 = __toESM(require_build());
273
+ var isNonEmptyString = (value) => (0, import_guards3.isString)(value) && value.trim() !== "";
274
+
275
+ // src/logic-functions/recall-api/get-recall-api-config.util.ts
276
+ var getRecallApiConfig = () => {
277
+ const apiKey = normalizeOptionalString(
278
+ getApplicationVariableValue(RECALL_API_KEY_ENV_VAR_NAME)
279
+ );
280
+ if ((0, import_guards4.isUndefined)(apiKey)) {
281
+ return {
282
+ success: false,
283
+ error: "RECALL_API_KEY server variable is not set. A server admin must set it on the Call Recorder application registration before scheduling bots."
284
+ };
285
+ }
286
+ const region = normalizeOptionalString(
287
+ getApplicationVariableValue(RECALL_REGION_ENV_VAR_NAME)
288
+ ) ?? DEFAULT_RECALL_REGION;
289
+ const botName = normalizeOptionalString(
290
+ getApplicationVariableValue(CALL_RECORDER_NAME_ENV_VAR_NAME)
291
+ ) ?? DEFAULT_CALL_RECORDER_NAME;
292
+ return {
293
+ success: true,
294
+ config: {
295
+ apiKey,
296
+ baseUrl: `https://${region}.recall.ai/api/v1`,
297
+ botName
298
+ }
299
+ };
300
+ };
301
+ var normalizeOptionalString = (value) => isNonEmptyString(value) ? value.trim() : void 0;
302
+
303
+ // src/logic-functions/utils/get-string.util.ts
304
+ var getString = (value) => isNonEmptyString(value) ? value : void 0;
305
+
306
+ // src/logic-functions/recall-api/recall-bot-api-request.util.ts
307
+ var import_guards5 = __toESM(require_build());
308
+
309
+ // src/logic-functions/constants/recall-api-max-attempts.ts
310
+ var RECALL_API_MAX_ATTEMPTS = 3;
311
+
312
+ // src/logic-functions/constants/recall-api-retry-delay-ms.ts
313
+ var RECALL_API_RETRY_DELAY_MS = 500;
314
+
315
+ // src/logic-functions/recall-api/recall-bot-api-request.util.ts
316
+ var recallBotApiRequest = async (requestArgs) => {
317
+ const maxAttempts = requestArgs.maxAttempts ?? RECALL_API_MAX_ATTEMPTS;
318
+ for (let attemptNumber = 1; ; attemptNumber++) {
319
+ const { result, isRetryable } = await performRecallBotApiRequestAttempt(requestArgs);
320
+ if (!isRetryable || attemptNumber >= maxAttempts) {
321
+ return result;
322
+ }
323
+ await sleep(RECALL_API_RETRY_DELAY_MS * attemptNumber);
324
+ }
325
+ };
326
+ var performRecallBotApiRequestAttempt = async ({
327
+ config,
328
+ path,
329
+ method,
330
+ body,
331
+ allowNotFound = false
332
+ }) => {
333
+ let response;
334
+ try {
335
+ response = await fetch(`${config.baseUrl}${path}`, {
336
+ method,
337
+ headers: {
338
+ Authorization: buildRecallApiAuthorizationHeader(config.apiKey),
339
+ ...(0, import_guards5.isUndefined)(body) ? {} : { "Content-Type": "application/json" }
340
+ },
341
+ ...(0, import_guards5.isUndefined)(body) ? {} : { body: JSON.stringify(body) }
342
+ });
343
+ } catch (error) {
344
+ return {
345
+ isRetryable: true,
346
+ result: {
347
+ ok: false,
348
+ status: null,
349
+ errorMessage: `Recall API request failed: ${error instanceof Error ? error.message : String(error)}`
350
+ }
351
+ };
352
+ }
353
+ if (allowNotFound && response.status === 404) {
354
+ return {
355
+ isRetryable: false,
356
+ result: {
357
+ ok: true,
358
+ status: response.status,
359
+ data: void 0
360
+ }
361
+ };
362
+ }
363
+ if (response.status === 204) {
364
+ return {
365
+ isRetryable: false,
366
+ result: {
367
+ ok: true,
368
+ status: response.status,
369
+ data: void 0
370
+ }
371
+ };
372
+ }
373
+ if (!response.ok) {
374
+ return {
375
+ isRetryable: isRetryableRecallApiStatus(response.status),
376
+ result: {
377
+ ok: false,
378
+ status: response.status,
379
+ errorMessage: await extractRecallApiErrorMessage(response)
380
+ }
381
+ };
382
+ }
383
+ try {
384
+ return {
385
+ isRetryable: false,
386
+ result: {
387
+ ok: true,
388
+ status: response.status,
389
+ data: await response.json()
390
+ }
391
+ };
392
+ } catch (error) {
393
+ return {
394
+ isRetryable: false,
395
+ result: {
396
+ ok: false,
397
+ status: response.status,
398
+ errorMessage: `Recall API returned a non-JSON response: ${error instanceof Error ? error.message : String(error)}`
399
+ }
400
+ };
401
+ }
402
+ };
403
+ var isRetryableRecallApiStatus = (status) => status === 429 || status >= 500;
404
+ var sleep = (delayMs) => new Promise((resolve) => {
405
+ setTimeout(resolve, delayMs);
406
+ });
407
+ var buildRecallApiAuthorizationHeader = (apiKey) => {
408
+ const trimmedApiKey = apiKey.trim();
409
+ return trimmedApiKey.toLowerCase().startsWith("token ") ? trimmedApiKey : `Token ${trimmedApiKey}`;
410
+ };
411
+ var extractRecallApiErrorMessage = async (response) => {
412
+ const fallback = `Recall API responded with HTTP ${response.status}`;
413
+ try {
414
+ const body = await response.json();
415
+ return `${fallback}: ${JSON.stringify(body)}`;
416
+ } catch {
417
+ return fallback;
418
+ }
419
+ };
420
+
421
+ // src/logic-functions/recall-api/retrieve-recall-transcript.util.ts
422
+ var retrieveRecallTranscript = async ({
423
+ transcriptId
424
+ }) => {
425
+ const configResult = getRecallApiConfig();
426
+ if (!configResult.success) {
427
+ return { ok: false, status: null, errorMessage: configResult.error };
428
+ }
429
+ const result = await recallBotApiRequest({
430
+ config: configResult.config,
431
+ path: `/transcript/${transcriptId}/`,
432
+ method: "GET"
433
+ });
434
+ if (!result.ok) {
435
+ return result;
436
+ }
437
+ const transcript = extractRecallTranscriptDetails(result.data);
438
+ if (isMalformedRecallTranscriptDetails(transcript)) {
439
+ return {
440
+ ok: false,
441
+ status: result.status,
442
+ errorMessage: "Recall API returned malformed transcript details"
443
+ };
444
+ }
445
+ return { ok: true, transcript };
446
+ };
447
+ var extractRecallTranscriptDetails = (response) => {
448
+ const data = asRecord(response?.data);
449
+ const status = asRecord(response?.status);
450
+ return {
451
+ downloadUrl: getString(data?.download_url),
452
+ statusCode: getString(status?.code),
453
+ statusSubCode: getString(status?.sub_code)
454
+ };
455
+ };
456
+ var isMalformedRecallTranscriptDetails = ({
457
+ downloadUrl,
458
+ statusCode
459
+ }) => (0, import_guards6.isUndefined)(downloadUrl) && (0, import_guards6.isUndefined)(statusCode) || (0, import_guards6.isUndefined)(downloadUrl) && statusCode === "done";
460
+
461
+ // src/logic-functions/flows/download-transcript.util.ts
462
+ var TRANSCRIPT_DOWNLOAD_TIMEOUT_MS = 2e4;
463
+ var downloadTranscript = async ({
464
+ transcriptId
465
+ }) => {
466
+ const retrieveResult = await retrieveRecallTranscript({ transcriptId });
467
+ if (!retrieveResult.ok) {
468
+ return { outcome: "error", errorMessage: retrieveResult.errorMessage };
469
+ }
470
+ const { downloadUrl, statusCode, statusSubCode } = retrieveResult.transcript;
471
+ if (!(0, import_guards7.isUndefined)(downloadUrl)) {
472
+ return downloadTranscriptContent(downloadUrl);
473
+ }
474
+ if (statusCode === "error" || statusCode === "failed") {
475
+ return { outcome: "failed", subCode: statusSubCode ?? null };
476
+ }
477
+ return { outcome: "pending" };
478
+ };
479
+ var downloadTranscriptContent = async (downloadUrl) => {
480
+ try {
481
+ const response = await fetch(downloadUrl, {
482
+ signal: AbortSignal.timeout(TRANSCRIPT_DOWNLOAD_TIMEOUT_MS)
483
+ });
484
+ if (!response.ok) {
485
+ console.warn(
486
+ `[call-recorder] transcript download responded with HTTP ${response.status}`
487
+ );
488
+ return {
489
+ outcome: "error",
490
+ errorMessage: "transcript download failed"
491
+ };
492
+ }
493
+ return { outcome: "filled", content: await response.json() };
494
+ } catch (error) {
495
+ console.warn(
496
+ `[call-recorder] transcript download failed: ${error instanceof Error ? error.message : String(error)}`
497
+ );
498
+ return {
499
+ outcome: "error",
500
+ errorMessage: "transcript download failed"
501
+ };
502
+ }
503
+ };
504
+
505
+ // src/logic-functions/recall-api/extract-recall-bot-convergence.util.ts
506
+ var import_guards9 = __toESM(require_build());
507
+
508
+ // src/logic-functions/domain/map-recall-status-code-to-call-recording-status.util.ts
509
+ var mapRecallStatusCodeToCallRecordingStatus = (statusCode) => {
510
+ switch (statusCode) {
511
+ case "joining_call":
512
+ case "in_waiting_room":
513
+ return "JOINING" /* JOINING */;
514
+ case "in_call_not_recording":
515
+ case "recording_permission_allowed":
516
+ case "in_call_recording":
517
+ return "RECORDING" /* RECORDING */;
518
+ // 'done' stays PROCESSING: COMPLETED is set only after all artifacts are ingested.
519
+ case "call_ended":
520
+ case "analysis_done":
521
+ case "done":
522
+ return "PROCESSING" /* PROCESSING */;
523
+ case "fatal":
524
+ case "analysis_failed":
525
+ case "recording_permission_denied":
526
+ return "FAILED" /* FAILED */;
527
+ default:
528
+ return void 0;
529
+ }
530
+ };
531
+
532
+ // src/logic-functions/recall-api/normalize-recall-timestamp.util.ts
533
+ var import_guards8 = __toESM(require_build());
534
+ var normalizeRecallTimestamp = (value) => {
535
+ if ((0, import_guards8.isUndefined)(value)) {
536
+ return void 0;
537
+ }
538
+ const parsed = new Date(value);
539
+ return Number.isNaN(parsed.getTime()) ? void 0 : parsed.toISOString();
540
+ };
541
+
542
+ // src/logic-functions/recall-api/extract-recall-bot-convergence.util.ts
543
+ var extractRecallBotConvergence = (bot) => {
544
+ const statusChanges = extractStatusChanges(bot);
545
+ const latestStatusChange = getLatestStatusChange(statusChanges);
546
+ const status = mapRecallStatusCodeToCallRecordingStatus(
547
+ latestStatusChange?.code
548
+ );
549
+ const recording = extractFirstRecording(bot);
550
+ return {
551
+ status,
552
+ failureReason: status === "FAILED" /* FAILED */ ? latestStatusChange?.code : void 0,
553
+ startedAt: normalizeRecallTimestamp(
554
+ recording?.startedAt ?? findStatusChangeTimestamp(statusChanges, "in_call_recording")
555
+ ),
556
+ endedAt: normalizeRecallTimestamp(
557
+ recording?.completedAt ?? findStatusChangeTimestamp(statusChanges, "call_ended")
558
+ ),
559
+ externalRecordingId: recording?.id,
560
+ isRecallRecordingDone: !(0, import_guards9.isUndefined)(recording?.completedAt) || statusChanges.some((statusChange) => statusChange.code === "done")
561
+ };
562
+ };
563
+ var extractStatusChanges = (bot) => {
564
+ if (!(0, import_guards9.isArray)(bot.status_changes)) {
565
+ return [];
566
+ }
567
+ return bot.status_changes.flatMap((statusChange) => {
568
+ const code = getString(asRecord(statusChange)?.code);
569
+ if ((0, import_guards9.isUndefined)(code)) {
570
+ return [];
571
+ }
572
+ return [{ code, createdAt: getString(asRecord(statusChange)?.created_at) }];
573
+ });
574
+ };
575
+ var getLatestStatusChange = (statusChanges) => statusChanges.reduce(
576
+ (latestStatusChange, statusChange) => {
577
+ if ((0, import_guards9.isUndefined)(latestStatusChange)) {
578
+ return statusChange;
579
+ }
580
+ const statusChangeTime = getStatusChangeTime(statusChange);
581
+ const latestStatusChangeTime = getStatusChangeTime(latestStatusChange);
582
+ if ((0, import_guards9.isUndefined)(statusChangeTime) && (0, import_guards9.isUndefined)(latestStatusChangeTime)) {
583
+ return statusChange;
584
+ }
585
+ if ((0, import_guards9.isUndefined)(statusChangeTime)) {
586
+ return latestStatusChange;
587
+ }
588
+ if ((0, import_guards9.isUndefined)(latestStatusChangeTime)) {
589
+ return statusChange;
590
+ }
591
+ return statusChangeTime >= latestStatusChangeTime ? statusChange : latestStatusChange;
592
+ },
593
+ void 0
594
+ );
595
+ var getStatusChangeTime = (statusChange) => {
596
+ const normalizedTimestamp = normalizeRecallTimestamp(statusChange.createdAt);
597
+ if ((0, import_guards9.isUndefined)(normalizedTimestamp)) {
598
+ return void 0;
599
+ }
600
+ return new Date(normalizedTimestamp).getTime();
601
+ };
602
+ var extractFirstRecording = (bot) => {
603
+ if (!(0, import_guards9.isArray)(bot.recordings)) {
604
+ return void 0;
605
+ }
606
+ const recording = asRecord(bot.recordings[0]);
607
+ if ((0, import_guards9.isUndefined)(recording)) {
608
+ return void 0;
609
+ }
610
+ return {
611
+ id: getString(recording.id),
612
+ startedAt: getString(recording.started_at),
613
+ completedAt: getString(recording.completed_at)
614
+ };
615
+ };
616
+ var findStatusChangeTimestamp = (statusChanges, code) => statusChanges.find((statusChange) => statusChange.code === code)?.createdAt;
617
+
618
+ // src/logic-functions/recall-api/get-recall-bot.util.ts
619
+ var getRecallBot = async ({
620
+ externalBotId
621
+ }) => {
622
+ const configResult = getRecallApiConfig();
623
+ if (!configResult.success) {
624
+ return { ok: false, status: null, errorMessage: configResult.error };
625
+ }
626
+ const result = await recallBotApiRequest({
627
+ config: configResult.config,
628
+ path: `/bot/${externalBotId}/`,
629
+ method: "GET"
630
+ });
631
+ if (!result.ok) {
632
+ return result;
633
+ }
634
+ const bot = asRecord(result.data);
635
+ if (bot === void 0) {
636
+ return {
637
+ ok: false,
638
+ status: result.status,
639
+ errorMessage: "Recall API returned an empty bot response"
640
+ };
641
+ }
642
+ return { ok: true, bot };
643
+ };
644
+
645
+ // src/logic-functions/flows/ingest-call-recording-media.util.ts
646
+ var import_guards10 = __toESM(require_build());
647
+ import { MetadataApiClient } from "twenty-client-sdk/metadata";
648
+
649
+ // src/constants/call-recording-audio-field-universal-identifier.ts
650
+ var CALL_RECORDING_AUDIO_FIELD_UNIVERSAL_IDENTIFIER = "2eafc2d0-8fec-430c-a939-65ca5fbc0f08";
651
+
652
+ // src/constants/call-recording-video-field-universal-identifier.ts
653
+ var CALL_RECORDING_VIDEO_FIELD_UNIVERSAL_IDENTIFIER = "bb9523d3-457e-4f4b-8c79-27a77afb87da";
654
+
655
+ // src/logic-functions/utils/get-record-at-path.util.ts
656
+ var getRecordAtPath = (record, path) => path.reduce(
657
+ (currentValue, pathPart) => asRecord(currentValue)?.[pathPart],
658
+ record
659
+ );
660
+
661
+ // src/logic-functions/recall-api/extract-recall-media-urls.util.ts
662
+ var extractRecallMediaUrls = (recording) => {
663
+ const mediaShortcuts = asRecord(recording.media_shortcuts);
664
+ return {
665
+ videoUrl: extractArtifactDownloadUrl(mediaShortcuts, "video_mixed"),
666
+ audioUrl: extractArtifactDownloadUrl(mediaShortcuts, "audio_mixed")
667
+ };
668
+ };
669
+ var extractArtifactDownloadUrl = (mediaShortcuts, artifactKey) => getString(getRecordAtPath(mediaShortcuts, [artifactKey, "download_url"])) ?? getString(
670
+ getRecordAtPath(mediaShortcuts, [artifactKey, "data", "download_url"])
671
+ );
672
+
673
+ // src/logic-functions/recall-api/get-recall-recording.util.ts
674
+ var getRecallRecording = async ({
675
+ externalRecordingId
676
+ }) => {
677
+ const configResult = getRecallApiConfig();
678
+ if (!configResult.success) {
679
+ return { ok: false, status: null, errorMessage: configResult.error };
680
+ }
681
+ const result = await recallBotApiRequest({
682
+ config: configResult.config,
683
+ path: `/recording/${externalRecordingId}/`,
684
+ method: "GET"
685
+ });
686
+ if (!result.ok) {
687
+ return result;
688
+ }
689
+ return { ok: true, recording: result.data ?? {} };
690
+ };
691
+
692
+ // src/logic-functions/flows/ingest-call-recording-media.util.ts
693
+ var MEDIA_DOWNLOAD_TIMEOUT_MS = 12e4;
694
+ var ingestCallRecordingMedia = async ({
695
+ callRecordingId,
696
+ externalRecordingId,
697
+ hasAudio,
698
+ hasVideo
699
+ }) => {
700
+ if (hasAudio && hasVideo) {
701
+ return {};
702
+ }
703
+ const recordingResult = await getRecallRecording({ externalRecordingId });
704
+ if (!recordingResult.ok) {
705
+ console.warn(
706
+ `[call-recorder] failed to fetch Recall recording ${externalRecordingId} while ingesting media for call recording ${callRecordingId}: ${recordingResult.errorMessage}`
707
+ );
708
+ return {};
709
+ }
710
+ const mediaUrls = extractRecallMediaUrls(recordingResult.recording);
711
+ const metadataClient = new MetadataApiClient();
712
+ const updateFields = {};
713
+ if (!hasVideo && !(0, import_guards10.isUndefined)(mediaUrls.videoUrl)) {
714
+ const video = await ingestMediaArtifact({
715
+ callRecordingId,
716
+ metadataClient,
717
+ url: mediaUrls.videoUrl,
718
+ fileName: "video.mp4",
719
+ fieldMetadataUniversalIdentifier: CALL_RECORDING_VIDEO_FIELD_UNIVERSAL_IDENTIFIER
720
+ });
721
+ if (!(0, import_guards10.isUndefined)(video)) {
722
+ updateFields.video = video;
723
+ }
724
+ }
725
+ if (!hasAudio && !(0, import_guards10.isUndefined)(mediaUrls.audioUrl)) {
726
+ const audio = await ingestMediaArtifact({
727
+ callRecordingId,
728
+ metadataClient,
729
+ url: mediaUrls.audioUrl,
730
+ fileName: "audio.mp3",
731
+ fieldMetadataUniversalIdentifier: CALL_RECORDING_AUDIO_FIELD_UNIVERSAL_IDENTIFIER
732
+ });
733
+ if (!(0, import_guards10.isUndefined)(audio)) {
734
+ updateFields.audio = audio;
735
+ }
736
+ }
737
+ return updateFields;
738
+ };
739
+ var ingestMediaArtifact = async ({
740
+ callRecordingId,
741
+ metadataClient,
742
+ url,
743
+ fileName,
744
+ fieldMetadataUniversalIdentifier
745
+ }) => {
746
+ try {
747
+ const { buffer, contentType } = await downloadMediaFile(url);
748
+ const uploadedFile = await metadataClient.uploadFile(
749
+ buffer,
750
+ fileName,
751
+ contentType,
752
+ fieldMetadataUniversalIdentifier
753
+ );
754
+ return [{ fileId: uploadedFile.id, label: fileName }];
755
+ } catch (error) {
756
+ console.warn(
757
+ `[call-recorder] failed to ingest ${fileName} for call recording ${callRecordingId}: ${error instanceof Error ? error.message : String(error)}`
758
+ );
759
+ return void 0;
760
+ }
761
+ };
762
+ var downloadMediaFile = async (url) => {
763
+ const response = await fetch(url, {
764
+ signal: AbortSignal.timeout(MEDIA_DOWNLOAD_TIMEOUT_MS)
765
+ });
766
+ if (!response.ok) {
767
+ throw new Error(`download failed with status ${response.status}`);
768
+ }
769
+ return {
770
+ buffer: Buffer.from(await response.arrayBuffer()),
771
+ contentType: response.headers.get("content-type") ?? "application/octet-stream"
772
+ };
773
+ };
774
+
775
+ // src/logic-functions/domain/is-call-recording-status-downgrade.util.ts
776
+ var import_guards11 = __toESM(require_build());
777
+ var CALL_RECORDING_STATUS_PROGRESSION = {
778
+ ["SCHEDULED" /* SCHEDULED */]: 0,
779
+ ["JOINING" /* JOINING */]: 1,
780
+ ["RECORDING" /* RECORDING */]: 2,
781
+ ["PROCESSING" /* PROCESSING */]: 3,
782
+ ["FAILED" /* FAILED */]: 4,
783
+ ["COMPLETED" /* COMPLETED */]: 5
784
+ };
785
+ var getCallRecordingStatusRank = (status) => status in CALL_RECORDING_STATUS_PROGRESSION ? CALL_RECORDING_STATUS_PROGRESSION[status] : void 0;
786
+ var isCallRecordingStatusDowngrade = ({
787
+ fromStatus,
788
+ toStatus
789
+ }) => {
790
+ const fromRank = (0, import_guards11.isUndefined)(fromStatus) ? void 0 : getCallRecordingStatusRank(fromStatus);
791
+ const toRank = getCallRecordingStatusRank(toStatus);
792
+ if ((0, import_guards11.isUndefined)(fromRank) || (0, import_guards11.isUndefined)(toRank)) {
793
+ return false;
794
+ }
795
+ return toRank < fromRank;
796
+ };
797
+
798
+ // src/logic-functions/domain/is-recall-recording-done-signal.util.ts
799
+ var isRecallRecordingDoneSignal = ({
800
+ event,
801
+ statusCode
802
+ }) => {
803
+ return event === "recording.done" || event === "recording.failed" || statusCode === "done";
804
+ };
805
+
806
+ // src/logic-functions/recall-api/parse-recall-webhook-event.util.ts
807
+ var import_guards12 = __toESM(require_build());
808
+
809
+ // src/logic-functions/recall-api/get-recall-webhook-bot-metadata.util.ts
810
+ var getRecallWebhookBotMetadata = (body) => {
811
+ const data = asRecord(body.data);
812
+ const bot = asRecord(body.bot);
813
+ return asRecord(bot?.metadata) ?? asRecord(getRecordAtPath(data, ["bot", "metadata"])) ?? asRecord(getRecordAtPath(data, ["recording", "metadata"])) ?? asRecord(data?.metadata);
814
+ };
815
+
816
+ // src/logic-functions/recall-api/parse-recall-webhook-event.util.ts
817
+ var parseRecallWebhookEvent = (body) => {
818
+ const event = getString(body.event) ?? getString(body.type);
819
+ if ((0, import_guards12.isUndefined)(event)) {
820
+ return void 0;
821
+ }
822
+ const data = asRecord(body.data);
823
+ const bot = asRecord(body.bot);
824
+ return {
825
+ event,
826
+ statusCode: getString(getRecordAtPath(data, ["status", "code"])) ?? getString(getRecordAtPath(data, ["data", "code"])) ?? getString(getRecordAtPath(bot, ["status", "code"])) ?? getStatusCodeFromEventName(event),
827
+ statusTimestamp: normalizeRecallTimestamp(
828
+ getString(getRecordAtPath(data, ["status", "created_at"])) ?? getString(getRecordAtPath(data, ["data", "updated_at"])) ?? getString(getRecordAtPath(bot, ["status", "created_at"]))
829
+ ),
830
+ externalBotId: getString(data?.bot_id) ?? getString(getRecordAtPath(data, ["bot", "id"])) ?? getString(getRecordAtPath(data, ["recording", "bot_id"])) ?? getString(getRecordAtPath(data, ["recording", "bot", "id"])) ?? getString(bot?.id),
831
+ externalRecordingId: getString(getRecordAtPath(data, ["status", "recording_id"])) ?? getString(getRecordAtPath(data, ["recording", "id"])) ?? getString(data?.recording_id),
832
+ callRecordingIdFromMetadata: getString(
833
+ getRecallWebhookBotMetadata(body)?.twentyCallRecordingId
834
+ ),
835
+ recordingStartedAt: normalizeRecallTimestamp(
836
+ getString(getRecordAtPath(data, ["recording", "started_at"]))
837
+ ),
838
+ recordingEndedAt: normalizeRecallTimestamp(
839
+ getString(getRecordAtPath(data, ["recording", "completed_at"]))
840
+ ),
841
+ transcriptId: getString(getRecordAtPath(data, ["transcript", "id"])),
842
+ transcriptFailureSubCode: getString(
843
+ getRecordAtPath(data, ["status", "sub_code"])
844
+ )
845
+ };
846
+ };
847
+ var getStatusCodeFromEventName = (event) => {
848
+ if (!event.startsWith("bot.")) {
849
+ return void 0;
850
+ }
851
+ const statusCode = event.slice("bot.".length);
852
+ return statusCode === "status_change" ? void 0 : statusCode;
853
+ };
854
+
855
+ // src/logic-functions/domain/parse-transcript-marker.util.ts
856
+ var import_guards13 = __toESM(require_build());
857
+ var parseTranscriptMarker = (transcript) => {
858
+ const candidate = asRecord(transcript);
859
+ if ((0, import_guards13.isUndefined)(candidate)) {
860
+ return void 0;
861
+ }
862
+ if (candidate.status !== "PENDING" && candidate.status !== "FAILED") {
863
+ return void 0;
864
+ }
865
+ return {
866
+ recallTranscriptId: (0, import_guards13.isString)(candidate.recallTranscriptId) ? candidate.recallTranscriptId : null,
867
+ status: candidate.status,
868
+ ...(0, import_guards13.isString)(candidate.requestedAt) ? { requestedAt: candidate.requestedAt } : {},
869
+ ...(0, import_guards13.isString)(candidate.subCode) ? { subCode: candidate.subCode } : {}
870
+ };
871
+ };
872
+
873
+ // src/logic-functions/constants/non-terminal-call-recording-statuses.ts
874
+ var NON_TERMINAL_CALL_RECORDING_STATUSES = [
875
+ "SCHEDULED" /* SCHEDULED */,
876
+ "JOINING" /* JOINING */,
877
+ "RECORDING" /* RECORDING */,
878
+ "PROCESSING" /* PROCESSING */
879
+ ];
880
+
881
+ // src/logic-functions/data/complete-call-recording-ingestion.util.ts
882
+ var completeCallRecordingIngestion = async (client, { id }) => {
883
+ const result = await client.mutation({
884
+ updateCallRecordings: {
885
+ __args: {
886
+ filter: {
887
+ id: { eq: id },
888
+ status: { in: NON_TERMINAL_CALL_RECORDING_STATUSES }
889
+ },
890
+ data: { status: "COMPLETED" /* COMPLETED */ }
891
+ },
892
+ id: true
893
+ }
894
+ });
895
+ return (result.updateCallRecordings ?? []).length > 0;
896
+ };
897
+
898
+ // src/logic-functions/flows/charge-completed-call-recording.util.ts
899
+ var import_guards15 = __toESM(require_build());
900
+
901
+ // node_modules/twenty-sdk/dist/billing/index.mjs
902
+ var e = "TWENTY_API_URL";
903
+ var t = "TWENTY_APP_ACCESS_TOKEN";
904
+ var n = 5e3;
905
+ var r = async ({ creditsUsedMicro: r2, operationType: i, quantity: a = 1, resourceContext: o }) => {
906
+ let s = process.env[e], c = process.env[t];
907
+ if (!(!s || !c)) try {
908
+ let e2 = await fetch(`${s.replace(/\/$/, "")}/app/billing/charge`, {
909
+ method: "POST",
910
+ headers: {
911
+ Authorization: `Bearer ${c}`,
912
+ "Content-Type": "application/json"
913
+ },
914
+ body: JSON.stringify({
915
+ creditsUsedMicro: r2,
916
+ quantity: a,
917
+ operationType: i,
918
+ resourceContext: o
919
+ }),
920
+ signal: AbortSignal.timeout(n)
921
+ });
922
+ if (!e2.ok) {
923
+ let t2 = await e2.text().catch(() => "");
924
+ console.error(`chargeCredits: ${e2.status} ${e2.statusText}: ${t2}`);
925
+ }
926
+ } catch (e2) {
927
+ console.error(`chargeCredits: ${e2 instanceof Error ? e2.message : String(e2)}`);
928
+ }
929
+ };
930
+
931
+ // src/logic-functions/domain/compute-call-recording-charge.util.ts
932
+ var import_guards14 = __toESM(require_build());
933
+
934
+ // src/logic-functions/constants/call-recording-micro-credits-per-hour.ts
935
+ var CALL_RECORDING_MICRO_CREDITS_PER_HOUR = 1e6;
936
+
937
+ // src/logic-functions/constants/milliseconds-per-minute.ts
938
+ var MILLISECONDS_PER_MINUTE = 6e4;
939
+
940
+ // src/logic-functions/domain/compute-call-recording-charge.util.ts
941
+ var MILLISECONDS_PER_HOUR = 36e5;
942
+ var computeCallRecordingCharge = ({
943
+ startedAt,
944
+ endedAt
945
+ }) => {
946
+ if ((0, import_guards14.isUndefined)(startedAt) || (0, import_guards14.isUndefined)(endedAt)) {
947
+ return void 0;
948
+ }
949
+ const durationMilliseconds = new Date(endedAt).getTime() - new Date(startedAt).getTime();
950
+ if (!Number.isFinite(durationMilliseconds) || durationMilliseconds <= 0) {
951
+ return void 0;
952
+ }
953
+ return {
954
+ creditsUsedMicro: Math.round(
955
+ durationMilliseconds / MILLISECONDS_PER_HOUR * CALL_RECORDING_MICRO_CREDITS_PER_HOUR
956
+ ),
957
+ quantityMinutes: Math.max(
958
+ 1,
959
+ Math.round(durationMilliseconds / MILLISECONDS_PER_MINUTE)
960
+ )
961
+ };
962
+ };
963
+
964
+ // src/logic-functions/flows/charge-completed-call-recording.util.ts
965
+ var chargeCompletedCallRecording = async ({
966
+ callRecordingId,
967
+ startedAt,
968
+ endedAt
969
+ }) => {
970
+ const charge = computeCallRecordingCharge({ startedAt, endedAt });
971
+ if ((0, import_guards15.isUndefined)(charge)) {
972
+ console.warn(
973
+ `[call-recorder] call recording ${callRecordingId} completed without usable recording timestamps; it will not be billed`
974
+ );
975
+ return;
976
+ }
977
+ await r({
978
+ creditsUsedMicro: charge.creditsUsedMicro,
979
+ quantity: charge.quantityMinutes,
980
+ operationType: "CALL_RECORDING",
981
+ resourceContext: "recall"
982
+ });
983
+ };
984
+
985
+ // src/logic-functions/flows/complete-and-charge-call-recording.util.ts
986
+ var completeAndChargeCallRecording = async (client, {
987
+ id,
988
+ startedAt,
989
+ endedAt
990
+ }) => {
991
+ const claimed = await completeCallRecordingIngestion(client, { id });
992
+ if (claimed) {
993
+ await chargeCompletedCallRecording({
994
+ callRecordingId: id,
995
+ startedAt,
996
+ endedAt
997
+ });
998
+ }
999
+ return claimed;
1000
+ };
1001
+
1002
+ // src/logic-functions/domain/is-call-recording-ingestion-complete.util.ts
1003
+ var import_guards16 = __toESM(require_build());
1004
+ var isCallRecordingIngestionComplete = ({
1005
+ transcript,
1006
+ audio,
1007
+ video
1008
+ }) => !(0, import_guards16.isNull)(transcript) && !(0, import_guards16.isUndefined)(transcript) && (0, import_guards16.isUndefined)(parseTranscriptMarker(transcript)) && (0, import_guards16.isNonEmptyArray)(audio) && (0, import_guards16.isNonEmptyArray)(video);
1009
+
1010
+ // src/logic-functions/domain/should-complete-call-recording-ingestion.util.ts
1011
+ var shouldCompleteCallRecordingIngestion = ({
1012
+ current,
1013
+ updateData
1014
+ }) => current.status !== "COMPLETED" /* COMPLETED */ && current.status !== "FAILED" /* FAILED */ && updateData.status !== "FAILED" /* FAILED */ && computeCallRecordingCharge({
1015
+ startedAt: updateData.startedAt ?? current.startedAt,
1016
+ endedAt: updateData.endedAt ?? current.endedAt
1017
+ }) !== void 0 && isCallRecordingIngestionComplete({
1018
+ transcript: updateData.transcript ?? current.transcript,
1019
+ audio: updateData.audio ?? current.audio,
1020
+ video: updateData.video ?? current.video
1021
+ });
1022
+
1023
+ // src/logic-functions/data/update-call-recording.util.ts
1024
+ var updateCallRecording = async (client, {
1025
+ id,
1026
+ data
1027
+ }) => {
1028
+ await client.mutation({
1029
+ updateCallRecording: {
1030
+ __args: {
1031
+ id,
1032
+ data
1033
+ },
1034
+ id: true
1035
+ }
1036
+ });
1037
+ };
1038
+
1039
+ // src/logic-functions/flows/persist-call-recording-progress.util.ts
1040
+ var persistCallRecordingProgress = async (client, {
1041
+ id,
1042
+ current,
1043
+ updateData
1044
+ }) => {
1045
+ const completesIngestion = shouldCompleteCallRecordingIngestion({
1046
+ current,
1047
+ updateData
1048
+ });
1049
+ if (!completesIngestion) {
1050
+ await updateCallRecording(client, { id, data: updateData });
1051
+ return { completesIngestion: false };
1052
+ }
1053
+ const nonStatusUpdate = { ...updateData };
1054
+ delete nonStatusUpdate.status;
1055
+ delete nonStatusUpdate.callRecorderFailureReason;
1056
+ if (Object.keys(nonStatusUpdate).length > 0) {
1057
+ await updateCallRecording(client, { id, data: nonStatusUpdate });
1058
+ }
1059
+ await completeAndChargeCallRecording(client, {
1060
+ id,
1061
+ startedAt: updateData.startedAt ?? current.startedAt,
1062
+ endedAt: updateData.endedAt ?? current.endedAt
1063
+ });
1064
+ return { completesIngestion: true };
1065
+ };
1066
+
1067
+ // src/logic-functions/flows/reconcile-call-recording-transcript-artifact.util.ts
1068
+ var import_guards19 = __toESM(require_build());
1069
+
1070
+ // src/logic-functions/domain/build-pending-transcript-marker.util.ts
1071
+ var buildPendingTranscriptMarker = ({
1072
+ recallTranscriptId,
1073
+ requestedAt
1074
+ }) => ({
1075
+ recallTranscriptId,
1076
+ status: "PENDING",
1077
+ requestedAt
1078
+ });
1079
+
1080
+ // src/logic-functions/recall-api/create-async-recall-transcript.util.ts
1081
+ var import_guards17 = __toESM(require_build());
1082
+ var createAsyncRecallTranscript = async ({
1083
+ externalRecordingId
1084
+ }) => {
1085
+ const configResult = getRecallApiConfig();
1086
+ if (!configResult.success) {
1087
+ return { ok: false, status: null, errorMessage: configResult.error };
1088
+ }
1089
+ const result = await recallBotApiRequest({
1090
+ config: configResult.config,
1091
+ path: `/recording/${externalRecordingId}/create_transcript/`,
1092
+ method: "POST",
1093
+ body: {
1094
+ provider: { recallai_async: { language_code: "auto" } },
1095
+ diarization: { use_separate_streams_when_available: true }
1096
+ },
1097
+ maxAttempts: 1
1098
+ });
1099
+ if (!result.ok) {
1100
+ return result;
1101
+ }
1102
+ if (!(0, import_guards17.isString)(result.data?.id)) {
1103
+ return {
1104
+ ok: false,
1105
+ status: null,
1106
+ errorMessage: "Recall API created a transcript but the response did not include a transcript id"
1107
+ };
1108
+ }
1109
+ return { ok: true, transcriptId: result.data.id };
1110
+ };
1111
+
1112
+ // src/logic-functions/recall-api/list-recall-transcripts.util.ts
1113
+ var import_guards18 = __toESM(require_build());
1114
+ var RECALL_TRANSCRIPT_LIST_MAX_PAGES = 10;
1115
+ var listRecallTranscripts = async ({
1116
+ externalRecordingId
1117
+ }) => {
1118
+ const configResult = getRecallApiConfig();
1119
+ if (!configResult.success) {
1120
+ return { ok: false, status: null, errorMessage: configResult.error };
1121
+ }
1122
+ const transcripts = [];
1123
+ let path = buildListRecallTranscriptsPath({
1124
+ externalRecordingId
1125
+ });
1126
+ for (let pageIndex = 0; !(0, import_guards18.isUndefined)(path) && pageIndex < RECALL_TRANSCRIPT_LIST_MAX_PAGES; pageIndex++) {
1127
+ const result = await recallBotApiRequest({
1128
+ config: configResult.config,
1129
+ path,
1130
+ method: "GET"
1131
+ });
1132
+ if (!result.ok) {
1133
+ return result;
1134
+ }
1135
+ const pageTranscripts = extractRecallTranscriptSummaries(result.data);
1136
+ if ((0, import_guards18.isUndefined)(pageTranscripts)) {
1137
+ return {
1138
+ ok: false,
1139
+ status: result.status,
1140
+ errorMessage: "Recall API returned malformed transcript list"
1141
+ };
1142
+ }
1143
+ transcripts.push(...pageTranscripts);
1144
+ path = extractNextPath(result.data, configResult.config.baseUrl);
1145
+ }
1146
+ if (!(0, import_guards18.isUndefined)(path)) {
1147
+ return {
1148
+ ok: false,
1149
+ status: null,
1150
+ errorMessage: `Recall transcript list exceeded ${RECALL_TRANSCRIPT_LIST_MAX_PAGES} pages`
1151
+ };
1152
+ }
1153
+ return { ok: true, transcripts };
1154
+ };
1155
+ var buildListRecallTranscriptsPath = ({
1156
+ externalRecordingId
1157
+ }) => {
1158
+ const searchParams = new URLSearchParams({
1159
+ recording_id: externalRecordingId
1160
+ });
1161
+ return `/transcript/?${searchParams.toString()}`;
1162
+ };
1163
+ var extractRecallTranscriptSummaries = (response) => {
1164
+ if (!(0, import_guards18.isArray)(response?.results)) {
1165
+ return void 0;
1166
+ }
1167
+ const transcripts = [];
1168
+ for (const result of response.results) {
1169
+ const transcript = extractRecallTranscriptSummary(result);
1170
+ if ((0, import_guards18.isUndefined)(transcript)) {
1171
+ return void 0;
1172
+ }
1173
+ transcripts.push(transcript);
1174
+ }
1175
+ return transcripts;
1176
+ };
1177
+ var extractRecallTranscriptSummary = (transcript) => {
1178
+ const transcriptRecord = asRecord(transcript);
1179
+ const transcriptId = getString(transcriptRecord?.id);
1180
+ if ((0, import_guards18.isUndefined)(transcriptRecord) || (0, import_guards18.isUndefined)(transcriptId)) {
1181
+ return void 0;
1182
+ }
1183
+ const status = asRecord(transcriptRecord.status);
1184
+ return {
1185
+ id: transcriptId,
1186
+ statusCode: getString(status?.code),
1187
+ statusSubCode: getString(status?.sub_code)
1188
+ };
1189
+ };
1190
+ var extractNextPath = (response, baseUrl) => {
1191
+ const nextPage = getString(response?.next);
1192
+ if ((0, import_guards18.isUndefined)(nextPage) || !nextPage.startsWith(baseUrl)) {
1193
+ return void 0;
1194
+ }
1195
+ return nextPage.slice(baseUrl.length);
1196
+ };
1197
+
1198
+ // src/logic-functions/flows/reconcile-call-recording-transcript-artifact.util.ts
1199
+ var reconcileCallRecordingTranscriptArtifact = async ({
1200
+ callRecordingId,
1201
+ currentStatus,
1202
+ externalRecordingId,
1203
+ requestedAt,
1204
+ transcript
1205
+ }) => {
1206
+ const existingTranscriptMarker = parseTranscriptMarker(transcript);
1207
+ if (!(0, import_guards19.isNull)(transcript) && !(0, import_guards19.isUndefined)(transcript) && (0, import_guards19.isUndefined)(existingTranscriptMarker)) {
1208
+ return buildEmptyTranscriptArtifactResult();
1209
+ }
1210
+ if (existingTranscriptMarker?.status === "FAILED") {
1211
+ return buildEmptyTranscriptArtifactResult();
1212
+ }
1213
+ const listResult = await listRecallTranscripts({ externalRecordingId });
1214
+ if (!listResult.ok) {
1215
+ console.warn(
1216
+ `[call-recorder] failed to list Recall transcripts for recording ${externalRecordingId}: ${listResult.errorMessage}`
1217
+ );
1218
+ return buildEmptyTranscriptArtifactResult();
1219
+ }
1220
+ const transcriptArtifact = selectRecallTranscriptArtifact(
1221
+ listResult.transcripts
1222
+ );
1223
+ const pendingTranscriptMarkerRecallTranscriptId = existingTranscriptMarker?.status === "PENDING" ? existingTranscriptMarker.recallTranscriptId ?? void 0 : void 0;
1224
+ const transcriptIdToDownload = transcriptArtifact?.id ?? pendingTranscriptMarkerRecallTranscriptId;
1225
+ if ((0, import_guards19.isUndefined)(transcriptArtifact) && (0, import_guards19.isUndefined)(pendingTranscriptMarkerRecallTranscriptId)) {
1226
+ const createResult = await createAsyncRecallTranscript({
1227
+ externalRecordingId
1228
+ });
1229
+ if (!createResult.ok) {
1230
+ console.warn(
1231
+ `[call-recorder] failed to request transcript for Recall recording ${externalRecordingId}: ${createResult.errorMessage}`
1232
+ );
1233
+ return buildEmptyTranscriptArtifactResult();
1234
+ }
1235
+ return {
1236
+ updateData: {
1237
+ transcript: buildPendingTranscriptMarker({
1238
+ recallTranscriptId: createResult.transcriptId,
1239
+ requestedAt
1240
+ })
1241
+ },
1242
+ requestedTranscript: true
1243
+ };
1244
+ }
1245
+ if (!(0, import_guards19.isUndefined)(transcriptArtifact) && (transcriptArtifact.statusCode === "failed" || transcriptArtifact.statusCode === "error")) {
1246
+ return {
1247
+ updateData: buildTranscriptFailureUpdate({
1248
+ currentStatus,
1249
+ transcriptId: transcriptArtifact.id,
1250
+ subCode: transcriptArtifact.statusSubCode ?? null
1251
+ }),
1252
+ requestedTranscript: false
1253
+ };
1254
+ }
1255
+ if (!(0, import_guards19.isUndefined)(transcriptArtifact) && transcriptArtifact.statusCode !== "done") {
1256
+ return buildEmptyTranscriptArtifactResult();
1257
+ }
1258
+ if ((0, import_guards19.isUndefined)(transcriptIdToDownload)) {
1259
+ return buildEmptyTranscriptArtifactResult();
1260
+ }
1261
+ const downloadResult = await downloadTranscript({
1262
+ transcriptId: transcriptIdToDownload
1263
+ });
1264
+ if (downloadResult.outcome === "filled") {
1265
+ return {
1266
+ updateData: {
1267
+ transcript: downloadResult.content
1268
+ },
1269
+ requestedTranscript: false
1270
+ };
1271
+ }
1272
+ if (downloadResult.outcome === "failed") {
1273
+ return {
1274
+ updateData: buildTranscriptFailureUpdate({
1275
+ currentStatus,
1276
+ transcriptId: transcriptIdToDownload,
1277
+ subCode: downloadResult.subCode
1278
+ }),
1279
+ requestedTranscript: false
1280
+ };
1281
+ }
1282
+ if (downloadResult.outcome === "error") {
1283
+ console.warn(
1284
+ `[call-recorder] could not fill transcript for call recording ${callRecordingId}: ${downloadResult.errorMessage}`
1285
+ );
1286
+ }
1287
+ return buildEmptyTranscriptArtifactResult();
1288
+ };
1289
+ var buildEmptyTranscriptArtifactResult = () => ({
1290
+ updateData: {},
1291
+ requestedTranscript: false
1292
+ });
1293
+ var selectRecallTranscriptArtifact = (transcripts) => transcripts.find((transcript) => transcript.statusCode !== "deleted");
1294
+ var buildTranscriptFailureUpdate = ({
1295
+ currentStatus,
1296
+ transcriptId,
1297
+ subCode
1298
+ }) => ({
1299
+ transcript: buildFailedTranscriptMarker({
1300
+ recallTranscriptId: transcriptId,
1301
+ subCode
1302
+ }),
1303
+ callRecorderFailureReason: buildTranscriptFailureReason(subCode),
1304
+ ...isCallRecordingStatusDowngrade({
1305
+ fromStatus: currentStatus,
1306
+ toStatus: "FAILED" /* FAILED */
1307
+ }) ? {} : { status: "FAILED" /* FAILED */ }
1308
+ });
1309
+
1310
+ // src/logic-functions/flows/handle-recall-webhook.util.ts
1311
+ var handleRecallWebhook = async ({
1312
+ client,
1313
+ body
1314
+ }) => {
1315
+ const webhookEvent = parseRecallWebhookEvent(body);
1316
+ if ((0, import_guards20.isUndefined)(webhookEvent)) {
1317
+ return {
1318
+ status: "skipped",
1319
+ event: null,
1320
+ reason: "missing event type"
1321
+ };
1322
+ }
1323
+ const { event } = webhookEvent;
1324
+ if (event === "transcript.done" || event === "transcript.failed") {
1325
+ return handleRecallTranscriptEvent({ client, webhookEvent, event });
1326
+ }
1327
+ return handleRecallStatusEvent({ client, webhookEvent });
1328
+ };
1329
+ var handleRecallStatusEvent = async ({
1330
+ client,
1331
+ webhookEvent
1332
+ }) => {
1333
+ const { event, statusCode } = webhookEvent;
1334
+ const callRecordingStatus = mapRecallEventToCallRecordingStatus({
1335
+ event,
1336
+ statusCode
1337
+ });
1338
+ if ((0, import_guards20.isUndefined)(callRecordingStatus)) {
1339
+ return {
1340
+ status: "skipped",
1341
+ event,
1342
+ reason: `unsupported Recall event status ${statusCode ?? event}`
1343
+ };
1344
+ }
1345
+ const callRecording = await findMatchingCallRecording({
1346
+ client,
1347
+ webhookEvent
1348
+ });
1349
+ if ((0, import_guards20.isUndefined)(callRecording)) {
1350
+ return {
1351
+ status: "skipped",
1352
+ event,
1353
+ reason: "no matching call recording"
1354
+ };
1355
+ }
1356
+ if (isCallRecordingStatusDowngrade({
1357
+ fromStatus: callRecording.status,
1358
+ toStatus: callRecordingStatus
1359
+ })) {
1360
+ return {
1361
+ status: "skipped",
1362
+ event,
1363
+ reason: `stale status event (${callRecording.status} -> ${callRecordingStatus})`
1364
+ };
1365
+ }
1366
+ const updateData = {
1367
+ ...(0, import_guards20.isUndefined)(webhookEvent.externalBotId) ? {} : { externalBotId: webhookEvent.externalBotId },
1368
+ ...buildExternalRecordingIdUpdate(webhookEvent),
1369
+ ...buildCallRecordingStatusUpdate({
1370
+ reason: getRecallWebhookFailureReason(webhookEvent),
1371
+ status: callRecordingStatus
1372
+ }),
1373
+ ...buildRecordingTimestampsUpdate({ webhookEvent, callRecording })
1374
+ };
1375
+ if (isRecallRecordingDoneSignal({ event, statusCode })) {
1376
+ const externalRecordingIdResolution = await resolveExternalRecordingId({
1377
+ callRecording,
1378
+ webhookEvent
1379
+ });
1380
+ Object.assign(
1381
+ updateData,
1382
+ await buildTranscriptArtifactUpdate({
1383
+ callRecording,
1384
+ externalRecordingId: externalRecordingIdResolution.externalRecordingId
1385
+ })
1386
+ );
1387
+ Object.assign(
1388
+ updateData,
1389
+ await buildMediaIngestionUpdate({
1390
+ callRecording,
1391
+ externalRecordingId: externalRecordingIdResolution.externalRecordingId
1392
+ })
1393
+ );
1394
+ const terminalArtifactGateFailureUpdate = buildTerminalArtifactGateFailureUpdate({
1395
+ callRecording,
1396
+ providerLookupFailed: externalRecordingIdResolution.providerLookupFailed,
1397
+ updateData,
1398
+ webhookEvent
1399
+ });
1400
+ if (!(0, import_guards20.isUndefined)(terminalArtifactGateFailureUpdate)) {
1401
+ Object.assign(updateData, terminalArtifactGateFailureUpdate);
1402
+ }
1403
+ }
1404
+ const { completesIngestion } = await persistCallRecordingProgress(client, {
1405
+ id: callRecording.id,
1406
+ current: callRecording,
1407
+ updateData
1408
+ });
1409
+ return {
1410
+ status: "updated",
1411
+ event,
1412
+ callRecordingId: callRecording.id,
1413
+ callRecordingStatus: completesIngestion ? "COMPLETED" /* COMPLETED */ : updateData.status ?? callRecordingStatus
1414
+ };
1415
+ };
1416
+ var findMatchingCallRecording = async ({
1417
+ client,
1418
+ webhookEvent
1419
+ }) => {
1420
+ if (!(0, import_guards20.isUndefined)(webhookEvent.callRecordingIdFromMetadata)) {
1421
+ return findCallRecordingByFilter(client, {
1422
+ id: { eq: webhookEvent.callRecordingIdFromMetadata }
1423
+ });
1424
+ }
1425
+ if ((0, import_guards20.isUndefined)(webhookEvent.externalBotId)) {
1426
+ return void 0;
1427
+ }
1428
+ return findCallRecordingByFilter(client, {
1429
+ externalBotId: { eq: webhookEvent.externalBotId }
1430
+ });
1431
+ };
1432
+ var findCallRecordingByFilter = async (client, filter) => {
1433
+ const queryResult = await client.query({
1434
+ callRecordings: {
1435
+ __args: {
1436
+ filter,
1437
+ first: 1
1438
+ },
1439
+ edges: {
1440
+ node: {
1441
+ id: true,
1442
+ status: true,
1443
+ startedAt: true,
1444
+ endedAt: true,
1445
+ externalRecordingId: true,
1446
+ transcript: true,
1447
+ audio: { fileId: true },
1448
+ video: { fileId: true }
1449
+ }
1450
+ }
1451
+ }
1452
+ });
1453
+ const node = queryResult.callRecordings?.edges?.[0]?.node;
1454
+ if ((0, import_guards20.isUndefined)(node) || (0, import_guards20.isNull)(node)) {
1455
+ return void 0;
1456
+ }
1457
+ return {
1458
+ id: node.id,
1459
+ status: getString(node.status),
1460
+ startedAt: getString(node.startedAt),
1461
+ endedAt: getString(node.endedAt),
1462
+ externalRecordingId: getString(node.externalRecordingId),
1463
+ transcript: node.transcript ?? void 0,
1464
+ audio: node.audio ?? void 0,
1465
+ video: node.video ?? void 0
1466
+ };
1467
+ };
1468
+ var mapRecallEventToCallRecordingStatus = ({
1469
+ event,
1470
+ statusCode
1471
+ }) => {
1472
+ if (event === "recording.done") {
1473
+ return "PROCESSING" /* PROCESSING */;
1474
+ }
1475
+ if (event === "recording.failed") {
1476
+ return "FAILED" /* FAILED */;
1477
+ }
1478
+ return mapRecallStatusCodeToCallRecordingStatus(statusCode);
1479
+ };
1480
+ var buildRecordingTimestampsUpdate = ({
1481
+ webhookEvent,
1482
+ callRecording
1483
+ }) => {
1484
+ const { event, statusCode, statusTimestamp } = webhookEvent;
1485
+ const impliesRecordingStarted = statusCode === "in_call_recording";
1486
+ const impliesRecordingEnded = event === "recording.done" || statusCode === "call_ended" || statusCode === "done";
1487
+ const startedAt = webhookEvent.recordingStartedAt ?? (impliesRecordingStarted ? statusTimestamp : void 0);
1488
+ const endedAt = webhookEvent.recordingEndedAt ?? (impliesRecordingEnded ? statusTimestamp : void 0);
1489
+ return {
1490
+ ...!(0, import_guards20.isUndefined)(startedAt) && (0, import_guards20.isUndefined)(callRecording.startedAt) ? { startedAt } : {},
1491
+ ...!(0, import_guards20.isUndefined)(endedAt) && (0, import_guards20.isUndefined)(callRecording.endedAt) ? { endedAt } : {}
1492
+ };
1493
+ };
1494
+ var buildExternalRecordingIdUpdate = (webhookEvent) => (0, import_guards20.isUndefined)(webhookEvent.externalRecordingId) ? {} : { externalRecordingId: webhookEvent.externalRecordingId };
1495
+ var buildCallRecordingStatusUpdate = ({
1496
+ reason,
1497
+ status
1498
+ }) => {
1499
+ if (status === "FAILED" /* FAILED */) {
1500
+ return { status, callRecorderFailureReason: reason };
1501
+ }
1502
+ return { status };
1503
+ };
1504
+ var buildTerminalArtifactGateFailureUpdate = ({
1505
+ callRecording,
1506
+ providerLookupFailed,
1507
+ updateData,
1508
+ webhookEvent
1509
+ }) => {
1510
+ if (updateData.status === "FAILED" /* FAILED */) {
1511
+ return (0, import_guards20.isUndefined)(updateData.callRecorderFailureReason) ? {
1512
+ status: "FAILED" /* FAILED */,
1513
+ callRecorderFailureReason: getRecallWebhookFailureReason(webhookEvent)
1514
+ } : void 0;
1515
+ }
1516
+ if (providerLookupFailed || hasRecordingArtifactPath({ callRecording, updateData })) {
1517
+ return void 0;
1518
+ }
1519
+ return {
1520
+ status: "FAILED" /* FAILED */,
1521
+ callRecorderFailureReason: "recording_artifacts_unavailable"
1522
+ };
1523
+ };
1524
+ var getRecallWebhookFailureReason = ({
1525
+ event,
1526
+ statusCode
1527
+ }) => statusCode ?? event;
1528
+ var hasRecordingArtifactPath = ({
1529
+ callRecording,
1530
+ updateData
1531
+ }) => {
1532
+ return !(0, import_guards20.isUndefined)(
1533
+ updateData.externalRecordingId ?? callRecording.externalRecordingId
1534
+ ) || (0, import_guards20.isNonEmptyArray)(updateData.audio ?? callRecording.audio) || (0, import_guards20.isNonEmptyArray)(updateData.video ?? callRecording.video) || hasReachableTranscript(updateData.transcript ?? callRecording.transcript);
1535
+ };
1536
+ var hasReachableTranscript = (transcript) => {
1537
+ if ((0, import_guards20.isNull)(transcript) || (0, import_guards20.isUndefined)(transcript)) {
1538
+ return false;
1539
+ }
1540
+ const marker = parseTranscriptMarker(transcript);
1541
+ return (0, import_guards20.isUndefined)(marker) || marker.status === "PENDING";
1542
+ };
1543
+ var isTranscriptUnset = (callRecording) => (0, import_guards20.isUndefined)(callRecording.transcript);
1544
+ var buildMediaIngestionUpdate = async ({
1545
+ callRecording,
1546
+ externalRecordingId
1547
+ }) => {
1548
+ const hasAudio = (0, import_guards20.isNonEmptyArray)(callRecording.audio);
1549
+ const hasVideo = (0, import_guards20.isNonEmptyArray)(callRecording.video);
1550
+ if (hasAudio && hasVideo) {
1551
+ return {};
1552
+ }
1553
+ if ((0, import_guards20.isUndefined)(externalRecordingId)) {
1554
+ console.warn(
1555
+ `[call-recorder] cannot ingest media for call recording ${callRecording.id}: no Recall recording id available`
1556
+ );
1557
+ return {};
1558
+ }
1559
+ return ingestCallRecordingMedia({
1560
+ callRecordingId: callRecording.id,
1561
+ externalRecordingId,
1562
+ hasAudio,
1563
+ hasVideo
1564
+ });
1565
+ };
1566
+ var buildTranscriptArtifactUpdate = async ({
1567
+ callRecording,
1568
+ externalRecordingId
1569
+ }) => {
1570
+ if ((0, import_guards20.isUndefined)(externalRecordingId)) {
1571
+ console.warn(
1572
+ `[call-recorder] cannot reconcile transcript for call recording ${callRecording.id}: no Recall recording id available`
1573
+ );
1574
+ return {};
1575
+ }
1576
+ const transcriptArtifactResult = await reconcileCallRecordingTranscriptArtifact({
1577
+ callRecordingId: callRecording.id,
1578
+ currentStatus: callRecording.status,
1579
+ externalRecordingId,
1580
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
1581
+ transcript: callRecording.transcript
1582
+ });
1583
+ return {
1584
+ ...(0, import_guards20.isUndefined)(callRecording.externalRecordingId) ? { externalRecordingId } : {},
1585
+ ...transcriptArtifactResult.updateData
1586
+ };
1587
+ };
1588
+ var resolveExternalRecordingId = async ({
1589
+ callRecording,
1590
+ webhookEvent
1591
+ }) => {
1592
+ const externalRecordingId = webhookEvent.externalRecordingId ?? callRecording.externalRecordingId;
1593
+ if (!(0, import_guards20.isUndefined)(externalRecordingId)) {
1594
+ return { externalRecordingId, providerLookupFailed: false };
1595
+ }
1596
+ if ((0, import_guards20.isUndefined)(webhookEvent.externalBotId)) {
1597
+ return { externalRecordingId: void 0, providerLookupFailed: false };
1598
+ }
1599
+ return fetchExternalRecordingIdFromRecallBot(webhookEvent.externalBotId);
1600
+ };
1601
+ var fetchExternalRecordingIdFromRecallBot = async (externalBotId) => {
1602
+ const botResult = await getRecallBot({ externalBotId });
1603
+ if (!botResult.ok) {
1604
+ console.warn(
1605
+ `[call-recorder] failed to fetch Recall bot ${externalBotId} while resolving a recording id: ${botResult.errorMessage}`
1606
+ );
1607
+ return { externalRecordingId: void 0, providerLookupFailed: true };
1608
+ }
1609
+ return {
1610
+ externalRecordingId: extractRecallBotConvergence(botResult.bot).externalRecordingId,
1611
+ providerLookupFailed: false
1612
+ };
1613
+ };
1614
+ var handleRecallTranscriptEvent = async ({
1615
+ client,
1616
+ webhookEvent,
1617
+ event
1618
+ }) => {
1619
+ const callRecording = await findMatchingCallRecording({
1620
+ client,
1621
+ webhookEvent
1622
+ });
1623
+ if ((0, import_guards20.isUndefined)(callRecording)) {
1624
+ return {
1625
+ status: "skipped",
1626
+ event,
1627
+ reason: "no matching call recording"
1628
+ };
1629
+ }
1630
+ const { transcriptId } = webhookEvent;
1631
+ if (event === "transcript.failed") {
1632
+ return applyTranscriptFailure({
1633
+ client,
1634
+ callRecording,
1635
+ event,
1636
+ transcriptId,
1637
+ subCode: webhookEvent.transcriptFailureSubCode ?? null
1638
+ });
1639
+ }
1640
+ if ((0, import_guards20.isUndefined)(transcriptId)) {
1641
+ return {
1642
+ status: "skipped",
1643
+ event,
1644
+ reason: "missing transcript id"
1645
+ };
1646
+ }
1647
+ const downloadResult = await downloadTranscript({ transcriptId });
1648
+ switch (downloadResult.outcome) {
1649
+ case "filled": {
1650
+ const updateData = {
1651
+ transcript: downloadResult.content,
1652
+ ...(0, import_guards20.isUndefined)(callRecording.externalRecordingId) ? buildExternalRecordingIdUpdate(webhookEvent) : {}
1653
+ };
1654
+ await persistCallRecordingProgress(client, {
1655
+ id: callRecording.id,
1656
+ current: callRecording,
1657
+ updateData
1658
+ });
1659
+ return {
1660
+ status: "updated",
1661
+ event,
1662
+ callRecordingId: callRecording.id,
1663
+ transcriptOutcome: "FILLED"
1664
+ };
1665
+ }
1666
+ case "failed":
1667
+ return applyTranscriptFailure({
1668
+ client,
1669
+ callRecording,
1670
+ event,
1671
+ transcriptId,
1672
+ subCode: downloadResult.subCode
1673
+ });
1674
+ case "pending":
1675
+ case "error": {
1676
+ const reason = downloadResult.outcome === "pending" ? "transcript not downloadable yet" : downloadResult.errorMessage;
1677
+ console.warn(
1678
+ `[call-recorder] could not fill transcript for call recording ${callRecording.id}: ${reason}`
1679
+ );
1680
+ return {
1681
+ status: "skipped",
1682
+ event,
1683
+ reason
1684
+ };
1685
+ }
1686
+ }
1687
+ };
1688
+ var applyTranscriptFailure = async ({
1689
+ client,
1690
+ callRecording,
1691
+ event,
1692
+ transcriptId,
1693
+ subCode
1694
+ }) => {
1695
+ const existingMarker = parseTranscriptMarker(callRecording.transcript);
1696
+ if (!isTranscriptUnset(callRecording) && (0, import_guards20.isUndefined)(existingMarker)) {
1697
+ return {
1698
+ status: "skipped",
1699
+ event,
1700
+ reason: "transcript already filled"
1701
+ };
1702
+ }
1703
+ console.warn(
1704
+ `[call-recorder] transcript failed for call recording ${callRecording.id}${(0, import_guards20.isNull)(subCode) ? "" : ` (${subCode})`}`
1705
+ );
1706
+ await updateCallRecording(client, {
1707
+ id: callRecording.id,
1708
+ data: {
1709
+ transcript: buildFailedTranscriptMarker({
1710
+ recallTranscriptId: transcriptId ?? existingMarker?.recallTranscriptId ?? null,
1711
+ subCode
1712
+ }),
1713
+ callRecorderFailureReason: buildTranscriptFailureReason(subCode),
1714
+ ...isCallRecordingStatusDowngrade({
1715
+ fromStatus: callRecording.status,
1716
+ toStatus: "FAILED" /* FAILED */
1717
+ }) ? {} : { status: "FAILED" /* FAILED */ }
1718
+ }
1719
+ });
1720
+ return {
1721
+ status: "updated",
1722
+ event,
1723
+ callRecordingId: callRecording.id,
1724
+ transcriptOutcome: "FAILED"
1725
+ };
1726
+ };
1727
+
1728
+ // src/logic-functions/process-recall-webhook.ts
1729
+ var processRecallWebhookHandler = (body) => handleRecallWebhook({
1730
+ client: new CoreApiClient(),
1731
+ body
1732
+ });
1733
+ var process_recall_webhook_default = defineLogicFunction({
1734
+ universalIdentifier: PROCESS_RECALL_WEBHOOK_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,
1735
+ name: "process-recall-webhook",
1736
+ description: "Updates the matching CallRecording lifecycle status from a verified Recall.ai webhook event.",
1737
+ timeoutSeconds: 30,
1738
+ handler: processRecallWebhookHandler
1739
+ });
1740
+ export {
1741
+ process_recall_webhook_default as default,
1742
+ processRecallWebhookHandler
1743
+ };
1744
+ //# sourceMappingURL=process-recall-webhook.mjs.map