@contractspec/integration.providers-impls 1.57.0 → 1.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/dist/analytics.d.ts +1 -8
  2. package/dist/analytics.d.ts.map +1 -1
  3. package/dist/analytics.js +3 -3
  4. package/dist/calendar.d.ts +1 -8
  5. package/dist/calendar.d.ts.map +1 -1
  6. package/dist/calendar.js +3 -3
  7. package/dist/database.d.ts +1 -8
  8. package/dist/database.d.ts.map +1 -1
  9. package/dist/database.js +3 -3
  10. package/dist/email.d.ts +1 -8
  11. package/dist/email.d.ts.map +1 -1
  12. package/dist/email.js +3 -3
  13. package/dist/embedding.d.ts +1 -8
  14. package/dist/embedding.d.ts.map +1 -1
  15. package/dist/embedding.js +3 -3
  16. package/dist/impls/elevenlabs-voice.d.ts +14 -18
  17. package/dist/impls/elevenlabs-voice.d.ts.map +1 -1
  18. package/dist/impls/elevenlabs-voice.js +98 -88
  19. package/dist/impls/fal-voice.d.ts +22 -26
  20. package/dist/impls/fal-voice.d.ts.map +1 -1
  21. package/dist/impls/fal-voice.js +103 -78
  22. package/dist/impls/fathom-meeting-recorder.d.ts +35 -39
  23. package/dist/impls/fathom-meeting-recorder.d.ts.map +1 -1
  24. package/dist/impls/fathom-meeting-recorder.js +285 -142
  25. package/dist/impls/fathom-meeting-recorder.mapper.d.ts +4 -8
  26. package/dist/impls/fathom-meeting-recorder.mapper.d.ts.map +1 -1
  27. package/dist/impls/fathom-meeting-recorder.mapper.js +102 -38
  28. package/dist/impls/fathom-meeting-recorder.types.d.ts +16 -20
  29. package/dist/impls/fathom-meeting-recorder.types.d.ts.map +1 -1
  30. package/dist/impls/fathom-meeting-recorder.types.js +1 -0
  31. package/dist/impls/fathom-meeting-recorder.utils.d.ts +10 -14
  32. package/dist/impls/fathom-meeting-recorder.utils.d.ts.map +1 -1
  33. package/dist/impls/fathom-meeting-recorder.utils.js +58 -41
  34. package/dist/impls/fathom-meeting-recorder.webhooks.d.ts +3 -7
  35. package/dist/impls/fathom-meeting-recorder.webhooks.d.ts.map +1 -1
  36. package/dist/impls/fathom-meeting-recorder.webhooks.js +25 -20
  37. package/dist/impls/fireflies-meeting-recorder.d.ts +21 -25
  38. package/dist/impls/fireflies-meeting-recorder.d.ts.map +1 -1
  39. package/dist/impls/fireflies-meeting-recorder.js +272 -149
  40. package/dist/impls/fireflies-meeting-recorder.queries.d.ts +3 -6
  41. package/dist/impls/fireflies-meeting-recorder.queries.d.ts.map +1 -1
  42. package/dist/impls/fireflies-meeting-recorder.queries.js +10 -8
  43. package/dist/impls/fireflies-meeting-recorder.types.d.ts +26 -29
  44. package/dist/impls/fireflies-meeting-recorder.types.d.ts.map +1 -1
  45. package/dist/impls/fireflies-meeting-recorder.types.js +1 -0
  46. package/dist/impls/fireflies-meeting-recorder.utils.d.ts +4 -7
  47. package/dist/impls/fireflies-meeting-recorder.utils.d.ts.map +1 -1
  48. package/dist/impls/fireflies-meeting-recorder.utils.js +34 -27
  49. package/dist/impls/gcs-storage.d.ts +18 -22
  50. package/dist/impls/gcs-storage.d.ts.map +1 -1
  51. package/dist/impls/gcs-storage.js +92 -84
  52. package/dist/impls/gmail-inbound.d.ts +20 -24
  53. package/dist/impls/gmail-inbound.d.ts.map +1 -1
  54. package/dist/impls/gmail-inbound.js +212 -185
  55. package/dist/impls/gmail-outbound.d.ts +12 -16
  56. package/dist/impls/gmail-outbound.d.ts.map +1 -1
  57. package/dist/impls/gmail-outbound.js +126 -92
  58. package/dist/impls/google-calendar.d.ts +17 -21
  59. package/dist/impls/google-calendar.d.ts.map +1 -1
  60. package/dist/impls/google-calendar.js +182 -145
  61. package/dist/impls/gradium-voice.d.ts +20 -22
  62. package/dist/impls/gradium-voice.d.ts.map +1 -1
  63. package/dist/impls/gradium-voice.js +85 -74
  64. package/dist/impls/granola-meeting-recorder.d.ts +31 -24
  65. package/dist/impls/granola-meeting-recorder.d.ts.map +1 -1
  66. package/dist/impls/granola-meeting-recorder.js +511 -143
  67. package/dist/impls/granola-meeting-recorder.mcp.d.ts +25 -0
  68. package/dist/impls/granola-meeting-recorder.mcp.d.ts.map +1 -0
  69. package/dist/impls/granola-meeting-recorder.mcp.js +279 -0
  70. package/dist/impls/granola-meeting-recorder.types.d.ts +60 -49
  71. package/dist/impls/granola-meeting-recorder.types.d.ts.map +1 -1
  72. package/dist/impls/granola-meeting-recorder.types.js +1 -0
  73. package/dist/impls/index.d.ts +28 -28
  74. package/dist/impls/index.d.ts.map +1 -0
  75. package/dist/impls/index.js +4659 -29
  76. package/dist/impls/jira.d.ts +18 -22
  77. package/dist/impls/jira.d.ts.map +1 -1
  78. package/dist/impls/jira.js +112 -101
  79. package/dist/impls/linear.d.ts +17 -21
  80. package/dist/impls/linear.d.ts.map +1 -1
  81. package/dist/impls/linear.js +78 -69
  82. package/dist/impls/mistral-embedding.d.ts +17 -21
  83. package/dist/impls/mistral-embedding.d.ts.map +1 -1
  84. package/dist/impls/mistral-embedding.js +41 -39
  85. package/dist/impls/mistral-llm.d.ts +25 -29
  86. package/dist/impls/mistral-llm.d.ts.map +1 -1
  87. package/dist/impls/mistral-llm.js +266 -244
  88. package/dist/impls/notion.d.ts +20 -24
  89. package/dist/impls/notion.d.ts.map +1 -1
  90. package/dist/impls/notion.js +145 -110
  91. package/dist/impls/posthog-reader.d.ts +18 -22
  92. package/dist/impls/posthog-reader.d.ts.map +1 -1
  93. package/dist/impls/posthog-reader.js +148 -129
  94. package/dist/impls/posthog-utils.d.ts +4 -7
  95. package/dist/impls/posthog-utils.d.ts.map +1 -1
  96. package/dist/impls/posthog-utils.js +31 -22
  97. package/dist/impls/posthog.d.ts +33 -37
  98. package/dist/impls/posthog.d.ts.map +1 -1
  99. package/dist/impls/posthog.js +320 -119
  100. package/dist/impls/postmark-email.d.ts +13 -17
  101. package/dist/impls/postmark-email.d.ts.map +1 -1
  102. package/dist/impls/postmark-email.js +55 -50
  103. package/dist/impls/powens-client.d.ts +111 -114
  104. package/dist/impls/powens-client.d.ts.map +1 -1
  105. package/dist/impls/powens-client.js +194 -170
  106. package/dist/impls/powens-openbanking.d.ts +22 -26
  107. package/dist/impls/powens-openbanking.d.ts.map +1 -1
  108. package/dist/impls/powens-openbanking.js +425 -217
  109. package/dist/impls/provider-factory.d.ts +29 -33
  110. package/dist/impls/provider-factory.d.ts.map +1 -1
  111. package/dist/impls/provider-factory.js +4072 -275
  112. package/dist/impls/qdrant-vector.d.ts +18 -22
  113. package/dist/impls/qdrant-vector.d.ts.map +1 -1
  114. package/dist/impls/qdrant-vector.js +76 -69
  115. package/dist/impls/stripe-payments.d.ts +22 -26
  116. package/dist/impls/stripe-payments.d.ts.map +1 -1
  117. package/dist/impls/stripe-payments.js +219 -193
  118. package/dist/impls/supabase-psql.d.ts +21 -25
  119. package/dist/impls/supabase-psql.d.ts.map +1 -1
  120. package/dist/impls/supabase-psql.js +138 -98
  121. package/dist/impls/supabase-vector.d.ts +29 -33
  122. package/dist/impls/supabase-vector.d.ts.map +1 -1
  123. package/dist/impls/supabase-vector.js +278 -103
  124. package/dist/impls/tldv-meeting-recorder.d.ts +18 -22
  125. package/dist/impls/tldv-meeting-recorder.d.ts.map +1 -1
  126. package/dist/impls/tldv-meeting-recorder.js +142 -127
  127. package/dist/impls/twilio-sms.d.ts +14 -17
  128. package/dist/impls/twilio-sms.d.ts.map +1 -1
  129. package/dist/impls/twilio-sms.js +62 -55
  130. package/dist/index.d.ts +15 -64
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +4700 -107
  133. package/dist/llm.d.ts +1 -8
  134. package/dist/llm.d.ts.map +1 -1
  135. package/dist/llm.js +3 -3
  136. package/dist/meeting-recorder.d.ts +1 -8
  137. package/dist/meeting-recorder.d.ts.map +1 -1
  138. package/dist/meeting-recorder.js +3 -3
  139. package/dist/node/analytics.js +2 -0
  140. package/dist/node/calendar.js +2 -0
  141. package/dist/node/database.js +2 -0
  142. package/dist/node/email.js +2 -0
  143. package/dist/node/embedding.js +2 -0
  144. package/dist/node/impls/elevenlabs-voice.js +102 -0
  145. package/dist/node/impls/fal-voice.js +112 -0
  146. package/dist/node/impls/fathom-meeting-recorder.js +287 -0
  147. package/dist/node/impls/fathom-meeting-recorder.mapper.js +105 -0
  148. package/dist/node/impls/fathom-meeting-recorder.types.js +0 -0
  149. package/dist/node/impls/fathom-meeting-recorder.utils.js +72 -0
  150. package/dist/node/impls/fathom-meeting-recorder.webhooks.js +29 -0
  151. package/dist/node/impls/fireflies-meeting-recorder.js +274 -0
  152. package/dist/node/impls/fireflies-meeting-recorder.queries.js +85 -0
  153. package/dist/node/impls/fireflies-meeting-recorder.types.js +0 -0
  154. package/dist/node/impls/fireflies-meeting-recorder.utils.js +42 -0
  155. package/dist/node/impls/gcs-storage.js +97 -0
  156. package/dist/node/impls/gmail-inbound.js +227 -0
  157. package/dist/node/impls/gmail-outbound.js +139 -0
  158. package/dist/node/impls/google-calendar.js +191 -0
  159. package/dist/node/impls/gradium-voice.js +90 -0
  160. package/dist/node/impls/granola-meeting-recorder.js +512 -0
  161. package/dist/node/impls/granola-meeting-recorder.mcp.js +278 -0
  162. package/dist/node/impls/granola-meeting-recorder.types.js +0 -0
  163. package/dist/node/impls/index.js +4658 -0
  164. package/dist/node/impls/jira.js +124 -0
  165. package/dist/node/impls/linear.js +83 -0
  166. package/dist/node/impls/mistral-embedding.js +43 -0
  167. package/dist/node/impls/mistral-llm.js +269 -0
  168. package/dist/node/impls/notion.js +160 -0
  169. package/dist/node/impls/posthog-reader.js +159 -0
  170. package/dist/node/impls/posthog-utils.js +38 -0
  171. package/dist/node/impls/posthog.js +322 -0
  172. package/dist/node/impls/postmark-email.js +60 -0
  173. package/dist/node/impls/powens-client.js +195 -0
  174. package/dist/node/impls/powens-openbanking.js +426 -0
  175. package/dist/node/impls/provider-factory.js +4080 -0
  176. package/dist/node/impls/qdrant-vector.js +78 -0
  177. package/dist/node/impls/stripe-payments.js +228 -0
  178. package/dist/node/impls/supabase-psql.js +150 -0
  179. package/dist/node/impls/supabase-vector.js +323 -0
  180. package/dist/node/impls/tldv-meeting-recorder.js +145 -0
  181. package/dist/node/impls/twilio-sms.js +65 -0
  182. package/dist/node/index.js +4699 -0
  183. package/dist/node/llm.js +2 -0
  184. package/dist/node/meeting-recorder.js +2 -0
  185. package/dist/node/openbanking.js +2 -0
  186. package/dist/node/payments.js +2 -0
  187. package/dist/node/project-management.js +2 -0
  188. package/dist/node/runtime.js +0 -0
  189. package/dist/node/secrets/provider.js +11 -0
  190. package/dist/node/sms.js +2 -0
  191. package/dist/node/storage.js +2 -0
  192. package/dist/node/vector-store.js +2 -0
  193. package/dist/node/voice.js +2 -0
  194. package/dist/openbanking.d.ts +1 -8
  195. package/dist/openbanking.d.ts.map +1 -1
  196. package/dist/openbanking.js +3 -3
  197. package/dist/payments.d.ts +1 -8
  198. package/dist/payments.d.ts.map +1 -1
  199. package/dist/payments.js +3 -3
  200. package/dist/project-management.d.ts +1 -8
  201. package/dist/project-management.d.ts.map +1 -1
  202. package/dist/project-management.js +3 -3
  203. package/dist/runtime.d.ts +2 -2
  204. package/dist/runtime.d.ts.map +1 -0
  205. package/dist/runtime.js +1 -0
  206. package/dist/secrets/provider.d.ts +3 -2
  207. package/dist/secrets/provider.d.ts.map +1 -0
  208. package/dist/secrets/provider.js +12 -3
  209. package/dist/sms.d.ts +1 -8
  210. package/dist/sms.d.ts.map +1 -1
  211. package/dist/sms.js +3 -3
  212. package/dist/storage.d.ts +1 -8
  213. package/dist/storage.d.ts.map +1 -1
  214. package/dist/storage.js +3 -3
  215. package/dist/vector-store.d.ts +1 -8
  216. package/dist/vector-store.d.ts.map +1 -1
  217. package/dist/vector-store.js +3 -3
  218. package/dist/voice.d.ts +1 -8
  219. package/dist/voice.d.ts.map +1 -1
  220. package/dist/voice.js +3 -3
  221. package/package.json +405 -114
  222. package/dist/_virtual/_rolldown/runtime.js +0 -36
  223. package/dist/impls/elevenlabs-voice.js.map +0 -1
  224. package/dist/impls/fal-voice.js.map +0 -1
  225. package/dist/impls/fathom-meeting-recorder.js.map +0 -1
  226. package/dist/impls/fathom-meeting-recorder.mapper.js.map +0 -1
  227. package/dist/impls/fathom-meeting-recorder.utils.js.map +0 -1
  228. package/dist/impls/fathom-meeting-recorder.webhooks.js.map +0 -1
  229. package/dist/impls/fireflies-meeting-recorder.js.map +0 -1
  230. package/dist/impls/fireflies-meeting-recorder.queries.js.map +0 -1
  231. package/dist/impls/fireflies-meeting-recorder.utils.js.map +0 -1
  232. package/dist/impls/gcs-storage.js.map +0 -1
  233. package/dist/impls/gmail-inbound.js.map +0 -1
  234. package/dist/impls/gmail-outbound.js.map +0 -1
  235. package/dist/impls/google-calendar.js.map +0 -1
  236. package/dist/impls/gradium-voice.js.map +0 -1
  237. package/dist/impls/granola-meeting-recorder.js.map +0 -1
  238. package/dist/impls/jira.js.map +0 -1
  239. package/dist/impls/linear.js.map +0 -1
  240. package/dist/impls/mistral-embedding.js.map +0 -1
  241. package/dist/impls/mistral-llm.js.map +0 -1
  242. package/dist/impls/notion.js.map +0 -1
  243. package/dist/impls/posthog-reader.js.map +0 -1
  244. package/dist/impls/posthog-utils.js.map +0 -1
  245. package/dist/impls/posthog.js.map +0 -1
  246. package/dist/impls/postmark-email.js.map +0 -1
  247. package/dist/impls/powens-client.js.map +0 -1
  248. package/dist/impls/powens-openbanking.js.map +0 -1
  249. package/dist/impls/provider-factory.js.map +0 -1
  250. package/dist/impls/qdrant-vector.js.map +0 -1
  251. package/dist/impls/stripe-payments.js.map +0 -1
  252. package/dist/impls/supabase-psql.js.map +0 -1
  253. package/dist/impls/supabase-vector.js.map +0 -1
  254. package/dist/impls/tldv-meeting-recorder.js.map +0 -1
  255. package/dist/impls/twilio-sms.js.map +0 -1
  256. package/dist/index.js.map +0 -1
