@contractspec/integration.providers-impls 3.8.9 → 3.8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics.js +1 -2
- package/dist/calendar.js +1 -2
- package/dist/database.js +1 -2
- package/dist/email.js +1 -2
- package/dist/embedding.js +1 -2
- package/dist/health.js +1 -2
- package/dist/impls/async-event-queue.js +1 -48
- package/dist/impls/composio-fallback-resolver.js +1 -579
- package/dist/impls/composio-mcp.js +1 -163
- package/dist/impls/composio-proxies.js +1 -310
- package/dist/impls/composio-sdk.js +1 -77
- package/dist/impls/composio-types.js +1 -53
- package/dist/impls/elevenlabs-voice.js +1 -104
- package/dist/impls/fal-voice.js +1 -117
- package/dist/impls/fathom-meeting-recorder.js +2 -289
- package/dist/impls/fathom-meeting-recorder.mapper.js +1 -107
- package/dist/impls/fathom-meeting-recorder.utils.js +1 -74
- package/dist/impls/fathom-meeting-recorder.webhooks.js +1 -31
- package/dist/impls/fireflies-meeting-recorder.js +5 -203
- package/dist/impls/fireflies-meeting-recorder.queries.js +4 -14
- package/dist/impls/fireflies-meeting-recorder.utils.js +1 -44
- package/dist/impls/gcs-storage.js +1 -99
- package/dist/impls/gmail-inbound.js +1 -229
- package/dist/impls/gmail-outbound.js +25 -137
- package/dist/impls/google-calendar.js +1 -193
- package/dist/impls/gradium-voice.js +1 -95
- package/dist/impls/granola-meeting-recorder.js +3 -514
- package/dist/impls/granola-meeting-recorder.mcp.js +1 -280
- package/dist/impls/health/base-health-provider.js +1 -617
- package/dist/impls/health/hybrid-health-providers.js +1 -1089
- package/dist/impls/health/official-health-providers.js +1 -969
- package/dist/impls/health/provider-normalizers.js +1 -288
- package/dist/impls/health/providers.js +1 -1095
- package/dist/impls/health-provider-factory.js +1 -1309
- package/dist/impls/index.js +42 -7448
- package/dist/impls/jira.js +1 -126
- package/dist/impls/linear.js +1 -85
- package/dist/impls/messaging-github.js +1 -111
- package/dist/impls/messaging-slack.js +1 -81
- package/dist/impls/messaging-telegram.js +1 -48
- package/dist/impls/messaging-whatsapp-meta.js +1 -53
- package/dist/impls/messaging-whatsapp-twilio.js +1 -83
- package/dist/impls/mistral-conversational.js +2 -477
- package/dist/impls/mistral-conversational.session.js +2 -207
- package/dist/impls/mistral-embedding.js +1 -45
- package/dist/impls/mistral-llm.js +1 -271
- package/dist/impls/mistral-stt.js +1 -168
- package/dist/impls/notion.js +1 -162
- package/dist/impls/posthog-reader.js +1 -161
- package/dist/impls/posthog-utils.js +1 -40
- package/dist/impls/posthog.js +1 -324
- package/dist/impls/postmark-email.js +1 -62
- package/dist/impls/powens-client.js +1 -197
- package/dist/impls/powens-openbanking.js +1 -428
- package/dist/impls/provider-factory.js +18 -6268
- package/dist/impls/qdrant-vector.js +1 -80
- package/dist/impls/stripe-payments.js +1 -230
- package/dist/impls/supabase-psql.js +1 -152
- package/dist/impls/supabase-vector.js +9 -298
- package/dist/impls/tldv-meeting-recorder.js +2 -147
- package/dist/impls/twilio-sms.js +1 -67
- package/dist/index.js +42 -7495
- package/dist/llm.js +1 -2
- package/dist/meeting-recorder.js +1 -2
- package/dist/messaging.js +1 -2
- package/dist/node/analytics.js +1 -2
- package/dist/node/calendar.js +1 -2
- package/dist/node/database.js +1 -2
- package/dist/node/email.js +1 -2
- package/dist/node/embedding.js +1 -2
- package/dist/node/health.js +1 -2
- package/dist/node/impls/async-event-queue.js +1 -49
- package/dist/node/impls/composio-fallback-resolver.js +1 -580
- package/dist/node/impls/composio-mcp.js +1 -164
- package/dist/node/impls/composio-proxies.js +1 -311
- package/dist/node/impls/composio-sdk.js +1 -78
- package/dist/node/impls/composio-types.js +1 -54
- package/dist/node/impls/elevenlabs-voice.js +1 -105
- package/dist/node/impls/fal-voice.js +1 -118
- package/dist/node/impls/fathom-meeting-recorder.js +2 -290
- package/dist/node/impls/fathom-meeting-recorder.mapper.js +1 -108
- package/dist/node/impls/fathom-meeting-recorder.utils.js +1 -75
- package/dist/node/impls/fathom-meeting-recorder.webhooks.js +1 -32
- package/dist/node/impls/fireflies-meeting-recorder.js +5 -204
- package/dist/node/impls/fireflies-meeting-recorder.queries.js +4 -15
- package/dist/node/impls/fireflies-meeting-recorder.utils.js +1 -45
- package/dist/node/impls/gcs-storage.js +1 -100
- package/dist/node/impls/gmail-inbound.js +1 -230
- package/dist/node/impls/gmail-outbound.js +25 -138
- package/dist/node/impls/google-calendar.js +1 -194
- package/dist/node/impls/gradium-voice.js +1 -96
- package/dist/node/impls/granola-meeting-recorder.js +3 -515
- package/dist/node/impls/granola-meeting-recorder.mcp.js +1 -281
- package/dist/node/impls/health/base-health-provider.js +1 -618
- package/dist/node/impls/health/hybrid-health-providers.js +1 -1090
- package/dist/node/impls/health/official-health-providers.js +1 -970
- package/dist/node/impls/health/provider-normalizers.js +1 -289
- package/dist/node/impls/health/providers.js +1 -1096
- package/dist/node/impls/health-provider-factory.js +1 -1310
- package/dist/node/impls/index.js +42 -7449
- package/dist/node/impls/jira.js +1 -127
- package/dist/node/impls/linear.js +1 -86
- package/dist/node/impls/messaging-github.js +1 -112
- package/dist/node/impls/messaging-slack.js +1 -82
- package/dist/node/impls/messaging-telegram.js +1 -49
- package/dist/node/impls/messaging-whatsapp-meta.js +1 -54
- package/dist/node/impls/messaging-whatsapp-twilio.js +1 -84
- package/dist/node/impls/mistral-conversational.js +2 -478
- package/dist/node/impls/mistral-conversational.session.js +2 -208
- package/dist/node/impls/mistral-embedding.js +1 -46
- package/dist/node/impls/mistral-llm.js +1 -272
- package/dist/node/impls/mistral-stt.js +1 -169
- package/dist/node/impls/notion.js +1 -163
- package/dist/node/impls/posthog-reader.js +1 -162
- package/dist/node/impls/posthog-utils.js +1 -41
- package/dist/node/impls/posthog.js +1 -325
- package/dist/node/impls/postmark-email.js +1 -63
- package/dist/node/impls/powens-client.js +1 -198
- package/dist/node/impls/powens-openbanking.js +1 -429
- package/dist/node/impls/provider-factory.js +18 -6269
- package/dist/node/impls/qdrant-vector.js +1 -81
- package/dist/node/impls/stripe-payments.js +1 -231
- package/dist/node/impls/supabase-psql.js +1 -153
- package/dist/node/impls/supabase-vector.js +9 -299
- package/dist/node/impls/tldv-meeting-recorder.js +2 -148
- package/dist/node/impls/twilio-sms.js +1 -68
- package/dist/node/index.js +42 -7496
- package/dist/node/llm.js +1 -2
- package/dist/node/meeting-recorder.js +1 -2
- package/dist/node/messaging.js +1 -2
- package/dist/node/openbanking.js +1 -2
- package/dist/node/payments.js +1 -2
- package/dist/node/project-management.js +1 -2
- package/dist/node/secrets/provider.js +1 -14
- package/dist/node/sms.js +1 -2
- package/dist/node/storage.js +1 -2
- package/dist/node/vector-store.js +1 -2
- package/dist/node/voice.js +1 -2
- package/dist/openbanking.js +1 -2
- package/dist/payments.js +1 -2
- package/dist/project-management.js +1 -2
- package/dist/secrets/provider.js +1 -13
- package/dist/sms.js +1 -2
- package/dist/storage.js +1 -2
- package/dist/vector-store.js +1 -2
- package/dist/voice.js +1 -2
- package/package.json +16 -16
|
@@ -1,75 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
// src/impls/fathom-meeting-recorder.utils.ts
|
|
5
|
-
function extractItems(page) {
|
|
6
|
-
if (Array.isArray(page.items))
|
|
7
|
-
return page.items;
|
|
8
|
-
if (Array.isArray(page.data)) {
|
|
9
|
-
return page.data;
|
|
10
|
-
}
|
|
11
|
-
return [];
|
|
12
|
-
}
|
|
13
|
-
function extractNextCursor(page) {
|
|
14
|
-
return page.nextCursor ?? page.next_cursor ?? undefined;
|
|
15
|
-
}
|
|
16
|
-
function mapInvitee(invitee) {
|
|
17
|
-
const email = invitee.email;
|
|
18
|
-
const name = invitee.name;
|
|
19
|
-
if (!email && !name)
|
|
20
|
-
return;
|
|
21
|
-
return {
|
|
22
|
-
email,
|
|
23
|
-
name,
|
|
24
|
-
role: "attendee",
|
|
25
|
-
isExternal: invitee.is_external
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function matchRecordingId(meeting, targetId) {
|
|
29
|
-
return meeting.recordingId === targetId;
|
|
30
|
-
}
|
|
31
|
-
function durationSeconds(start, end) {
|
|
32
|
-
if (!start || !end)
|
|
33
|
-
return;
|
|
34
|
-
const startDate = start instanceof Date ? start : new Date(start);
|
|
35
|
-
const endDate = end instanceof Date ? end : new Date(end);
|
|
36
|
-
if (Number.isNaN(startDate.valueOf()) || Number.isNaN(endDate.valueOf())) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
return Math.max(0, (endDate.valueOf() - startDate.valueOf()) / 1000);
|
|
40
|
-
}
|
|
41
|
-
function mapTranscriptSegment(segment, index) {
|
|
42
|
-
return {
|
|
43
|
-
index,
|
|
44
|
-
speakerName: segment.speaker?.display_name ?? undefined,
|
|
45
|
-
speakerEmail: segment.speaker?.matched_calendar_invitee_email ?? undefined,
|
|
46
|
-
text: segment.text,
|
|
47
|
-
startTimeMs: parseTimestamp(segment.timestamp)
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function parseTimestamp(value) {
|
|
51
|
-
const parts = value.split(":").map((part) => Number(part));
|
|
52
|
-
if (parts.length !== 3 || parts.some((part) => Number.isNaN(part))) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const [hours = 0, minutes = 0, seconds = 0] = parts;
|
|
56
|
-
return (hours * 3600 + minutes * 60 + seconds) * 1000;
|
|
57
|
-
}
|
|
58
|
-
async function safeReadError(response) {
|
|
59
|
-
try {
|
|
60
|
-
const data = await response.json();
|
|
61
|
-
return data?.message ?? response.statusText;
|
|
62
|
-
} catch {
|
|
63
|
-
return response.statusText;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
export {
|
|
67
|
-
safeReadError,
|
|
68
|
-
parseTimestamp,
|
|
69
|
-
matchRecordingId,
|
|
70
|
-
mapTranscriptSegment,
|
|
71
|
-
mapInvitee,
|
|
72
|
-
extractNextCursor,
|
|
73
|
-
extractItems,
|
|
74
|
-
durationSeconds
|
|
75
|
-
};
|
|
2
|
+
var u=import.meta.require;function m(e){if(Array.isArray(e.items))return e.items;if(Array.isArray(e.data))return e.data;return[]}function d(e){return e.nextCursor??e.next_cursor??void 0}function c(e){let{email:t,name:n}=e;if(!t&&!n)return;return{email:t,name:n,role:"attendee",isExternal:e.is_external}}function f(e,t){return e.recordingId===t}function g(e,t){if(!e||!t)return;let n=e instanceof Date?e:new Date(e),r=t instanceof Date?t:new Date(t);if(Number.isNaN(n.valueOf())||Number.isNaN(r.valueOf()))return;return Math.max(0,(r.valueOf()-n.valueOf())/1000)}function p(e,t){return{index:t,speakerName:e.speaker?.display_name??void 0,speakerEmail:e.speaker?.matched_calendar_invitee_email??void 0,text:e.text,startTimeMs:s(e.timestamp)}}function s(e){let t=e.split(":").map((a)=>Number(a));if(t.length!==3||t.some((a)=>Number.isNaN(a)))return;let[n=0,r=0,i=0]=t;return(n*3600+r*60+i)*1000}async function l(e){try{return(await e.json())?.message??e.statusText}catch{return e.statusText}}export{l as safeReadError,s as parseTimestamp,f as matchRecordingId,p as mapTranscriptSegment,c as mapInvitee,d as extractNextCursor,m as extractItems,g as durationSeconds};
|
|
@@ -1,32 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
// src/impls/fathom-meeting-recorder.webhooks.ts
|
|
5
|
-
import { TriggeredFor } from "fathom-typescript/sdk/models/operations";
|
|
6
|
-
function normalizeWebhookHeaders(headers) {
|
|
7
|
-
const normalized = {};
|
|
8
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
9
|
-
if (value == null)
|
|
10
|
-
continue;
|
|
11
|
-
const normalizedKey = key.toLowerCase();
|
|
12
|
-
if (Array.isArray(value)) {
|
|
13
|
-
if (value.length === 0)
|
|
14
|
-
continue;
|
|
15
|
-
normalized[normalizedKey] = value.join(", ");
|
|
16
|
-
} else {
|
|
17
|
-
normalized[normalizedKey] = value;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return normalized;
|
|
21
|
-
}
|
|
22
|
-
function normalizeTriggeredFor(values) {
|
|
23
|
-
if (!values)
|
|
24
|
-
return;
|
|
25
|
-
const allowed = new Set(Object.values(TriggeredFor));
|
|
26
|
-
const normalized = values.map((value) => value.trim()).filter((value) => allowed.has(value));
|
|
27
|
-
return normalized.length ? normalized : undefined;
|
|
28
|
-
}
|
|
29
|
-
export {
|
|
30
|
-
normalizeWebhookHeaders,
|
|
31
|
-
normalizeTriggeredFor
|
|
32
|
-
};
|
|
2
|
+
var C=import.meta.require;import{TriggeredFor as B}from"fathom-typescript/sdk/models/operations";function G(q){let j={};for(let[x,b]of Object.entries(q)){if(b==null)continue;let A=x.toLowerCase();if(Array.isArray(b)){if(b.length===0)continue;j[A]=b.join(", ")}else j[A]=b}return j}function H(q){if(!q)return;let j=new Set(Object.values(B)),x=q.map((b)=>b.trim()).filter((b)=>j.has(b));return x.length?x:void 0}export{G as normalizeWebhookHeaders,H as normalizeTriggeredFor};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
// src/impls/fireflies-meeting-recorder.queries.ts
|
|
5
|
-
var TRANSCRIPTS_QUERY = `
|
|
2
|
+
var g=import.meta.require;var l=`
|
|
6
3
|
query Transcripts(
|
|
7
4
|
$limit: Int
|
|
8
5
|
$skip: Int
|
|
@@ -34,8 +31,7 @@ var TRANSCRIPTS_QUERY = `
|
|
|
34
31
|
transcript_url
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
var TRANSCRIPT_QUERY = `
|
|
34
|
+
`,n=`
|
|
39
35
|
query Transcript($transcriptId: String!) {
|
|
40
36
|
transcript(id: $transcriptId) {
|
|
41
37
|
id
|
|
@@ -53,8 +49,7 @@ var TRANSCRIPT_QUERY = `
|
|
|
53
49
|
transcript_url
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
|
-
|
|
57
|
-
var TRANSCRIPT_WITH_SEGMENTS_QUERY = `
|
|
52
|
+
`,x=`
|
|
58
53
|
query Transcript($transcriptId: String!) {
|
|
59
54
|
transcript(id: $transcriptId) {
|
|
60
55
|
id
|
|
@@ -80,198 +75,5 @@ var TRANSCRIPT_WITH_SEGMENTS_QUERY = `
|
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
77
|
}
|
|
83
|
-
`;
|
|
84
|
-
|
|
85
|
-
// src/impls/fireflies-meeting-recorder.utils.ts
|
|
86
|
-
import { Buffer } from "buffer";
|
|
87
|
-
import { timingSafeEqual } from "crypto";
|
|
88
|
-
function parseSeconds(value) {
|
|
89
|
-
if (value == null)
|
|
90
|
-
return;
|
|
91
|
-
const num = typeof value === "number" ? value : Number(value);
|
|
92
|
-
if (!Number.isFinite(num))
|
|
93
|
-
return;
|
|
94
|
-
return num * 1000;
|
|
95
|
-
}
|
|
96
|
-
function normalizeHeader(headers, key) {
|
|
97
|
-
const header = headers[key] ?? headers[key.toLowerCase()] ?? headers[key.toUpperCase()];
|
|
98
|
-
if (Array.isArray(header))
|
|
99
|
-
return header[0];
|
|
100
|
-
return header;
|
|
101
|
-
}
|
|
102
|
-
function safeCompareHex(a, b) {
|
|
103
|
-
try {
|
|
104
|
-
const aBuffer = Buffer.from(a, "hex");
|
|
105
|
-
const bBuffer = Buffer.from(b, "hex");
|
|
106
|
-
if (aBuffer.length !== bBuffer.length)
|
|
107
|
-
return false;
|
|
108
|
-
return timingSafeEqual(aBuffer, bBuffer);
|
|
109
|
-
} catch {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
async function safeReadError(response) {
|
|
114
|
-
try {
|
|
115
|
-
const data = await response.json();
|
|
116
|
-
return data?.message ?? response.statusText;
|
|
117
|
-
} catch {
|
|
118
|
-
return response.statusText;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// src/impls/fireflies-meeting-recorder.ts
|
|
123
|
-
import { createHmac } from "crypto";
|
|
124
|
-
var DEFAULT_BASE_URL = "https://api.fireflies.ai/graphql";
|
|
125
|
-
|
|
126
|
-
class FirefliesMeetingRecorderProvider {
|
|
127
|
-
apiKey;
|
|
128
|
-
baseUrl;
|
|
129
|
-
defaultPageSize;
|
|
130
|
-
webhookSecret;
|
|
131
|
-
constructor(options) {
|
|
132
|
-
this.apiKey = options.apiKey;
|
|
133
|
-
this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
134
|
-
this.defaultPageSize = options.pageSize;
|
|
135
|
-
this.webhookSecret = options.webhookSecret;
|
|
136
|
-
}
|
|
137
|
-
async listMeetings(params) {
|
|
138
|
-
const limit = params.pageSize ?? this.defaultPageSize ?? 25;
|
|
139
|
-
const skip = params.cursor ? Number(params.cursor) : 0;
|
|
140
|
-
const data = await this.query(TRANSCRIPTS_QUERY, {
|
|
141
|
-
limit,
|
|
142
|
-
skip: Number.isFinite(skip) ? skip : 0,
|
|
143
|
-
fromDate: params.from,
|
|
144
|
-
toDate: params.to,
|
|
145
|
-
keyword: params.query,
|
|
146
|
-
scope: params.query ? "all" : undefined
|
|
147
|
-
});
|
|
148
|
-
const meetings = data.transcripts.map((transcript) => this.mapTranscriptToMeeting(transcript, params));
|
|
149
|
-
const nextCursor = meetings.length === limit ? String(skip + limit) : undefined;
|
|
150
|
-
return {
|
|
151
|
-
meetings,
|
|
152
|
-
nextCursor,
|
|
153
|
-
hasMore: Boolean(nextCursor)
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
async getMeeting(params) {
|
|
157
|
-
const data = await this.query(TRANSCRIPT_QUERY, {
|
|
158
|
-
transcriptId: params.meetingId
|
|
159
|
-
});
|
|
160
|
-
return this.mapTranscriptToMeeting(data.transcript, params);
|
|
161
|
-
}
|
|
162
|
-
async getTranscript(params) {
|
|
163
|
-
const data = await this.query(TRANSCRIPT_WITH_SEGMENTS_QUERY, { transcriptId: params.meetingId });
|
|
164
|
-
const transcript = data.transcript;
|
|
165
|
-
const segments = (transcript.sentences ?? []).map((segment) => this.mapSentence(segment));
|
|
166
|
-
return {
|
|
167
|
-
id: transcript.id,
|
|
168
|
-
meetingId: transcript.id,
|
|
169
|
-
tenantId: params.tenantId,
|
|
170
|
-
connectionId: params.connectionId ?? "unknown",
|
|
171
|
-
externalId: transcript.id,
|
|
172
|
-
format: "segments",
|
|
173
|
-
text: segments.map((segment) => segment.text).join(`
|
|
174
|
-
`),
|
|
175
|
-
segments,
|
|
176
|
-
generatedAt: transcript.dateString ?? undefined,
|
|
177
|
-
sourceUrl: transcript.transcript_url ?? undefined,
|
|
178
|
-
metadata: {
|
|
179
|
-
meetingLink: transcript.meeting_link,
|
|
180
|
-
durationMinutes: transcript.duration
|
|
181
|
-
},
|
|
182
|
-
raw: transcript
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
async parseWebhook(request) {
|
|
186
|
-
const payload = request.parsedBody ?? JSON.parse(request.rawBody);
|
|
187
|
-
const body = payload;
|
|
188
|
-
const verified = this.webhookSecret ? await this.verifyWebhook(request) : undefined;
|
|
189
|
-
return {
|
|
190
|
-
providerKey: "meeting-recorder.fireflies",
|
|
191
|
-
eventType: body.eventType,
|
|
192
|
-
meetingId: body.meetingId,
|
|
193
|
-
transcriptId: body.meetingId,
|
|
194
|
-
verified,
|
|
195
|
-
payload,
|
|
196
|
-
metadata: {
|
|
197
|
-
clientReferenceId: body.clientReferenceId
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
async verifyWebhook(request) {
|
|
202
|
-
if (!this.webhookSecret)
|
|
203
|
-
return true;
|
|
204
|
-
const signatureHeader = normalizeHeader(request.headers, "x-hub-signature");
|
|
205
|
-
if (!signatureHeader)
|
|
206
|
-
return false;
|
|
207
|
-
const signature = signatureHeader.replace(/^sha256=/, "");
|
|
208
|
-
const digest = createHmac("sha256", this.webhookSecret).update(request.rawBody).digest("hex");
|
|
209
|
-
return safeCompareHex(digest, signature);
|
|
210
|
-
}
|
|
211
|
-
mapTranscriptToMeeting(transcript, params) {
|
|
212
|
-
const connectionId = params.connectionId ?? "unknown";
|
|
213
|
-
const organizer = transcript.organizer_email ? { email: transcript.organizer_email, role: "organizer" } : undefined;
|
|
214
|
-
const attendees = transcript.meeting_attendees?.length ? transcript.meeting_attendees.map((attendee) => this.mapAttendee(attendee)) : transcript.participants?.map((email) => ({ email, role: "attendee" }));
|
|
215
|
-
return {
|
|
216
|
-
id: transcript.id,
|
|
217
|
-
tenantId: params.tenantId,
|
|
218
|
-
connectionId,
|
|
219
|
-
externalId: transcript.id,
|
|
220
|
-
title: transcript.title ?? undefined,
|
|
221
|
-
organizer,
|
|
222
|
-
invitees: attendees,
|
|
223
|
-
participants: attendees,
|
|
224
|
-
scheduledStartAt: transcript.dateString ?? undefined,
|
|
225
|
-
recordingStartAt: transcript.dateString ?? undefined,
|
|
226
|
-
durationSeconds: transcript.duration ? transcript.duration * 60 : undefined,
|
|
227
|
-
meetingUrl: transcript.meeting_link ?? transcript.transcript_url ?? undefined,
|
|
228
|
-
transcriptAvailable: Boolean(transcript.transcript_url),
|
|
229
|
-
sourcePlatform: "fireflies",
|
|
230
|
-
metadata: {
|
|
231
|
-
transcriptUrl: transcript.transcript_url
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
mapAttendee(attendee) {
|
|
236
|
-
return {
|
|
237
|
-
name: attendee.name ?? attendee.displayName ?? undefined,
|
|
238
|
-
email: attendee.email ?? undefined,
|
|
239
|
-
role: "attendee"
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
mapSentence(segment) {
|
|
243
|
-
return {
|
|
244
|
-
index: segment.index ?? undefined,
|
|
245
|
-
speakerId: segment.speaker_id ?? undefined,
|
|
246
|
-
speakerName: segment.speaker_name ?? undefined,
|
|
247
|
-
text: segment.text,
|
|
248
|
-
startTimeMs: parseSeconds(segment.start_time),
|
|
249
|
-
endTimeMs: parseSeconds(segment.end_time)
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
async query(query, variables) {
|
|
253
|
-
const response = await fetch(this.baseUrl, {
|
|
254
|
-
method: "POST",
|
|
255
|
-
headers: {
|
|
256
|
-
"Content-Type": "application/json",
|
|
257
|
-
Authorization: `Bearer ${this.apiKey}`
|
|
258
|
-
},
|
|
259
|
-
body: JSON.stringify({ query, variables })
|
|
260
|
-
});
|
|
261
|
-
if (!response.ok) {
|
|
262
|
-
const message = await safeReadError(response);
|
|
263
|
-
throw new Error(`Fireflies API error (${response.status}): ${message}`);
|
|
264
|
-
}
|
|
265
|
-
const result = await response.json();
|
|
266
|
-
if (result.errors?.length) {
|
|
267
|
-
throw new Error(result.errors.map((error) => error.message).join("; "));
|
|
268
|
-
}
|
|
269
|
-
if (!result.data) {
|
|
270
|
-
throw new Error("Fireflies API returned empty data payload.");
|
|
271
|
-
}
|
|
272
|
-
return result.data;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
export {
|
|
276
|
-
FirefliesMeetingRecorderProvider
|
|
277
|
-
};
|
|
78
|
+
`;import{Buffer as D}from"buffer";import{timingSafeEqual as h}from"crypto";function _(i){if(i==null)return;let u=typeof i==="number"?i:Number(i);if(!Number.isFinite(u))return;return u*1000}function T(i,u){let f=i[u]??i[u.toLowerCase()]??i[u.toUpperCase()];if(Array.isArray(f))return f[0];return f}function k(i,u){try{let f=D.from(i,"hex"),o=D.from(u,"hex");if(f.length!==o.length)return!1;return h(f,o)}catch{return!1}}async function y(i){try{return(await i.json())?.message??i.statusText}catch{return i.statusText}}import{createHmac as w}from"crypto";var I="https://api.fireflies.ai/graphql";class N{apiKey;baseUrl;defaultPageSize;webhookSecret;constructor(i){this.apiKey=i.apiKey,this.baseUrl=i.baseUrl??I,this.defaultPageSize=i.pageSize,this.webhookSecret=i.webhookSecret}async listMeetings(i){let u=i.pageSize??this.defaultPageSize??25,f=i.cursor?Number(i.cursor):0,$=(await this.query(l,{limit:u,skip:Number.isFinite(f)?f:0,fromDate:i.from,toDate:i.to,keyword:i.query,scope:i.query?"all":void 0})).transcripts.map((S)=>this.mapTranscriptToMeeting(S,i)),d=$.length===u?String(f+u):void 0;return{meetings:$,nextCursor:d,hasMore:Boolean(d)}}async getMeeting(i){let u=await this.query(n,{transcriptId:i.meetingId});return this.mapTranscriptToMeeting(u.transcript,i)}async getTranscript(i){let f=(await this.query(x,{transcriptId:i.meetingId})).transcript,o=(f.sentences??[]).map(($)=>this.mapSentence($));return{id:f.id,meetingId:f.id,tenantId:i.tenantId,connectionId:i.connectionId??"unknown",externalId:f.id,format:"segments",text:o.map(($)=>$.text).join(`
|
|
79
|
+
`),segments:o,generatedAt:f.dateString??void 0,sourceUrl:f.transcript_url??void 0,metadata:{meetingLink:f.meeting_link,durationMinutes:f.duration},raw:f}}async parseWebhook(i){let u=i.parsedBody??JSON.parse(i.rawBody),f=u,o=this.webhookSecret?await this.verifyWebhook(i):void 0;return{providerKey:"meeting-recorder.fireflies",eventType:f.eventType,meetingId:f.meetingId,transcriptId:f.meetingId,verified:o,payload:u,metadata:{clientReferenceId:f.clientReferenceId}}}async verifyWebhook(i){if(!this.webhookSecret)return!0;let u=T(i.headers,"x-hub-signature");if(!u)return!1;let f=u.replace(/^sha256=/,""),o=w("sha256",this.webhookSecret).update(i.rawBody).digest("hex");return k(o,f)}mapTranscriptToMeeting(i,u){let f=u.connectionId??"unknown",o=i.organizer_email?{email:i.organizer_email,role:"organizer"}:void 0,$=i.meeting_attendees?.length?i.meeting_attendees.map((d)=>this.mapAttendee(d)):i.participants?.map((d)=>({email:d,role:"attendee"}));return{id:i.id,tenantId:u.tenantId,connectionId:f,externalId:i.id,title:i.title??void 0,organizer:o,invitees:$,participants:$,scheduledStartAt:i.dateString??void 0,recordingStartAt:i.dateString??void 0,durationSeconds:i.duration?i.duration*60:void 0,meetingUrl:i.meeting_link??i.transcript_url??void 0,transcriptAvailable:Boolean(i.transcript_url),sourcePlatform:"fireflies",metadata:{transcriptUrl:i.transcript_url}}}mapAttendee(i){return{name:i.name??i.displayName??void 0,email:i.email??void 0,role:"attendee"}}mapSentence(i){return{index:i.index??void 0,speakerId:i.speaker_id??void 0,speakerName:i.speaker_name??void 0,text:i.text,startTimeMs:_(i.start_time),endTimeMs:_(i.end_time)}}async query(i,u){let f=await fetch(this.baseUrl,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({query:i,variables:u})});if(!f.ok){let $=await y(f);throw Error(`Fireflies API error (${f.status}): ${$}`)}let o=await f.json();if(o.errors?.length)throw Error(o.errors.map(($)=>$.message).join("; "));if(!o.data)throw Error("Fireflies API returned empty data payload.");return o.data}}export{N as FirefliesMeetingRecorderProvider};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
// src/impls/fireflies-meeting-recorder.queries.ts
|
|
5
|
-
var TRANSCRIPTS_QUERY = `
|
|
2
|
+
var t=import.meta.require;var i=`
|
|
6
3
|
query Transcripts(
|
|
7
4
|
$limit: Int
|
|
8
5
|
$skip: Int
|
|
@@ -34,8 +31,7 @@ var TRANSCRIPTS_QUERY = `
|
|
|
34
31
|
transcript_url
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
var TRANSCRIPT_QUERY = `
|
|
34
|
+
`,r=`
|
|
39
35
|
query Transcript($transcriptId: String!) {
|
|
40
36
|
transcript(id: $transcriptId) {
|
|
41
37
|
id
|
|
@@ -53,8 +49,7 @@ var TRANSCRIPT_QUERY = `
|
|
|
53
49
|
transcript_url
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
|
-
|
|
57
|
-
var TRANSCRIPT_WITH_SEGMENTS_QUERY = `
|
|
52
|
+
`,a=`
|
|
58
53
|
query Transcript($transcriptId: String!) {
|
|
59
54
|
transcript(id: $transcriptId) {
|
|
60
55
|
id
|
|
@@ -80,9 +75,4 @@ var TRANSCRIPT_WITH_SEGMENTS_QUERY = `
|
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
77
|
}
|
|
83
|
-
`;
|
|
84
|
-
export {
|
|
85
|
-
TRANSCRIPT_WITH_SEGMENTS_QUERY,
|
|
86
|
-
TRANSCRIPT_QUERY,
|
|
87
|
-
TRANSCRIPTS_QUERY
|
|
88
|
-
};
|
|
78
|
+
`;export{a as TRANSCRIPT_WITH_SEGMENTS_QUERY,r as TRANSCRIPT_QUERY,i as TRANSCRIPTS_QUERY};
|
|
@@ -1,45 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
// src/impls/fireflies-meeting-recorder.utils.ts
|
|
5
|
-
import { Buffer } from "buffer";
|
|
6
|
-
import { timingSafeEqual } from "crypto";
|
|
7
|
-
function parseSeconds(value) {
|
|
8
|
-
if (value == null)
|
|
9
|
-
return;
|
|
10
|
-
const num = typeof value === "number" ? value : Number(value);
|
|
11
|
-
if (!Number.isFinite(num))
|
|
12
|
-
return;
|
|
13
|
-
return num * 1000;
|
|
14
|
-
}
|
|
15
|
-
function normalizeHeader(headers, key) {
|
|
16
|
-
const header = headers[key] ?? headers[key.toLowerCase()] ?? headers[key.toUpperCase()];
|
|
17
|
-
if (Array.isArray(header))
|
|
18
|
-
return header[0];
|
|
19
|
-
return header;
|
|
20
|
-
}
|
|
21
|
-
function safeCompareHex(a, b) {
|
|
22
|
-
try {
|
|
23
|
-
const aBuffer = Buffer.from(a, "hex");
|
|
24
|
-
const bBuffer = Buffer.from(b, "hex");
|
|
25
|
-
if (aBuffer.length !== bBuffer.length)
|
|
26
|
-
return false;
|
|
27
|
-
return timingSafeEqual(aBuffer, bBuffer);
|
|
28
|
-
} catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async function safeReadError(response) {
|
|
33
|
-
try {
|
|
34
|
-
const data = await response.json();
|
|
35
|
-
return data?.message ?? response.statusText;
|
|
36
|
-
} catch {
|
|
37
|
-
return response.statusText;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export {
|
|
41
|
-
safeReadError,
|
|
42
|
-
safeCompareHex,
|
|
43
|
-
parseSeconds,
|
|
44
|
-
normalizeHeader
|
|
45
|
-
};
|
|
2
|
+
var o=import.meta.require;import{Buffer as i}from"buffer";import{timingSafeEqual as s}from"crypto";function m(r){if(r==null)return;let n=typeof r==="number"?r:Number(r);if(!Number.isFinite(n))return;return n*1000}function c(r,n){let e=r[n]??r[n.toLowerCase()]??r[n.toUpperCase()];if(Array.isArray(e))return e[0];return e}function d(r,n){try{let e=i.from(r,"hex"),t=i.from(n,"hex");if(e.length!==t.length)return!1;return s(e,t)}catch{return!1}}async function g(r){try{return(await r.json())?.message??r.statusText}catch{return r.statusText}}export{g as safeReadError,d as safeCompareHex,m as parseSeconds,c as normalizeHeader};
|
|
@@ -1,100 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
// src/impls/gcs-storage.ts
|
|
5
|
-
import { Storage } from "@google-cloud/storage";
|
|
6
|
-
|
|
7
|
-
class GoogleCloudStorageProvider {
|
|
8
|
-
storage;
|
|
9
|
-
bucketName;
|
|
10
|
-
constructor(options) {
|
|
11
|
-
this.storage = options.storage ?? new Storage(options.clientOptions ?? undefined);
|
|
12
|
-
this.bucketName = options.bucket;
|
|
13
|
-
}
|
|
14
|
-
async putObject(input) {
|
|
15
|
-
const bucketName = input.bucket ?? this.bucketName;
|
|
16
|
-
const bucket = this.storage.bucket(bucketName);
|
|
17
|
-
const file = bucket.file(input.key);
|
|
18
|
-
const buffer = toBuffer(input.data);
|
|
19
|
-
await file.save(buffer, {
|
|
20
|
-
resumable: false,
|
|
21
|
-
contentType: input.contentType,
|
|
22
|
-
metadata: input.metadata
|
|
23
|
-
});
|
|
24
|
-
if (input.makePublic) {
|
|
25
|
-
await file.makePublic();
|
|
26
|
-
}
|
|
27
|
-
const [metadata] = await file.getMetadata();
|
|
28
|
-
return toMetadata(metadata);
|
|
29
|
-
}
|
|
30
|
-
async getObject(input) {
|
|
31
|
-
const bucketName = input.bucket ?? this.bucketName;
|
|
32
|
-
const bucket = this.storage.bucket(bucketName);
|
|
33
|
-
const file = bucket.file(input.key);
|
|
34
|
-
const [exists] = await file.exists();
|
|
35
|
-
if (!exists)
|
|
36
|
-
return null;
|
|
37
|
-
const [contents] = await file.download();
|
|
38
|
-
const [metadata] = await file.getMetadata();
|
|
39
|
-
return {
|
|
40
|
-
...toMetadata(metadata),
|
|
41
|
-
data: new Uint8Array(contents)
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
async deleteObject(input) {
|
|
45
|
-
const bucketName = input.bucket ?? this.bucketName;
|
|
46
|
-
const bucket = this.storage.bucket(bucketName);
|
|
47
|
-
const file = bucket.file(input.key);
|
|
48
|
-
await file.delete({ ignoreNotFound: true });
|
|
49
|
-
}
|
|
50
|
-
async generateSignedUrl(options) {
|
|
51
|
-
const bucketName = options.bucket ?? this.bucketName;
|
|
52
|
-
const bucket = this.storage.bucket(bucketName);
|
|
53
|
-
const file = bucket.file(options.key);
|
|
54
|
-
const action = options.method === "PUT" ? "write" : "read";
|
|
55
|
-
const expires = Date.now() + options.expiresInSeconds * 1000;
|
|
56
|
-
const [url] = await file.getSignedUrl({
|
|
57
|
-
action,
|
|
58
|
-
expires,
|
|
59
|
-
contentType: options.contentType
|
|
60
|
-
});
|
|
61
|
-
return { url, expiresAt: new Date(expires) };
|
|
62
|
-
}
|
|
63
|
-
async listObjects(query) {
|
|
64
|
-
const bucketName = query.bucket ?? this.bucketName;
|
|
65
|
-
const bucket = this.storage.bucket(bucketName);
|
|
66
|
-
const [files, nextQuery, response] = await bucket.getFiles({
|
|
67
|
-
prefix: query.prefix,
|
|
68
|
-
maxResults: query.maxResults,
|
|
69
|
-
pageToken: query.pageToken
|
|
70
|
-
});
|
|
71
|
-
const nextTokenFromQuery = typeof nextQuery === "object" && nextQuery !== null && "pageToken" in nextQuery ? nextQuery.pageToken : undefined;
|
|
72
|
-
const nextTokenFromResponse = response && typeof response === "object" && "nextPageToken" in response ? response.nextPageToken : undefined;
|
|
73
|
-
return {
|
|
74
|
-
objects: files.map((file) => toMetadata(file.metadata)),
|
|
75
|
-
nextPageToken: nextTokenFromQuery ?? nextTokenFromResponse ?? undefined
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function toBuffer(data) {
|
|
80
|
-
if (data instanceof Uint8Array) {
|
|
81
|
-
return Buffer.from(data);
|
|
82
|
-
}
|
|
83
|
-
return Buffer.from(data);
|
|
84
|
-
}
|
|
85
|
-
function toMetadata(metadata) {
|
|
86
|
-
const meta = metadata;
|
|
87
|
-
return {
|
|
88
|
-
bucket: String(meta.bucket ?? ""),
|
|
89
|
-
key: String(meta.name ?? ""),
|
|
90
|
-
sizeBytes: meta.size ? Number(meta.size) : undefined,
|
|
91
|
-
contentType: meta.contentType ? String(meta.contentType) : undefined,
|
|
92
|
-
etag: meta.etag ? String(meta.etag) : undefined,
|
|
93
|
-
checksum: meta.md5Hash ? String(meta.md5Hash) : undefined,
|
|
94
|
-
lastModified: meta.updated ? new Date(String(meta.updated)) : undefined,
|
|
95
|
-
metadata: meta.metadata
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
export {
|
|
99
|
-
GoogleCloudStorageProvider
|
|
100
|
-
};
|
|
2
|
+
var k=import.meta.require;import{Storage as d}from"@google-cloud/storage";class b{storage;bucketName;constructor(e){this.storage=e.storage??new d(e.clientOptions??void 0),this.bucketName=e.bucket}async putObject(e){let t=e.bucket??this.bucketName,n=this.storage.bucket(t).file(e.key),o=g(e.data);if(await n.save(o,{resumable:!1,contentType:e.contentType,metadata:e.metadata}),e.makePublic)await n.makePublic();let[a]=await n.getMetadata();return c(a)}async getObject(e){let t=e.bucket??this.bucketName,n=this.storage.bucket(t).file(e.key),[o]=await n.exists();if(!o)return null;let[a]=await n.download(),[r]=await n.getMetadata();return{...c(r),data:new Uint8Array(a)}}async deleteObject(e){let t=e.bucket??this.bucketName;await this.storage.bucket(t).file(e.key).delete({ignoreNotFound:!0})}async generateSignedUrl(e){let t=e.bucket??this.bucketName,n=this.storage.bucket(t).file(e.key),o=e.method==="PUT"?"write":"read",a=Date.now()+e.expiresInSeconds*1000,[r]=await n.getSignedUrl({action:o,expires:a,contentType:e.contentType});return{url:r,expiresAt:new Date(a)}}async listObjects(e){let t=e.bucket??this.bucketName,s=this.storage.bucket(t),[n,o,a]=await s.getFiles({prefix:e.prefix,maxResults:e.maxResults,pageToken:e.pageToken}),r=typeof o==="object"&&o!==null&&"pageToken"in o?o.pageToken:void 0,i=a&&typeof a==="object"&&"nextPageToken"in a?a.nextPageToken:void 0;return{objects:n.map((u)=>c(u.metadata)),nextPageToken:r??i??void 0}}}function g(e){if(e instanceof Uint8Array)return Buffer.from(e);return Buffer.from(e)}function c(e){let t=e;return{bucket:String(t.bucket??""),key:String(t.name??""),sizeBytes:t.size?Number(t.size):void 0,contentType:t.contentType?String(t.contentType):void 0,etag:t.etag?String(t.etag):void 0,checksum:t.md5Hash?String(t.md5Hash):void 0,lastModified:t.updated?new Date(String(t.updated)):void 0,metadata:t.metadata}}export{b as GoogleCloudStorageProvider};
|