@contractspec/integration.providers-impls 1.56.1 → 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.
- package/README.md +115 -1
- package/dist/analytics.d.ts +2 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +3 -0
- package/dist/calendar.d.ts +1 -7
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +3 -3
- package/dist/database.d.ts +2 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +3 -0
- package/dist/email.d.ts +1 -7
- package/dist/email.d.ts.map +1 -1
- package/dist/email.js +3 -3
- package/dist/embedding.d.ts +1 -7
- package/dist/embedding.d.ts.map +1 -1
- package/dist/embedding.js +3 -3
- package/dist/impls/elevenlabs-voice.d.ts +14 -18
- package/dist/impls/elevenlabs-voice.d.ts.map +1 -1
- package/dist/impls/elevenlabs-voice.js +98 -88
- package/dist/impls/fal-voice.d.ts +25 -0
- package/dist/impls/fal-voice.d.ts.map +1 -0
- package/dist/impls/fal-voice.js +113 -0
- package/dist/impls/fathom-meeting-recorder.d.ts +38 -0
- package/dist/impls/fathom-meeting-recorder.d.ts.map +1 -0
- package/dist/impls/fathom-meeting-recorder.js +288 -0
- package/dist/impls/fathom-meeting-recorder.mapper.d.ts +5 -0
- package/dist/impls/fathom-meeting-recorder.mapper.d.ts.map +1 -0
- package/dist/impls/fathom-meeting-recorder.mapper.js +106 -0
- package/dist/impls/fathom-meeting-recorder.types.d.ts +20 -0
- package/dist/impls/fathom-meeting-recorder.types.d.ts.map +1 -0
- package/dist/impls/fathom-meeting-recorder.types.js +1 -0
- package/dist/impls/fathom-meeting-recorder.utils.d.ts +11 -0
- package/dist/impls/fathom-meeting-recorder.utils.d.ts.map +1 -0
- package/dist/impls/fathom-meeting-recorder.utils.js +73 -0
- package/dist/impls/fathom-meeting-recorder.webhooks.d.ts +4 -0
- package/dist/impls/fathom-meeting-recorder.webhooks.d.ts.map +1 -0
- package/dist/impls/fathom-meeting-recorder.webhooks.js +30 -0
- package/dist/impls/fireflies-meeting-recorder.d.ts +24 -0
- package/dist/impls/fireflies-meeting-recorder.d.ts.map +1 -0
- package/dist/impls/fireflies-meeting-recorder.js +275 -0
- package/dist/impls/fireflies-meeting-recorder.queries.d.ts +4 -0
- package/dist/impls/fireflies-meeting-recorder.queries.d.ts.map +1 -0
- package/dist/impls/fireflies-meeting-recorder.queries.js +86 -0
- package/dist/impls/fireflies-meeting-recorder.types.d.ts +32 -0
- package/dist/impls/fireflies-meeting-recorder.types.d.ts.map +1 -0
- package/dist/impls/fireflies-meeting-recorder.types.js +1 -0
- package/dist/impls/fireflies-meeting-recorder.utils.d.ts +5 -0
- package/dist/impls/fireflies-meeting-recorder.utils.d.ts.map +1 -0
- package/dist/impls/fireflies-meeting-recorder.utils.js +43 -0
- package/dist/impls/gcs-storage.d.ts +18 -22
- package/dist/impls/gcs-storage.d.ts.map +1 -1
- package/dist/impls/gcs-storage.js +92 -84
- package/dist/impls/gmail-inbound.d.ts +20 -24
- package/dist/impls/gmail-inbound.d.ts.map +1 -1
- package/dist/impls/gmail-inbound.js +212 -185
- package/dist/impls/gmail-outbound.d.ts +12 -16
- package/dist/impls/gmail-outbound.d.ts.map +1 -1
- package/dist/impls/gmail-outbound.js +126 -92
- package/dist/impls/google-calendar.d.ts +17 -21
- package/dist/impls/google-calendar.d.ts.map +1 -1
- package/dist/impls/google-calendar.js +182 -145
- package/dist/impls/gradium-voice.d.ts +24 -0
- package/dist/impls/gradium-voice.d.ts.map +1 -0
- package/dist/impls/gradium-voice.js +91 -0
- package/dist/impls/granola-meeting-recorder.d.ts +34 -0
- package/dist/impls/granola-meeting-recorder.d.ts.map +1 -0
- package/dist/impls/granola-meeting-recorder.js +513 -0
- package/dist/impls/granola-meeting-recorder.mcp.d.ts +25 -0
- package/dist/impls/granola-meeting-recorder.mcp.d.ts.map +1 -0
- package/dist/impls/granola-meeting-recorder.mcp.js +279 -0
- package/dist/impls/granola-meeting-recorder.types.d.ts +61 -0
- package/dist/impls/granola-meeting-recorder.types.d.ts.map +1 -0
- package/dist/impls/granola-meeting-recorder.types.js +1 -0
- package/dist/impls/index.d.ts +28 -15
- package/dist/impls/index.d.ts.map +1 -0
- package/dist/impls/index.js +4659 -16
- package/dist/impls/jira.d.ts +21 -0
- package/dist/impls/jira.d.ts.map +1 -0
- package/dist/impls/jira.js +125 -0
- package/dist/impls/linear.d.ts +20 -0
- package/dist/impls/linear.d.ts.map +1 -0
- package/dist/impls/linear.js +84 -0
- package/dist/impls/mistral-embedding.d.ts +17 -21
- package/dist/impls/mistral-embedding.d.ts.map +1 -1
- package/dist/impls/mistral-embedding.js +41 -39
- package/dist/impls/mistral-llm.d.ts +25 -29
- package/dist/impls/mistral-llm.d.ts.map +1 -1
- package/dist/impls/mistral-llm.js +266 -244
- package/dist/impls/notion.d.ts +23 -0
- package/dist/impls/notion.d.ts.map +1 -0
- package/dist/impls/notion.js +161 -0
- package/dist/impls/posthog-reader.d.ts +22 -0
- package/dist/impls/posthog-reader.d.ts.map +1 -0
- package/dist/impls/posthog-reader.js +160 -0
- package/dist/impls/posthog-utils.d.ts +5 -0
- package/dist/impls/posthog-utils.d.ts.map +1 -0
- package/dist/impls/posthog-utils.js +39 -0
- package/dist/impls/posthog.d.ts +36 -0
- package/dist/impls/posthog.d.ts.map +1 -0
- package/dist/impls/posthog.js +323 -0
- package/dist/impls/postmark-email.d.ts +13 -17
- package/dist/impls/postmark-email.d.ts.map +1 -1
- package/dist/impls/postmark-email.js +55 -50
- package/dist/impls/powens-client.d.ts +111 -114
- package/dist/impls/powens-client.d.ts.map +1 -1
- package/dist/impls/powens-client.js +194 -170
- package/dist/impls/powens-openbanking.d.ts +22 -26
- package/dist/impls/powens-openbanking.d.ts.map +1 -1
- package/dist/impls/powens-openbanking.js +425 -217
- package/dist/impls/provider-factory.d.ts +29 -25
- package/dist/impls/provider-factory.d.ts.map +1 -1
- package/dist/impls/provider-factory.js +4074 -136
- package/dist/impls/qdrant-vector.d.ts +18 -22
- package/dist/impls/qdrant-vector.d.ts.map +1 -1
- package/dist/impls/qdrant-vector.js +76 -69
- package/dist/impls/stripe-payments.d.ts +22 -26
- package/dist/impls/stripe-payments.d.ts.map +1 -1
- package/dist/impls/stripe-payments.js +219 -193
- package/dist/impls/supabase-psql.d.ts +24 -0
- package/dist/impls/supabase-psql.d.ts.map +1 -0
- package/dist/impls/supabase-psql.js +151 -0
- package/dist/impls/supabase-vector.d.ts +32 -0
- package/dist/impls/supabase-vector.d.ts.map +1 -0
- package/dist/impls/supabase-vector.js +324 -0
- package/dist/impls/tldv-meeting-recorder.d.ts +21 -0
- package/dist/impls/tldv-meeting-recorder.d.ts.map +1 -0
- package/dist/impls/tldv-meeting-recorder.js +146 -0
- package/dist/impls/twilio-sms.d.ts +14 -17
- package/dist/impls/twilio-sms.d.ts.map +1 -1
- package/dist/impls/twilio-sms.js +62 -55
- package/dist/index.d.ts +15 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4700 -69
- package/dist/llm.d.ts +1 -7
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +3 -3
- package/dist/meeting-recorder.d.ts +2 -0
- package/dist/meeting-recorder.d.ts.map +1 -0
- package/dist/meeting-recorder.js +3 -0
- package/dist/node/analytics.js +2 -0
- package/dist/node/calendar.js +2 -0
- package/dist/node/database.js +2 -0
- package/dist/node/email.js +2 -0
- package/dist/node/embedding.js +2 -0
- package/dist/node/impls/elevenlabs-voice.js +102 -0
- package/dist/node/impls/fal-voice.js +112 -0
- package/dist/node/impls/fathom-meeting-recorder.js +287 -0
- package/dist/node/impls/fathom-meeting-recorder.mapper.js +105 -0
- package/dist/node/impls/fathom-meeting-recorder.types.js +0 -0
- package/dist/node/impls/fathom-meeting-recorder.utils.js +72 -0
- package/dist/node/impls/fathom-meeting-recorder.webhooks.js +29 -0
- package/dist/node/impls/fireflies-meeting-recorder.js +274 -0
- package/dist/node/impls/fireflies-meeting-recorder.queries.js +85 -0
- package/dist/node/impls/fireflies-meeting-recorder.types.js +0 -0
- package/dist/node/impls/fireflies-meeting-recorder.utils.js +42 -0
- package/dist/node/impls/gcs-storage.js +97 -0
- package/dist/node/impls/gmail-inbound.js +227 -0
- package/dist/node/impls/gmail-outbound.js +139 -0
- package/dist/node/impls/google-calendar.js +191 -0
- package/dist/node/impls/gradium-voice.js +90 -0
- package/dist/node/impls/granola-meeting-recorder.js +512 -0
- package/dist/node/impls/granola-meeting-recorder.mcp.js +278 -0
- package/dist/node/impls/granola-meeting-recorder.types.js +0 -0
- package/dist/node/impls/index.js +4658 -0
- package/dist/node/impls/jira.js +124 -0
- package/dist/node/impls/linear.js +83 -0
- package/dist/node/impls/mistral-embedding.js +43 -0
- package/dist/node/impls/mistral-llm.js +269 -0
- package/dist/node/impls/notion.js +160 -0
- package/dist/node/impls/posthog-reader.js +159 -0
- package/dist/node/impls/posthog-utils.js +38 -0
- package/dist/node/impls/posthog.js +322 -0
- package/dist/node/impls/postmark-email.js +60 -0
- package/dist/node/impls/powens-client.js +195 -0
- package/dist/node/impls/powens-openbanking.js +426 -0
- package/dist/node/impls/provider-factory.js +4080 -0
- package/dist/node/impls/qdrant-vector.js +78 -0
- package/dist/node/impls/stripe-payments.js +228 -0
- package/dist/node/impls/supabase-psql.js +150 -0
- package/dist/node/impls/supabase-vector.js +323 -0
- package/dist/node/impls/tldv-meeting-recorder.js +145 -0
- package/dist/node/impls/twilio-sms.js +65 -0
- package/dist/node/index.js +4699 -0
- package/dist/node/llm.js +2 -0
- package/dist/node/meeting-recorder.js +2 -0
- package/dist/node/openbanking.js +2 -0
- package/dist/node/payments.js +2 -0
- package/dist/node/project-management.js +2 -0
- package/dist/node/runtime.js +0 -0
- package/dist/node/secrets/provider.js +11 -0
- package/dist/node/sms.js +2 -0
- package/dist/node/storage.js +2 -0
- package/dist/node/vector-store.js +2 -0
- package/dist/node/voice.js +2 -0
- package/dist/openbanking.d.ts +1 -7
- package/dist/openbanking.d.ts.map +1 -1
- package/dist/openbanking.js +3 -3
- package/dist/payments.d.ts +1 -7
- package/dist/payments.d.ts.map +1 -1
- package/dist/payments.js +3 -3
- package/dist/project-management.d.ts +2 -0
- package/dist/project-management.d.ts.map +1 -0
- package/dist/project-management.js +3 -0
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/secrets/provider.d.ts +3 -2
- package/dist/secrets/provider.d.ts.map +1 -0
- package/dist/secrets/provider.js +12 -3
- package/dist/sms.d.ts +1 -7
- package/dist/sms.d.ts.map +1 -1
- package/dist/sms.js +3 -3
- package/dist/storage.d.ts +1 -7
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +3 -3
- package/dist/vector-store.d.ts +1 -7
- package/dist/vector-store.d.ts.map +1 -1
- package/dist/vector-store.js +3 -3
- package/dist/voice.d.ts +1 -7
- package/dist/voice.d.ts.map +1 -1
- package/dist/voice.js +3 -3
- package/package.json +419 -76
- package/dist/_virtual/rolldown_runtime.js +0 -36
- package/dist/impls/elevenlabs-voice.js.map +0 -1
- package/dist/impls/gcs-storage.js.map +0 -1
- package/dist/impls/gmail-inbound.js.map +0 -1
- package/dist/impls/gmail-outbound.js.map +0 -1
- package/dist/impls/google-calendar.js.map +0 -1
- package/dist/impls/mistral-embedding.js.map +0 -1
- package/dist/impls/mistral-llm.js.map +0 -1
- package/dist/impls/postmark-email.js.map +0 -1
- package/dist/impls/powens-client.js.map +0 -1
- package/dist/impls/powens-openbanking.js.map +0 -1
- package/dist/impls/provider-factory.js.map +0 -1
- package/dist/impls/qdrant-vector.js.map +0 -1
- package/dist/impls/stripe-payments.js.map +0 -1
- package/dist/impls/twilio-sms.js.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
// src/impls/supabase-psql.ts
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
import { sql as drizzleSql } from "drizzle-orm";
|
|
4
|
+
import { drizzle } from "drizzle-orm/postgres-js";
|
|
5
|
+
import postgres from "postgres";
|
|
6
|
+
|
|
7
|
+
class SupabasePostgresProvider {
|
|
8
|
+
client;
|
|
9
|
+
db;
|
|
10
|
+
ownsClient;
|
|
11
|
+
createDrizzle;
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.createDrizzle = options.createDrizzle ?? ((client) => drizzle(client));
|
|
14
|
+
if (options.db) {
|
|
15
|
+
if (!options.client) {
|
|
16
|
+
throw new Error("SupabasePostgresProvider requires a postgres client when db is provided.");
|
|
17
|
+
}
|
|
18
|
+
this.client = options.client;
|
|
19
|
+
this.db = options.db;
|
|
20
|
+
this.ownsClient = false;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (options.client) {
|
|
24
|
+
this.client = options.client;
|
|
25
|
+
this.ownsClient = false;
|
|
26
|
+
} else {
|
|
27
|
+
if (!options.connectionString) {
|
|
28
|
+
throw new Error("SupabasePostgresProvider requires either a connectionString or a client.");
|
|
29
|
+
}
|
|
30
|
+
this.client = postgres(options.connectionString, {
|
|
31
|
+
max: options.maxConnections,
|
|
32
|
+
prepare: false,
|
|
33
|
+
ssl: resolveSslMode(options.sslMode)
|
|
34
|
+
});
|
|
35
|
+
this.ownsClient = true;
|
|
36
|
+
}
|
|
37
|
+
this.db = this.createDrizzle(this.client);
|
|
38
|
+
}
|
|
39
|
+
async query(statement, params = []) {
|
|
40
|
+
const query = buildParameterizedSql(statement, params);
|
|
41
|
+
const result = await this.db.execute(query);
|
|
42
|
+
const rows = asRows(result);
|
|
43
|
+
return {
|
|
44
|
+
rows,
|
|
45
|
+
rowCount: rows.length
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async execute(statement, params = []) {
|
|
49
|
+
const query = buildParameterizedSql(statement, params);
|
|
50
|
+
await this.db.execute(query);
|
|
51
|
+
}
|
|
52
|
+
async transaction(run) {
|
|
53
|
+
const transactionResult = this.client.begin(async (transactionClient) => {
|
|
54
|
+
const transactionalProvider = new SupabasePostgresProvider({
|
|
55
|
+
client: transactionClient,
|
|
56
|
+
db: this.createDrizzle(transactionClient),
|
|
57
|
+
createDrizzle: this.createDrizzle
|
|
58
|
+
});
|
|
59
|
+
return run(transactionalProvider);
|
|
60
|
+
});
|
|
61
|
+
return transactionResult;
|
|
62
|
+
}
|
|
63
|
+
async close() {
|
|
64
|
+
if (this.ownsClient) {
|
|
65
|
+
await this.client.end({ timeout: 5 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function buildParameterizedSql(statement, params) {
|
|
70
|
+
const segments = [];
|
|
71
|
+
const pattern = /\$(\d+)/g;
|
|
72
|
+
let cursor = 0;
|
|
73
|
+
for (const match of statement.matchAll(pattern)) {
|
|
74
|
+
const token = match[0];
|
|
75
|
+
const indexPart = match[1];
|
|
76
|
+
const start = match.index;
|
|
77
|
+
if (indexPart == null || start == null)
|
|
78
|
+
continue;
|
|
79
|
+
const parameterIndex = Number(indexPart) - 1;
|
|
80
|
+
if (!Number.isInteger(parameterIndex) || parameterIndex < 0 || parameterIndex >= params.length) {
|
|
81
|
+
throw new Error(`SQL placeholder ${token} is out of bounds for ${params.length} parameter(s).`);
|
|
82
|
+
}
|
|
83
|
+
const staticSegment = statement.slice(cursor, start);
|
|
84
|
+
if (staticSegment.length > 0) {
|
|
85
|
+
segments.push(drizzleSql.raw(staticSegment));
|
|
86
|
+
}
|
|
87
|
+
const parameterValue = params[parameterIndex];
|
|
88
|
+
if (parameterValue === undefined) {
|
|
89
|
+
throw new Error(`SQL placeholder ${token} is missing a parameter value.`);
|
|
90
|
+
}
|
|
91
|
+
const normalizedValue = normalizeParam(parameterValue);
|
|
92
|
+
segments.push(drizzleSql`${normalizedValue}`);
|
|
93
|
+
cursor = start + token.length;
|
|
94
|
+
}
|
|
95
|
+
const tailSegment = statement.slice(cursor);
|
|
96
|
+
if (tailSegment.length > 0) {
|
|
97
|
+
segments.push(drizzleSql.raw(tailSegment));
|
|
98
|
+
}
|
|
99
|
+
if (segments.length === 0) {
|
|
100
|
+
return drizzleSql.raw("");
|
|
101
|
+
}
|
|
102
|
+
return drizzleSql.join(segments);
|
|
103
|
+
}
|
|
104
|
+
function normalizeParam(value) {
|
|
105
|
+
if (typeof value === "bigint") {
|
|
106
|
+
return value.toString();
|
|
107
|
+
}
|
|
108
|
+
if (value instanceof Uint8Array) {
|
|
109
|
+
return Buffer.from(value);
|
|
110
|
+
}
|
|
111
|
+
if (isPlainObject(value)) {
|
|
112
|
+
return JSON.stringify(value);
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
function asRows(result) {
|
|
117
|
+
if (!Array.isArray(result)) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
function isPlainObject(value) {
|
|
123
|
+
if (value == null || typeof value !== "object") {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
if (value instanceof Date) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
if (value instanceof Uint8Array) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
function resolveSslMode(mode) {
|
|
138
|
+
switch (mode) {
|
|
139
|
+
case "allow":
|
|
140
|
+
return false;
|
|
141
|
+
case "prefer":
|
|
142
|
+
return "prefer";
|
|
143
|
+
case "require":
|
|
144
|
+
default:
|
|
145
|
+
return "require";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/impls/supabase-vector.ts
|
|
150
|
+
class SupabaseVectorProvider {
|
|
151
|
+
database;
|
|
152
|
+
createTableIfMissing;
|
|
153
|
+
distanceMetric;
|
|
154
|
+
quotedSchema;
|
|
155
|
+
qualifiedTable;
|
|
156
|
+
collectionIndex;
|
|
157
|
+
namespaceIndex;
|
|
158
|
+
ensureTablePromise;
|
|
159
|
+
constructor(options) {
|
|
160
|
+
this.database = options.database ?? new SupabasePostgresProvider({
|
|
161
|
+
connectionString: options.connectionString,
|
|
162
|
+
maxConnections: options.maxConnections,
|
|
163
|
+
sslMode: options.sslMode
|
|
164
|
+
});
|
|
165
|
+
this.createTableIfMissing = options.createTableIfMissing ?? true;
|
|
166
|
+
this.distanceMetric = options.distanceMetric ?? "cosine";
|
|
167
|
+
const schema = sanitizeIdentifier(options.schema ?? "public", "schema");
|
|
168
|
+
const table = sanitizeIdentifier(options.table ?? "contractspec_vectors", "table");
|
|
169
|
+
this.quotedSchema = quoteIdentifier(schema);
|
|
170
|
+
this.qualifiedTable = `${this.quotedSchema}.${quoteIdentifier(table)}`;
|
|
171
|
+
this.collectionIndex = quoteIdentifier(`${table}_collection_idx`);
|
|
172
|
+
this.namespaceIndex = quoteIdentifier(`${table}_namespace_idx`);
|
|
173
|
+
}
|
|
174
|
+
async upsert(request) {
|
|
175
|
+
if (request.documents.length === 0) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (this.createTableIfMissing) {
|
|
179
|
+
await this.ensureTable();
|
|
180
|
+
}
|
|
181
|
+
for (const document of request.documents) {
|
|
182
|
+
await this.database.execute(`INSERT INTO ${this.qualifiedTable}
|
|
183
|
+
(collection, id, embedding, payload, namespace, expires_at, updated_at)
|
|
184
|
+
VALUES ($1, $2, $3::vector, $4::jsonb, $5, $6, now())
|
|
185
|
+
ON CONFLICT (collection, id)
|
|
186
|
+
DO UPDATE SET
|
|
187
|
+
embedding = EXCLUDED.embedding,
|
|
188
|
+
payload = EXCLUDED.payload,
|
|
189
|
+
namespace = EXCLUDED.namespace,
|
|
190
|
+
expires_at = EXCLUDED.expires_at,
|
|
191
|
+
updated_at = now();`, [
|
|
192
|
+
request.collection,
|
|
193
|
+
document.id,
|
|
194
|
+
toVectorLiteral(document.vector),
|
|
195
|
+
document.payload ? JSON.stringify(document.payload) : null,
|
|
196
|
+
document.namespace ?? null,
|
|
197
|
+
document.expiresAt ?? null
|
|
198
|
+
]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async search(query) {
|
|
202
|
+
const operator = this.distanceOperator;
|
|
203
|
+
const results = await this.database.query(`SELECT
|
|
204
|
+
id,
|
|
205
|
+
payload,
|
|
206
|
+
namespace,
|
|
207
|
+
(embedding ${operator} $3::vector) AS distance
|
|
208
|
+
FROM ${this.qualifiedTable}
|
|
209
|
+
WHERE collection = $1
|
|
210
|
+
AND ($2::text IS NULL OR namespace = $2)
|
|
211
|
+
AND (expires_at IS NULL OR expires_at > now())
|
|
212
|
+
AND ($4::jsonb IS NULL OR payload @> $4::jsonb)
|
|
213
|
+
ORDER BY embedding ${operator} $3::vector
|
|
214
|
+
LIMIT $5;`, [
|
|
215
|
+
query.collection,
|
|
216
|
+
query.namespace ?? null,
|
|
217
|
+
toVectorLiteral(query.vector),
|
|
218
|
+
query.filter ? JSON.stringify(query.filter) : null,
|
|
219
|
+
query.topK
|
|
220
|
+
]);
|
|
221
|
+
const mapped = results.rows.map((row) => {
|
|
222
|
+
const distance = Number(row.distance);
|
|
223
|
+
return {
|
|
224
|
+
id: row.id,
|
|
225
|
+
score: distanceToScore(distance, this.distanceMetric),
|
|
226
|
+
payload: isRecord(row.payload) ? row.payload : undefined,
|
|
227
|
+
namespace: row.namespace ?? undefined
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
const scoreThreshold = query.scoreThreshold;
|
|
231
|
+
if (scoreThreshold == null) {
|
|
232
|
+
return mapped;
|
|
233
|
+
}
|
|
234
|
+
return mapped.filter((result) => result.score >= scoreThreshold);
|
|
235
|
+
}
|
|
236
|
+
async delete(request) {
|
|
237
|
+
if (request.ids.length === 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const params = [
|
|
241
|
+
request.collection,
|
|
242
|
+
request.ids,
|
|
243
|
+
request.namespace ?? null
|
|
244
|
+
];
|
|
245
|
+
await this.database.execute(`DELETE FROM ${this.qualifiedTable}
|
|
246
|
+
WHERE collection = $1
|
|
247
|
+
AND id = ANY($2::text[])
|
|
248
|
+
AND ($3::text IS NULL OR namespace = $3);`, params);
|
|
249
|
+
}
|
|
250
|
+
async ensureTable() {
|
|
251
|
+
if (!this.ensureTablePromise) {
|
|
252
|
+
this.ensureTablePromise = this.createTable();
|
|
253
|
+
}
|
|
254
|
+
await this.ensureTablePromise;
|
|
255
|
+
}
|
|
256
|
+
async createTable() {
|
|
257
|
+
await this.database.execute("CREATE EXTENSION IF NOT EXISTS vector;");
|
|
258
|
+
await this.database.execute(`CREATE SCHEMA IF NOT EXISTS ${this.quotedSchema};`);
|
|
259
|
+
await this.database.execute(`CREATE TABLE IF NOT EXISTS ${this.qualifiedTable} (
|
|
260
|
+
collection text NOT NULL,
|
|
261
|
+
id text NOT NULL,
|
|
262
|
+
embedding vector NOT NULL,
|
|
263
|
+
payload jsonb,
|
|
264
|
+
namespace text,
|
|
265
|
+
expires_at timestamptz,
|
|
266
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
267
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
268
|
+
PRIMARY KEY (collection, id)
|
|
269
|
+
);`);
|
|
270
|
+
await this.database.execute(`CREATE INDEX IF NOT EXISTS ${this.collectionIndex}
|
|
271
|
+
ON ${this.qualifiedTable} (collection);`);
|
|
272
|
+
await this.database.execute(`CREATE INDEX IF NOT EXISTS ${this.namespaceIndex}
|
|
273
|
+
ON ${this.qualifiedTable} (namespace);`);
|
|
274
|
+
}
|
|
275
|
+
get distanceOperator() {
|
|
276
|
+
switch (this.distanceMetric) {
|
|
277
|
+
case "l2":
|
|
278
|
+
return "<->";
|
|
279
|
+
case "inner_product":
|
|
280
|
+
return "<#>";
|
|
281
|
+
case "cosine":
|
|
282
|
+
default:
|
|
283
|
+
return "<=>";
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function sanitizeIdentifier(value, label) {
|
|
288
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
289
|
+
throw new Error(`SupabaseVectorProvider ${label} "${value}" is invalid.`);
|
|
290
|
+
}
|
|
291
|
+
return value;
|
|
292
|
+
}
|
|
293
|
+
function quoteIdentifier(value) {
|
|
294
|
+
return `"${value.replaceAll('"', '""')}"`;
|
|
295
|
+
}
|
|
296
|
+
function toVectorLiteral(vector) {
|
|
297
|
+
if (vector.length === 0) {
|
|
298
|
+
throw new Error("Supabase vectors must contain at least one dimension.");
|
|
299
|
+
}
|
|
300
|
+
for (const value of vector) {
|
|
301
|
+
if (!Number.isFinite(value)) {
|
|
302
|
+
throw new Error(`Supabase vectors must be finite numbers. Found "${value}".`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return `[${vector.join(",")}]`;
|
|
306
|
+
}
|
|
307
|
+
function isRecord(value) {
|
|
308
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
309
|
+
}
|
|
310
|
+
function distanceToScore(distance, metric) {
|
|
311
|
+
switch (metric) {
|
|
312
|
+
case "inner_product":
|
|
313
|
+
return -distance;
|
|
314
|
+
case "l2":
|
|
315
|
+
return 1 / (1 + distance);
|
|
316
|
+
case "cosine":
|
|
317
|
+
default:
|
|
318
|
+
return 1 - distance;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
export {
|
|
322
|
+
SupabaseVectorProvider
|
|
323
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// src/impls/tldv-meeting-recorder.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "https://pasta.tldv.io/v1alpha1";
|
|
3
|
+
|
|
4
|
+
class TldvMeetingRecorderProvider {
|
|
5
|
+
apiKey;
|
|
6
|
+
baseUrl;
|
|
7
|
+
defaultPageSize;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.apiKey = options.apiKey;
|
|
10
|
+
this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
11
|
+
this.defaultPageSize = options.pageSize;
|
|
12
|
+
}
|
|
13
|
+
async listMeetings(params) {
|
|
14
|
+
const page = params.cursor ? Number(params.cursor) : 1;
|
|
15
|
+
const limit = params.pageSize ?? this.defaultPageSize ?? 50;
|
|
16
|
+
const query = new URLSearchParams;
|
|
17
|
+
query.set("page", String(Number.isFinite(page) ? page : 1));
|
|
18
|
+
query.set("limit", String(limit));
|
|
19
|
+
if (params.query)
|
|
20
|
+
query.set("query", params.query);
|
|
21
|
+
if (params.from)
|
|
22
|
+
query.set("from", params.from);
|
|
23
|
+
if (params.to)
|
|
24
|
+
query.set("to", params.to);
|
|
25
|
+
if (params.organizerEmail)
|
|
26
|
+
query.set("organizer", params.organizerEmail);
|
|
27
|
+
if (params.participantEmail)
|
|
28
|
+
query.set("participant", params.participantEmail);
|
|
29
|
+
const data = await this.request(`/meetings?${query.toString()}`);
|
|
30
|
+
const nextPage = data.page < data.pages ? data.page + 1 : undefined;
|
|
31
|
+
return {
|
|
32
|
+
meetings: data.results.map((meeting) => this.mapMeeting(meeting, params)),
|
|
33
|
+
nextCursor: nextPage ? String(nextPage) : undefined,
|
|
34
|
+
hasMore: Boolean(nextPage)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async getMeeting(params) {
|
|
38
|
+
const meeting = await this.request(`/meetings/${encodeURIComponent(params.meetingId)}`);
|
|
39
|
+
return this.mapMeeting(meeting, params);
|
|
40
|
+
}
|
|
41
|
+
async getTranscript(params) {
|
|
42
|
+
const response = await this.request(`/meetings/${encodeURIComponent(params.meetingId)}/transcript`);
|
|
43
|
+
const segments = response.data.map((segment, index) => this.mapTranscriptSegment(segment, index));
|
|
44
|
+
return {
|
|
45
|
+
id: response.id,
|
|
46
|
+
meetingId: response.meetingId,
|
|
47
|
+
tenantId: params.tenantId,
|
|
48
|
+
connectionId: params.connectionId ?? "unknown",
|
|
49
|
+
externalId: response.id,
|
|
50
|
+
format: "segments",
|
|
51
|
+
text: segments.map((segment) => segment.text).join(`
|
|
52
|
+
`),
|
|
53
|
+
segments,
|
|
54
|
+
metadata: {
|
|
55
|
+
providerMeetingId: response.meetingId
|
|
56
|
+
},
|
|
57
|
+
raw: response.data
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async parseWebhook(request) {
|
|
61
|
+
const payload = request.parsedBody ?? JSON.parse(request.rawBody);
|
|
62
|
+
const body = payload;
|
|
63
|
+
return {
|
|
64
|
+
providerKey: "meeting-recorder.tldv",
|
|
65
|
+
eventType: body.event,
|
|
66
|
+
meetingId: body.data?.id ?? body.data?.meetingId,
|
|
67
|
+
receivedAt: body.executedAt,
|
|
68
|
+
payload
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
mapMeeting(meeting, params) {
|
|
72
|
+
const connectionId = params.connectionId ?? "unknown";
|
|
73
|
+
const invitees = meeting.invitees?.map((invitee) => this.mapInvitee(invitee)).filter(Boolean);
|
|
74
|
+
return {
|
|
75
|
+
id: meeting.id,
|
|
76
|
+
tenantId: params.tenantId,
|
|
77
|
+
connectionId,
|
|
78
|
+
externalId: meeting.id,
|
|
79
|
+
title: meeting.name,
|
|
80
|
+
organizer: this.mapInvitee(meeting.organizer, "organizer"),
|
|
81
|
+
invitees: invitees?.length ? invitees : undefined,
|
|
82
|
+
participants: invitees?.length ? invitees : undefined,
|
|
83
|
+
scheduledStartAt: meeting.happenedAt,
|
|
84
|
+
recordingStartAt: meeting.happenedAt,
|
|
85
|
+
durationSeconds: meeting.duration,
|
|
86
|
+
meetingUrl: meeting.url,
|
|
87
|
+
transcriptAvailable: true,
|
|
88
|
+
sourcePlatform: "tldv",
|
|
89
|
+
metadata: {
|
|
90
|
+
template: meeting.template,
|
|
91
|
+
extraProperties: meeting.extraProperties
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
mapInvitee(invitee, role = "attendee") {
|
|
96
|
+
if (!invitee)
|
|
97
|
+
return;
|
|
98
|
+
return {
|
|
99
|
+
name: invitee.name ?? undefined,
|
|
100
|
+
email: invitee.email ?? undefined,
|
|
101
|
+
role
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
mapTranscriptSegment(segment, index) {
|
|
105
|
+
return {
|
|
106
|
+
index,
|
|
107
|
+
speakerName: segment.speaker ?? undefined,
|
|
108
|
+
text: segment.text,
|
|
109
|
+
startTimeMs: parseSeconds(segment.startTime),
|
|
110
|
+
endTimeMs: parseSeconds(segment.endTime)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async request(path) {
|
|
114
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
115
|
+
headers: {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
"x-api-key": this.apiKey
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
const message = await safeReadError(response);
|
|
122
|
+
throw new Error(`tl;dv API error (${response.status}): ${message}`);
|
|
123
|
+
}
|
|
124
|
+
return await response.json();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function parseSeconds(value) {
|
|
128
|
+
if (value == null)
|
|
129
|
+
return;
|
|
130
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
131
|
+
if (!Number.isFinite(num))
|
|
132
|
+
return;
|
|
133
|
+
return num * 1000;
|
|
134
|
+
}
|
|
135
|
+
async function safeReadError(response) {
|
|
136
|
+
try {
|
|
137
|
+
const data = await response.json();
|
|
138
|
+
return data?.message ?? response.statusText;
|
|
139
|
+
} catch {
|
|
140
|
+
return response.statusText;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
TldvMeetingRecorderProvider
|
|
145
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// src/impls/twilio-sms.ts
|
|
2
|
+
import Twilio from "twilio";
|
|
3
|
+
|
|
4
|
+
class TwilioSmsProvider {
|
|
5
|
+
client;
|
|
6
|
+
fromNumber;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.client = options.client ?? Twilio(options.accountSid, options.authToken);
|
|
9
|
+
this.fromNumber = options.fromNumber;
|
|
10
|
+
}
|
|
11
|
+
async sendSms(input) {
|
|
12
|
+
const message = await this.client.messages.create({
|
|
13
|
+
to: input.to,
|
|
14
|
+
from: input.from ?? this.fromNumber,
|
|
15
|
+
body: input.body
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
id: message.sid,
|
|
19
|
+
to: message.to ?? input.to,
|
|
20
|
+
from: message.from ?? input.from ?? this.fromNumber ?? "",
|
|
21
|
+
body: message.body ?? input.body,
|
|
22
|
+
status: mapStatus(message.status),
|
|
23
|
+
sentAt: message.dateCreated ? new Date(message.dateCreated) : undefined,
|
|
24
|
+
deliveredAt: message.status === "delivered" && message.dateUpdated ? new Date(message.dateUpdated) : undefined,
|
|
25
|
+
price: message.price ? Number(message.price) : undefined,
|
|
26
|
+
priceCurrency: message.priceUnit ?? undefined,
|
|
27
|
+
errorCode: message.errorCode ? String(message.errorCode) : undefined,
|
|
28
|
+
errorMessage: message.errorMessage ?? undefined
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async getDeliveryStatus(messageId) {
|
|
32
|
+
const message = await this.client.messages(messageId).fetch();
|
|
33
|
+
return {
|
|
34
|
+
status: mapStatus(message.status),
|
|
35
|
+
errorCode: message.errorCode ? String(message.errorCode) : undefined,
|
|
36
|
+
errorMessage: message.errorMessage ?? undefined,
|
|
37
|
+
updatedAt: message.dateUpdated ? new Date(message.dateUpdated) : new Date
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function mapStatus(status) {
|
|
42
|
+
switch (status) {
|
|
43
|
+
case "queued":
|
|
44
|
+
case "accepted":
|
|
45
|
+
case "scheduled":
|
|
46
|
+
return "queued";
|
|
47
|
+
case "sending":
|
|
48
|
+
case "processing":
|
|
49
|
+
return "sending";
|
|
50
|
+
case "sent":
|
|
51
|
+
return "sent";
|
|
52
|
+
case "delivered":
|
|
53
|
+
return "delivered";
|
|
54
|
+
case "undelivered":
|
|
55
|
+
return "undelivered";
|
|
56
|
+
case "failed":
|
|
57
|
+
case "canceled":
|
|
58
|
+
return "failed";
|
|
59
|
+
default:
|
|
60
|
+
return "queued";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
TwilioSmsProvider
|
|
65
|
+
};
|