@@ -0,0 +1,512 @@
1
+ // src/impls/granola-meeting-recorder.mcp.ts
2
+ var UNKNOWN_EMAIL = "unknown@granola.local";
3
+ var EPOCH = "1970-01-01T00:00:00.000Z";
4
+
5
+ class GranolaMcpClient {
6
+ requestId = 0;
7
+ mcpUrl;
8
+ mcpAccessToken;
9
+ mcpHeaders;
10
+ fetchFn;
11
+ constructor(options) {
12
+ this.mcpUrl = options.mcpUrl;
13
+ this.mcpAccessToken = options.mcpAccessToken;
14
+ this.mcpHeaders = options.mcpHeaders;
15
+ this.fetchFn = options.fetchFn ?? fetch;
16
+ }
17
+ async callTool(name, args) {
18
+ const headers = {
19
+ "Content-Type": "application/json",
20
+ ...this.mcpHeaders ?? {}
21
+ };
22
+ if (this.mcpAccessToken) {
23
+ headers.Authorization = `Bearer ${this.mcpAccessToken}`;
24
+ }
25
+ const response = await this.fetchFn(this.mcpUrl, {
26
+ method: "POST",
27
+ headers,
28
+ body: JSON.stringify({
29
+ jsonrpc: "2.0",
30
+ id: ++this.requestId,
31
+ method: "tools/call",
32
+ params: {
33
+ name,
34
+ arguments: args
35
+ }
36
+ })
37
+ });
38
+ if (!response.ok) {
39
+ const message = await safeReadText(response);
40
+ throw new Error(`Granola MCP error (${response.status}): ${message}`);
41
+ }
42
+ const rpc = await response.json();
43
+ if (rpc.error) {
44
+ throw new Error(rpc.error.message ?? "Granola MCP returned an error.");
45
+ }
46
+ return extractRpcResult(rpc);
47
+ }
48
+ }
49
+ function normalizeMcpListResult(payload) {
50
+ const root = asObject(payload);
51
+ const list = asArray(payload) ?? asArray(root?.notes) ?? asArray(root?.meetings) ?? asArray(root?.items) ?? asArray(root?.results) ?? asArray(root?.data) ?? [];
52
+ const notes = list.map((item) => mapSummaryItem(item)).filter((item) => Boolean(item));
53
+ return {
54
+ notes,
55
+ nextCursor: readString(root, ["nextCursor", "next_cursor", "cursor"]),
56
+ hasMore: readBoolean(root, ["hasMore", "has_more"])
57
+ };
58
+ }
59
+ function normalizeMcpMeeting(payload, targetMeetingId) {
60
+ const root = asObject(payload);
61
+ const candidates = asArray(payload) ?? asArray(root?.meetings) ?? asArray(root?.notes) ?? asArray(root?.items) ?? asArray(root?.results) ?? asArray(root?.data);
62
+ if (candidates?.length) {
63
+ const selected = candidates.find((item) => readId(item) === targetMeetingId) ?? candidates.find((item) => String(readId(item) ?? "").includes(targetMeetingId)) ?? candidates[0];
64
+ return selected ? mapMeetingItem(selected) : undefined;
65
+ }
66
+ const direct = mapMeetingItem(payload);
67
+ if (direct && direct.id === targetMeetingId) {
68
+ return direct;
69
+ }
70
+ return direct;
71
+ }
72
+ function normalizeMcpTranscript(payload) {
73
+ const root = asObject(payload);
74
+ const list = asArray(payload) ?? asArray(root?.transcript) ?? asArray(root?.segments) ?? asArray(root?.items) ?? asArray(root?.data) ?? [];
75
+ if (list.length === 0 && typeof payload === "string") {
76
+ return [
77
+ {
78
+ text: payload,
79
+ start_time: "00:00:00",
80
+ end_time: "00:00:00"
81
+ }
82
+ ];
83
+ }
84
+ return list.map((item) => mapTranscriptSegment(item)).filter((item) => Boolean(item));
85
+ }
86
+ function extractRpcResult(rpc) {
87
+ const result = rpc.result;
88
+ if (!result)
89
+ return null;
90
+ if (result.structuredContent !== undefined)
91
+ return result.structuredContent;
92
+ if (result.data !== undefined)
93
+ return result.data;
94
+ const textPayload = result.content?.find((entry) => entry?.type === "text")?.text;
95
+ if (!textPayload)
96
+ return result;
97
+ try {
98
+ return JSON.parse(textPayload);
99
+ } catch {
100
+ return textPayload;
101
+ }
102
+ }
103
+ function mapSummaryItem(value) {
104
+ const object = asObject(value);
105
+ if (!object)
106
+ return;
107
+ const id = readId(object);
108
+ if (!id)
109
+ return;
110
+ const owner = mapOwner(object);
111
+ return {
112
+ id,
113
+ title: readString(object, ["title", "name", "meeting_title"]) ?? null,
114
+ owner,
115
+ created_at: readString(object, ["created_at", "createdAt", "date", "meeting_date"]) ?? EPOCH
116
+ };
117
+ }
118
+ function mapMeetingItem(value) {
119
+ const summary = mapSummaryItem(value);
120
+ if (!summary)
121
+ return;
122
+ const object = asObject(value) ?? {};
123
+ const attendees = asArray(object.attendees) ?? asArray(object.participants) ?? asArray(object.invitees) ?? [];
124
+ const mappedAttendees = attendees.map((entry) => mapUser(entry)).filter((entry) => Boolean(entry));
125
+ const folders = asArray(object.folder_membership) ?? asArray(object.folders) ?? [];
126
+ const folderMembership = folders.map((entry, index) => mapFolder(entry, index)).filter((entry) => Boolean(entry));
127
+ const calendarEvent = asObject(object.calendar_event) ? {
128
+ event_title: readString(asObject(object.calendar_event), [
129
+ "event_title",
130
+ "title"
131
+ ]) ?? null,
132
+ invitees: mappedAttendees.map((attendee) => ({
133
+ email: attendee.email
134
+ })),
135
+ organiser: readString(asObject(object.calendar_event), [
136
+ "organiser",
137
+ "organizer"
138
+ ]) ?? summary.owner.email,
139
+ calendar_event_id: readString(asObject(object.calendar_event), [
140
+ "calendar_event_id",
141
+ "id"
142
+ ]) ?? null,
143
+ scheduled_start_time: readString(asObject(object.calendar_event), [
144
+ "scheduled_start_time",
145
+ "start_time",
146
+ "start"
147
+ ]) ?? null,
148
+ scheduled_end_time: readString(asObject(object.calendar_event), [
149
+ "scheduled_end_time",
150
+ "end_time",
151
+ "end"
152
+ ]) ?? null
153
+ } : null;
154
+ const transcript = normalizeMcpTranscript(object.transcript ?? object.segments);
155
+ return {
156
+ ...summary,
157
+ calendar_event: calendarEvent,
158
+ attendees: mappedAttendees,
159
+ folder_membership: folderMembership,
160
+ summary_text: readString(object, ["summary_text", "summary", "enhanced_notes"]) ?? "",
161
+ transcript: transcript.length ? transcript : null
162
+ };
163
+ }
164
+ function mapTranscriptSegment(value) {
165
+ const object = asObject(value);
166
+ if (!object) {
167
+ if (typeof value !== "string")
168
+ return;
169
+ return {
170
+ text: value,
171
+ start_time: "00:00:00",
172
+ end_time: "00:00:00"
173
+ };
174
+ }
175
+ const text = readString(object, ["text", "content", "utterance"]);
176
+ if (!text)
177
+ return;
178
+ const speakerSource = readString(asObject(object.speaker), ["source", "name"]) ?? readString(object, ["speaker", "speaker_name"]);
179
+ return {
180
+ speaker: speakerSource ? { source: speakerSource } : undefined,
181
+ text,
182
+ start_time: readString(object, ["start_time", "startTime", "timestamp", "time"]) ?? "00:00:00",
183
+ end_time: readString(object, ["end_time", "endTime"]) ?? "00:00:00"
184
+ };
185
+ }
186
+ function mapOwner(object) {
187
+ const ownerObject = asObject(object.owner) ?? asObject(object.organizer) ?? asObject(object.organiser);
188
+ const attendee = asArray(object.attendees)?.[0] ?? asArray(object.participants)?.[0] ?? asArray(object.invitees)?.[0];
189
+ const ownerCandidate = ownerObject ?? asObject(attendee) ?? {};
190
+ return {
191
+ name: readString(ownerCandidate, ["name", "displayName"]) ?? null,
192
+ email: readString(ownerCandidate, ["email"]) ?? UNKNOWN_EMAIL
193
+ };
194
+ }
195
+ function mapUser(value) {
196
+ if (typeof value === "string") {
197
+ return {
198
+ name: null,
199
+ email: value
200
+ };
201
+ }
202
+ const object = asObject(value);
203
+ if (!object)
204
+ return;
205
+ const email = readString(object, ["email"]);
206
+ if (!email)
207
+ return;
208
+ return {
209
+ name: readString(object, ["name", "displayName"]) ?? null,
210
+ email
211
+ };
212
+ }
213
+ function mapFolder(value, index) {
214
+ const object = asObject(value);
215
+ if (!object)
216
+ return;
217
+ const id = readString(object, ["id"]) ?? `folder-${index}`;
218
+ const name = readString(object, ["name"]) ?? "Folder";
219
+ return {
220
+ id,
221
+ object: "folder",
222
+ name
223
+ };
224
+ }
225
+ function readId(value) {
226
+ const object = asObject(value);
227
+ if (!object)
228
+ return;
229
+ return readString(object, [
230
+ "id",
231
+ "meeting_id",
232
+ "meetingId",
233
+ "note_id",
234
+ "noteId"
235
+ ]);
236
+ }
237
+ function readString(object, keys) {
238
+ if (!object)
239
+ return;
240
+ for (const key of keys) {
241
+ const value = object[key];
242
+ if (typeof value === "string" && value.trim().length > 0) {
243
+ return value;
244
+ }
245
+ }
246
+ return;
247
+ }
248
+ function readBoolean(object, keys) {
249
+ if (!object)
250
+ return;
251
+ for (const key of keys) {
252
+ const value = object[key];
253
+ if (typeof value === "boolean")
254
+ return value;
255
+ }
256
+ return;
257
+ }
258
+ function asObject(value) {
259
+ if (!value || typeof value !== "object" || Array.isArray(value))
260
+ return;
261
+ return value;
262
+ }
263
+ function asArray(value) {
264
+ return Array.isArray(value) ? value : undefined;
265
+ }
266
+ async function safeReadText(response) {
267
+ try {
268
+ return await response.text();
269
+ } catch {
270
+ return response.statusText;
271
+ }
272
+ }
273
+
274
+ // src/impls/granola-meeting-recorder.ts
275
+ var DEFAULT_BASE_URL = "https://public-api.granola.ai";
276
+ var DEFAULT_MCP_URL = "https://mcp.granola.ai/mcp";
277
+ var MAX_PAGE_SIZE = 30;
278
+
279
+ class GranolaMeetingRecorderProvider {
280
+ apiKey;
281
+ baseUrl;
282
+ defaultPageSize;
283
+ transport;
284
+ mcpClient;
285
+ constructor(options) {
286
+ this.apiKey = options.apiKey;
287
+ this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
288
+ this.defaultPageSize = options.pageSize;
289
+ this.transport = options.transport ?? "api";
290
+ this.mcpClient = new GranolaMcpClient({
291
+ mcpUrl: options.mcpUrl ?? DEFAULT_MCP_URL,
292
+ mcpAccessToken: options.mcpAccessToken,
293
+ mcpHeaders: options.mcpHeaders,
294
+ fetchFn: options.fetchFn
295
+ });
296
+ }
297
+ async listMeetings(params) {
298
+ if (this.transport === "mcp") {
299
+ return this.listMeetingsViaMcp(params);
300
+ }
301
+ const query = new URLSearchParams;
302
+ if (params.from)
303
+ query.set("created_after", params.from);
304
+ if (params.to)
305
+ query.set("created_before", params.to);
306
+ if (params.cursor)
307
+ query.set("cursor", params.cursor);
308
+ const pageSize = params.pageSize ?? this.defaultPageSize;
309
+ if (pageSize) {
310
+ query.set("page_size", String(Math.min(pageSize, MAX_PAGE_SIZE)));
311
+ }
312
+ const data = await this.request(`/v1/notes?${query.toString()}`);
313
+ return {
314
+ meetings: data.notes.map((note) => this.mapNoteSummary(note, params)),
315
+ nextCursor: data.cursor ?? undefined,
316
+ hasMore: data.hasMore
317
+ };
318
+ }
319
+ async getMeeting(params) {
320
+ if (this.transport === "mcp") {
321
+ return this.getMeetingViaMcp(params);
322
+ }
323
+ const includeTranscript = params.includeTranscript ?? false;
324
+ const note = await this.getNote(params.meetingId, includeTranscript);
325
+ return this.mapNoteDetail(note, params);
326
+ }
327
+ async getTranscript(params) {
328
+ if (this.transport === "mcp") {
329
+ return this.getTranscriptViaMcp(params);
330
+ }
331
+ const note = await this.getNote(params.meetingId, true);
332
+ const segments = this.mapTranscriptSegments(note.transcript);
333
+ return {
334
+ id: note.id,
335
+ meetingId: note.id,
336
+ tenantId: params.tenantId,
337
+ connectionId: params.connectionId ?? "unknown",
338
+ externalId: note.id,
339
+ format: "segments",
340
+ text: segments.map((segment) => segment.text).join(`
341
+ `),
342
+ segments,
343
+ generatedAt: note.created_at,
344
+ metadata: {
345
+ summaryText: note.summary_text
346
+ },
347
+ raw: note.transcript ?? undefined
348
+ };
349
+ }
350
+ async listMeetingsViaMcp(params) {
351
+ const payload = await this.mcpClient.callTool("list_meetings", {
352
+ cursor: params.cursor,
353
+ limit: params.pageSize ?? this.defaultPageSize,
354
+ query: params.query,
355
+ from: params.from,
356
+ to: params.to,
357
+ organizerEmail: params.organizerEmail,
358
+ participantEmail: params.participantEmail
359
+ });
360
+ const normalized = normalizeMcpListResult(payload);
361
+ return {
362
+ meetings: normalized.notes.map((note) => this.mapNoteSummary(note, params)),
363
+ nextCursor: normalized.nextCursor,
364
+ hasMore: normalized.hasMore ?? Boolean(normalized.nextCursor && normalized.notes.length > 0)
365
+ };
366
+ }
367
+ async getMeetingViaMcp(params) {
368
+ const primaryPayload = await this.mcpClient.callTool("list_meetings", {
369
+ query: params.meetingId,
370
+ limit: 50
371
+ });
372
+ let note = normalizeMcpMeeting(primaryPayload, params.meetingId);
373
+ if (!note) {
374
+ const fallbackPayload = await this.mcpClient.callTool("get_meetings", {
375
+ query: params.meetingId
376
+ });
377
+ note = normalizeMcpMeeting(fallbackPayload, params.meetingId);
378
+ }
379
+ if (!note) {
380
+ throw new Error(`Granola meeting "${params.meetingId}" not found via MCP.`);
381
+ }
382
+ return this.mapNoteDetail(note, params);
383
+ }
384
+ async getTranscriptViaMcp(params) {
385
+ const payload = await this.mcpClient.callTool("get_meeting_transcript", {
386
+ meeting_id: params.meetingId,
387
+ meetingId: params.meetingId,
388
+ id: params.meetingId
389
+ });
390
+ const transcript = normalizeMcpTranscript(payload);
391
+ const segments = this.mapTranscriptSegments(transcript);
392
+ return {
393
+ id: params.meetingId,
394
+ meetingId: params.meetingId,
395
+ tenantId: params.tenantId,
396
+ connectionId: params.connectionId ?? "unknown",
397
+ externalId: params.meetingId,
398
+ format: "segments",
399
+ text: segments.map((segment) => segment.text).join(`
400
+ `),
401
+ segments,
402
+ metadata: {
403
+ provider: "granola",
404
+ transport: "mcp"
405
+ },
406
+ raw: payload
407
+ };
408
+ }
409
+ async getNote(noteId, includeTranscript) {
410
+ const query = includeTranscript ? "?include=transcript" : "";
411
+ return this.request(`/v1/notes/${noteId}${query}`);
412
+ }
413
+ mapNoteSummary(note, params) {
414
+ const connectionId = params.connectionId ?? "unknown";
415
+ return {
416
+ id: note.id,
417
+ tenantId: params.tenantId,
418
+ connectionId,
419
+ externalId: note.id,
420
+ title: note.title ?? undefined,
421
+ organizer: this.mapUser(note.owner),
422
+ scheduledStartAt: note.created_at,
423
+ recordingStartAt: note.created_at,
424
+ transcriptAvailable: false,
425
+ createdAt: note.created_at,
426
+ updatedAt: note.created_at,
427
+ sourcePlatform: "granola"
428
+ };
429
+ }
430
+ mapNoteDetail(note, params) {
431
+ const connectionId = params.connectionId ?? "unknown";
432
+ const calendarEvent = note.calendar_event ?? undefined;
433
+ const invitees = calendarEvent?.invitees ? calendarEvent.invitees.map((invitee) => this.mapInvitee(invitee)) : note.attendees?.map((attendee) => this.mapUser(attendee)).filter(Boolean);
434
+ const participants = note.attendees?.map((attendee) => this.mapUser(attendee)).filter(Boolean);
435
+ return {
436
+ id: note.id,
437
+ tenantId: params.tenantId,
438
+ connectionId,
439
+ externalId: note.id,
440
+ title: note.title ?? calendarEvent?.event_title ?? undefined,
441
+ summary: note.summary_text ?? undefined,
442
+ organizer: this.mapUser(note.owner),
443
+ invitees: invitees?.length ? invitees : undefined,
444
+ participants: participants?.length ? participants : undefined,
445
+ scheduledStartAt: calendarEvent?.scheduled_start_time ?? undefined,
446
+ scheduledEndAt: calendarEvent?.scheduled_end_time ?? undefined,
447
+ recordingStartAt: calendarEvent?.scheduled_start_time ?? note.created_at,
448
+ recordingEndAt: calendarEvent?.scheduled_end_time ?? undefined,
449
+ transcriptAvailable: Array.isArray(note.transcript),
450
+ createdAt: note.created_at,
451
+ updatedAt: note.created_at,
452
+ sourcePlatform: "granola",
453
+ metadata: {
454
+ calendarEvent,
455
+ folderMembership: note.folder_membership
456
+ }
457
+ };
458
+ }
459
+ mapTranscriptSegments(transcript) {
460
+ if (!transcript)
461
+ return [];
462
+ return transcript.map((segment, index) => ({
463
+ index,
464
+ speakerName: segment.speaker?.source ?? undefined,
465
+ text: segment.text,
466
+ startTime: segment.start_time,
467
+ endTime: segment.end_time
468
+ }));
469
+ }
470
+ mapUser(user) {
471
+ if (!user)
472
+ return;
473
+ return {
474
+ name: user.name ?? undefined,
475
+ email: user.email ?? undefined,
476
+ role: "organizer"
477
+ };
478
+ }
479
+ mapInvitee(invitee) {
480
+ return {
481
+ email: invitee.email,
482
+ role: "attendee"
483
+ };
484
+ }
485
+ async request(path) {
486
+ if (!this.apiKey) {
487
+ throw new Error('Granola apiKey is required when transport is "api".');
488
+ }
489
+ const response = await fetch(`${this.baseUrl}${path}`, {
490
+ headers: {
491
+ Authorization: `Bearer ${this.apiKey}`,
492
+ "Content-Type": "application/json"
493
+ }
494
+ });
495
+ if (!response.ok) {
496
+ const message = await safeReadError(response);
497
+ throw new Error(`Granola API error (${response.status}): ${message}`);
498
+ }
499
+ return await response.json();
500
+ }
501
+ }
502
+ async function safeReadError(response) {
503
+ try {
504
+ const data = await response.json();
505
+ return data?.message ?? response.statusText;
506
+ } catch {
507
+ return response.statusText;
508
+ }
509
+ }
510
+ export {
511
+ GranolaMeetingRecorderProvider
512
+ };