@squadbase/vite-server 0.0.1-build-6 → 0.0.1-build-8

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/index.js CHANGED
@@ -37,6 +37,11 @@ function resolveEnvVar(entry, key, connectionId) {
37
37
  }
38
38
  return value;
39
39
  }
40
+ function resolveEnvVarOptional(entry, key) {
41
+ const envVarName = entry.envVars[key];
42
+ if (!envVarName) return void 0;
43
+ return process.env[envVarName] || void 0;
44
+ }
40
45
 
41
46
  // src/connector-client/bigquery.ts
42
47
  function createBigQueryClient(entry, connectionId) {
@@ -48,7 +53,7 @@ function createBigQueryClient(entry, connectionId) {
48
53
  gcpCredentials = JSON.parse(serviceAccountJson);
49
54
  } catch {
50
55
  throw new Error(
51
- `BigQuery service account JSON (decoded from base64) is not valid JSON for connection "${connectionId}"`
56
+ `BigQuery service account JSON (decoded from base64) is not valid JSON for connectionId "${connectionId}"`
52
57
  );
53
58
  }
54
59
  return {
@@ -105,14 +110,184 @@ function createSnowflakeClient(entry, connectionId) {
105
110
  };
106
111
  }
107
112
 
113
+ // src/connector-client/mysql.ts
114
+ function createMySQLClient(entry, connectionId) {
115
+ const connectionUrl = resolveEnvVar(entry, "connection-url", connectionId);
116
+ let poolPromise = null;
117
+ function getPool() {
118
+ if (!poolPromise) {
119
+ poolPromise = import("mysql2/promise").then(
120
+ (mysql) => mysql.default.createPool(connectionUrl)
121
+ );
122
+ }
123
+ return poolPromise;
124
+ }
125
+ return {
126
+ async query(sql, params) {
127
+ const pool = await getPool();
128
+ const [rows] = await pool.execute(sql, params);
129
+ return { rows };
130
+ }
131
+ };
132
+ }
133
+
134
+ // src/connector-client/aws-athena.ts
135
+ function createAthenaClient(entry, connectionId) {
136
+ const region = resolveEnvVar(entry, "aws-region", connectionId);
137
+ const accessKeyId = resolveEnvVar(entry, "aws-access-key-id", connectionId);
138
+ const secretAccessKey = resolveEnvVar(entry, "aws-secret-access-key", connectionId);
139
+ const workgroup = resolveEnvVarOptional(entry, "workgroup") ?? "primary";
140
+ const outputLocation = resolveEnvVarOptional(entry, "output-location");
141
+ return {
142
+ async query(sql) {
143
+ const {
144
+ AthenaClient,
145
+ StartQueryExecutionCommand,
146
+ GetQueryExecutionCommand,
147
+ GetQueryResultsCommand
148
+ } = await import("@aws-sdk/client-athena");
149
+ const client = new AthenaClient({
150
+ region,
151
+ credentials: { accessKeyId, secretAccessKey }
152
+ });
153
+ const startParams = {
154
+ QueryString: sql,
155
+ WorkGroup: workgroup
156
+ };
157
+ if (outputLocation) {
158
+ startParams.ResultConfiguration = { OutputLocation: outputLocation };
159
+ }
160
+ const { QueryExecutionId } = await client.send(
161
+ new StartQueryExecutionCommand(startParams)
162
+ );
163
+ if (!QueryExecutionId) throw new Error("Athena: failed to start query execution");
164
+ while (true) {
165
+ const { QueryExecution } = await client.send(
166
+ new GetQueryExecutionCommand({ QueryExecutionId })
167
+ );
168
+ const state = QueryExecution?.Status?.State;
169
+ if (state === "SUCCEEDED") break;
170
+ if (state === "FAILED") {
171
+ throw new Error(
172
+ `Athena query failed: ${QueryExecution?.Status?.StateChangeReason ?? "unknown"}`
173
+ );
174
+ }
175
+ if (state === "CANCELLED") throw new Error("Athena query was cancelled");
176
+ await new Promise((r) => setTimeout(r, 500));
177
+ }
178
+ const { ResultSet } = await client.send(
179
+ new GetQueryResultsCommand({ QueryExecutionId })
180
+ );
181
+ const resultRows = ResultSet?.Rows ?? [];
182
+ if (resultRows.length === 0) return { rows: [] };
183
+ const headers = resultRows[0].Data?.map((d) => d.VarCharValue ?? "") ?? [];
184
+ const rows = resultRows.slice(1).map((row) => {
185
+ const obj = {};
186
+ row.Data?.forEach((d, i) => {
187
+ obj[headers[i]] = d.VarCharValue ?? null;
188
+ });
189
+ return obj;
190
+ });
191
+ return { rows };
192
+ }
193
+ };
194
+ }
195
+
196
+ // src/connector-client/redshift.ts
197
+ function createRedshiftClient(entry, connectionId) {
198
+ const region = resolveEnvVar(entry, "aws-region", connectionId);
199
+ const accessKeyId = resolveEnvVar(entry, "aws-access-key-id", connectionId);
200
+ const secretAccessKey = resolveEnvVar(entry, "aws-secret-access-key", connectionId);
201
+ const database = resolveEnvVar(entry, "database", connectionId);
202
+ const clusterIdentifier = resolveEnvVarOptional(entry, "cluster-identifier");
203
+ const workgroupName = resolveEnvVarOptional(entry, "workgroup-name");
204
+ const secretArn = resolveEnvVarOptional(entry, "secret-arn");
205
+ const dbUser = resolveEnvVarOptional(entry, "db-user");
206
+ return {
207
+ async query(sql) {
208
+ const {
209
+ RedshiftDataClient,
210
+ ExecuteStatementCommand,
211
+ DescribeStatementCommand,
212
+ GetStatementResultCommand
213
+ } = await import("@aws-sdk/client-redshift-data");
214
+ const client = new RedshiftDataClient({
215
+ region,
216
+ credentials: { accessKeyId, secretAccessKey }
217
+ });
218
+ const executeParams = {
219
+ Sql: sql,
220
+ Database: database
221
+ };
222
+ if (clusterIdentifier) executeParams.ClusterIdentifier = clusterIdentifier;
223
+ if (workgroupName) executeParams.WorkgroupName = workgroupName;
224
+ if (secretArn) executeParams.SecretArn = secretArn;
225
+ if (dbUser) executeParams.DbUser = dbUser;
226
+ const { Id } = await client.send(
227
+ new ExecuteStatementCommand(executeParams)
228
+ );
229
+ if (!Id) throw new Error("Redshift: failed to start statement execution");
230
+ while (true) {
231
+ const desc = await client.send(new DescribeStatementCommand({ Id }));
232
+ const status = desc.Status;
233
+ if (status === "FINISHED") break;
234
+ if (status === "FAILED") {
235
+ throw new Error(`Redshift query failed: ${desc.Error ?? "unknown"}`);
236
+ }
237
+ if (status === "ABORTED") throw new Error("Redshift query was aborted");
238
+ await new Promise((r) => setTimeout(r, 500));
239
+ }
240
+ const result = await client.send(new GetStatementResultCommand({ Id }));
241
+ const columns = result.ColumnMetadata?.map((c) => c.name ?? "") ?? [];
242
+ const rows = (result.Records ?? []).map((record) => {
243
+ const obj = {};
244
+ record.forEach((field, i) => {
245
+ const col = columns[i];
246
+ const value = field.stringValue ?? field.longValue ?? field.doubleValue ?? field.booleanValue ?? (field.isNull ? null : field.blobValue ?? null);
247
+ obj[col] = value;
248
+ });
249
+ return obj;
250
+ });
251
+ return { rows };
252
+ }
253
+ };
254
+ }
255
+
256
+ // src/connector-client/databricks.ts
257
+ function createDatabricksClient(entry, connectionId) {
258
+ const host = resolveEnvVar(entry, "host", connectionId);
259
+ const httpPath = resolveEnvVar(entry, "http-path", connectionId);
260
+ const token = resolveEnvVar(entry, "token", connectionId);
261
+ return {
262
+ async query(sql) {
263
+ const { DBSQLClient } = await import("@databricks/sql");
264
+ const client = new DBSQLClient();
265
+ await client.connect({ host, path: httpPath, token });
266
+ try {
267
+ const session = await client.openSession();
268
+ try {
269
+ const operation = await session.executeStatement(sql);
270
+ const result = await operation.fetchAll();
271
+ await operation.close();
272
+ return { rows: result };
273
+ } finally {
274
+ await session.close();
275
+ }
276
+ } finally {
277
+ await client.close();
278
+ }
279
+ }
280
+ };
281
+ }
282
+
108
283
  // src/connector-client/registry.ts
109
284
  function createConnectorRegistry() {
110
285
  let connectionsCache = null;
111
286
  const clientCache = /* @__PURE__ */ new Map();
112
287
  function getConnectionsFilePath() {
113
- return process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), "../../.squadbase/connections.json");
288
+ return process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
114
289
  }
115
- function loadConnections() {
290
+ function loadConnections2() {
116
291
  if (connectionsCache !== null) return connectionsCache;
117
292
  const filePath = getConnectionsFilePath();
118
293
  try {
@@ -124,7 +299,7 @@ function createConnectorRegistry() {
124
299
  return connectionsCache;
125
300
  }
126
301
  async function getClient2(connectionId) {
127
- const connections = loadConnections();
302
+ const connections = loadConnections2();
128
303
  const entry = connections[connectionId];
129
304
  if (!entry) {
130
305
  throw new Error(`connection '${connectionId}' not found in .squadbase/connections.json`);
@@ -138,6 +313,20 @@ function createConnectorRegistry() {
138
313
  if (connectorSlug === "bigquery") {
139
314
  return { client: createBigQueryClient(entry, connectionId), connectorSlug };
140
315
  }
316
+ if (connectorSlug === "athena") {
317
+ return { client: createAthenaClient(entry, connectionId), connectorSlug };
318
+ }
319
+ if (connectorSlug === "redshift") {
320
+ return { client: createRedshiftClient(entry, connectionId), connectorSlug };
321
+ }
322
+ if (connectorSlug === "databricks") {
323
+ return { client: createDatabricksClient(entry, connectionId), connectorSlug };
324
+ }
325
+ if (connectorSlug === "mysql") {
326
+ const client = createMySQLClient(entry, connectionId);
327
+ clientCache.set(connectionId, client);
328
+ return { client, connectorSlug };
329
+ }
141
330
  if (connectorSlug === "postgresql" || connectorSlug === "squadbase-db") {
142
331
  const urlEnvName = entry.envVars["connection-url"];
143
332
  if (!urlEnvName) {
@@ -154,7 +343,7 @@ function createConnectorRegistry() {
154
343
  return { client, connectorSlug };
155
344
  }
156
345
  throw new Error(
157
- `connector type '${connectorSlug}' is not supported. Supported: "snowflake", "bigquery", "postgresql", "squadbase-db"`
346
+ `connector type '${connectorSlug}' is not supported as a SQL connector. Supported SQL types: "postgresql", "squadbase-db", "mysql", "snowflake", "bigquery", "athena", "redshift", "databricks". Non-SQL types (airtable, google-analytics, kintone, wix-store, dbt) should be used via TypeScript handlers.`
158
347
  );
159
348
  }
160
349
  function reloadEnvFile2(envPath) {
@@ -175,7 +364,7 @@ function createConnectorRegistry() {
175
364
  }
176
365
  function watchConnectionsFile2() {
177
366
  const filePath = getConnectionsFilePath();
178
- const envPath = path.join(process.cwd(), "..", "..", ".env");
367
+ const envPath = path.join(process.cwd(), ".env");
179
368
  try {
180
369
  fsWatch(filePath, { persistent: false }, () => {
181
370
  console.log("[connector-client] connections.json changed, clearing cache");
@@ -186,11 +375,273 @@ function createConnectorRegistry() {
186
375
  } catch {
187
376
  }
188
377
  }
189
- return { getClient: getClient2, reloadEnvFile: reloadEnvFile2, watchConnectionsFile: watchConnectionsFile2 };
378
+ return { getClient: getClient2, loadConnections: loadConnections2, reloadEnvFile: reloadEnvFile2, watchConnectionsFile: watchConnectionsFile2 };
379
+ }
380
+
381
+ // src/connector-client/airtable.ts
382
+ function createAirtableClient(entry, slug) {
383
+ const baseId = resolveEnvVar(entry, "base-id", slug);
384
+ const apiKey = resolveEnvVar(entry, "api-key", slug);
385
+ const baseUrl = `https://api.airtable.com/v0/${baseId}`;
386
+ const headers = {
387
+ Authorization: `Bearer ${apiKey}`,
388
+ "Content-Type": "application/json"
389
+ };
390
+ return {
391
+ async listRecords(tableIdOrName, options) {
392
+ const params = new URLSearchParams();
393
+ if (options?.filterByFormula) params.set("filterByFormula", options.filterByFormula);
394
+ if (options?.maxRecords) params.set("maxRecords", String(options.maxRecords));
395
+ if (options?.pageSize) params.set("pageSize", String(options.pageSize));
396
+ if (options?.offset) params.set("offset", options.offset);
397
+ options?.fields?.forEach((f) => params.append("fields[]", f));
398
+ options?.sort?.forEach((s, i) => {
399
+ params.set(`sort[${i}][field]`, s.field);
400
+ if (s.direction) params.set(`sort[${i}][direction]`, s.direction);
401
+ });
402
+ const qs = params.toString();
403
+ const url = `${baseUrl}/${encodeURIComponent(tableIdOrName)}${qs ? `?${qs}` : ""}`;
404
+ const res = await fetch(url, { headers });
405
+ if (!res.ok) throw new Error(`Airtable API error: ${res.status} ${await res.text()}`);
406
+ return res.json();
407
+ },
408
+ async getRecord(tableIdOrName, recordId) {
409
+ const url = `${baseUrl}/${encodeURIComponent(tableIdOrName)}/${recordId}`;
410
+ const res = await fetch(url, { headers });
411
+ if (!res.ok) throw new Error(`Airtable API error: ${res.status} ${await res.text()}`);
412
+ return res.json();
413
+ }
414
+ };
415
+ }
416
+
417
+ // src/connector-client/google-analytics.ts
418
+ function createGoogleAnalyticsClient(entry, slug) {
419
+ const serviceAccountJsonBase64 = resolveEnvVar(entry, "service-account-json-base64", slug);
420
+ const propertyId = resolveEnvVar(entry, "property-id", slug);
421
+ const serviceAccountJson = Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8");
422
+ let credentials;
423
+ try {
424
+ credentials = JSON.parse(serviceAccountJson);
425
+ } catch {
426
+ throw new Error(
427
+ `Google Analytics service account JSON (decoded from base64) is not valid JSON for slug "${slug}"`
428
+ );
429
+ }
430
+ return {
431
+ async runReport(request) {
432
+ const { BetaAnalyticsDataClient } = await import("@google-analytics/data");
433
+ const client = new BetaAnalyticsDataClient({
434
+ credentials: {
435
+ client_email: credentials.client_email,
436
+ private_key: credentials.private_key
437
+ }
438
+ });
439
+ const response = await client.runReport({
440
+ property: `properties/${propertyId}`,
441
+ dateRanges: request.dateRanges,
442
+ dimensions: request.dimensions,
443
+ metrics: request.metrics,
444
+ limit: request.limit != null ? String(request.limit) : void 0,
445
+ offset: request.offset != null ? String(request.offset) : void 0
446
+ });
447
+ const reportResponse = Array.isArray(response) ? response[0] : response;
448
+ const rawRows = reportResponse.rows;
449
+ const rows = (rawRows ?? []).map((row) => ({
450
+ dimensionValues: (row.dimensionValues ?? []).map((d) => ({
451
+ value: d.value ?? ""
452
+ })),
453
+ metricValues: (row.metricValues ?? []).map((m) => ({
454
+ value: m.value ?? ""
455
+ }))
456
+ }));
457
+ return {
458
+ rows,
459
+ rowCount: Number(reportResponse.rowCount ?? 0)
460
+ };
461
+ }
462
+ };
463
+ }
464
+
465
+ // src/connector-client/kintone.ts
466
+ function createKintoneClient(entry, slug) {
467
+ const baseUrl = resolveEnvVar(entry, "base-url", slug);
468
+ const username = resolveEnvVar(entry, "username", slug);
469
+ const password = resolveEnvVar(entry, "password", slug);
470
+ return {
471
+ async getRecords(appId, options) {
472
+ const { KintoneRestAPIClient } = await import("@kintone/rest-api-client");
473
+ const client = new KintoneRestAPIClient({
474
+ baseUrl,
475
+ auth: { username, password }
476
+ });
477
+ const result = await client.record.getRecords({
478
+ app: appId,
479
+ query: options?.query,
480
+ fields: options?.fields,
481
+ totalCount: options?.totalCount
482
+ });
483
+ return {
484
+ records: result.records,
485
+ totalCount: result.totalCount
486
+ };
487
+ },
488
+ async getRecord(appId, recordId) {
489
+ const { KintoneRestAPIClient } = await import("@kintone/rest-api-client");
490
+ const client = new KintoneRestAPIClient({
491
+ baseUrl,
492
+ auth: { username, password }
493
+ });
494
+ const result = await client.record.getRecord({
495
+ app: appId,
496
+ id: recordId
497
+ });
498
+ return { record: result.record };
499
+ },
500
+ async listApps(options) {
501
+ const { KintoneRestAPIClient } = await import("@kintone/rest-api-client");
502
+ const client = new KintoneRestAPIClient({
503
+ baseUrl,
504
+ auth: { username, password }
505
+ });
506
+ const result = await client.app.getApps({
507
+ ids: options?.ids,
508
+ name: options?.name,
509
+ limit: options?.limit,
510
+ offset: options?.offset
511
+ });
512
+ return { apps: result.apps };
513
+ }
514
+ };
515
+ }
516
+
517
+ // src/connector-client/wix-store.ts
518
+ function createWixStoreClient(entry, slug) {
519
+ const siteId = resolveEnvVar(entry, "site-id", slug);
520
+ const apiKey = resolveEnvVar(entry, "api-key", slug);
521
+ const headers = {
522
+ Authorization: apiKey,
523
+ "wix-site-id": siteId,
524
+ "Content-Type": "application/json"
525
+ };
526
+ return {
527
+ async queryProducts(options) {
528
+ const body = {};
529
+ if (options?.query) body.query = options.query;
530
+ if (options?.limit) {
531
+ body.query = { ...body.query ?? {}, paging: { limit: options.limit, offset: options?.offset ?? 0 } };
532
+ }
533
+ const res = await fetch(
534
+ "https://www.wixapis.com/stores/v1/products/query",
535
+ { method: "POST", headers, body: JSON.stringify(body) }
536
+ );
537
+ if (!res.ok) throw new Error(`Wix Store API error: ${res.status} ${await res.text()}`);
538
+ const data = await res.json();
539
+ return { products: data.products ?? [], totalResults: data.totalResults ?? 0 };
540
+ },
541
+ async queryOrders(options) {
542
+ const body = {};
543
+ if (options?.query) body.query = options.query;
544
+ if (options?.limit) {
545
+ body.query = { ...body.query ?? {}, paging: { limit: options.limit, offset: options?.offset ?? 0 } };
546
+ }
547
+ const res = await fetch(
548
+ "https://www.wixapis.com/stores/v2/orders/query",
549
+ { method: "POST", headers, body: JSON.stringify(body) }
550
+ );
551
+ if (!res.ok) throw new Error(`Wix Store API error: ${res.status} ${await res.text()}`);
552
+ const data = await res.json();
553
+ return { orders: data.orders ?? [], totalResults: data.totalResults ?? 0 };
554
+ }
555
+ };
556
+ }
557
+
558
+ // src/connector-client/dbt.ts
559
+ function createDbtClient(entry, slug) {
560
+ const host = resolveEnvVar(entry, "host", slug);
561
+ const prodEnvId = resolveEnvVar(entry, "prod-env-id", slug);
562
+ const token = resolveEnvVar(entry, "token", slug);
563
+ const discoveryUrl = `https://${host}/graphql`;
564
+ const headers = {
565
+ Authorization: `Bearer ${token}`,
566
+ "Content-Type": "application/json"
567
+ };
568
+ async function gqlRequest(query, variables) {
569
+ const res = await fetch(discoveryUrl, {
570
+ method: "POST",
571
+ headers,
572
+ body: JSON.stringify({ query, variables })
573
+ });
574
+ if (!res.ok) throw new Error(`dbt Discovery API error: ${res.status} ${await res.text()}`);
575
+ const json = await res.json();
576
+ if (json.errors) {
577
+ throw new Error(`dbt Discovery API GraphQL error: ${JSON.stringify(json.errors)}`);
578
+ }
579
+ return json.data ?? {};
580
+ }
581
+ return {
582
+ query: gqlRequest,
583
+ async getModels(options) {
584
+ const limit = options?.limit ?? 100;
585
+ const data = await gqlRequest(
586
+ `query ($environmentId: BigInt!, $first: Int) {
587
+ environment(id: $environmentId) {
588
+ applied {
589
+ models(first: $first) {
590
+ edges {
591
+ node {
592
+ uniqueId
593
+ name
594
+ description
595
+ materializedType
596
+ database
597
+ schema
598
+ alias
599
+ }
600
+ }
601
+ }
602
+ }
603
+ }
604
+ }`,
605
+ { environmentId: Number(prodEnvId), first: limit }
606
+ );
607
+ const env = data.environment;
608
+ const applied = env?.applied;
609
+ const models = applied?.models;
610
+ return models?.edges.map((e) => e.node) ?? [];
611
+ },
612
+ async getModelByName(uniqueId) {
613
+ const data = await gqlRequest(
614
+ `query ($environmentId: BigInt!, $uniqueId: String!) {
615
+ environment(id: $environmentId) {
616
+ applied {
617
+ modelByUniqueId(uniqueId: $uniqueId) {
618
+ uniqueId
619
+ name
620
+ description
621
+ materializedType
622
+ database
623
+ schema
624
+ alias
625
+ columns {
626
+ name
627
+ description
628
+ type
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }`,
634
+ { environmentId: Number(prodEnvId), uniqueId }
635
+ );
636
+ const env = data.environment;
637
+ const applied = env?.applied;
638
+ return applied?.modelByUniqueId ?? null;
639
+ }
640
+ };
190
641
  }
191
642
 
192
643
  // src/connector-client/index.ts
193
- var { getClient, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
644
+ var { getClient, loadConnections, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
194
645
 
195
646
  // src/registry.ts
196
647
  var dataSources = /* @__PURE__ */ new Map();
@@ -301,10 +752,10 @@ async function initialize() {
301
752
  _query: sqlDef.query,
302
753
  handler: async (runtimeParams) => {
303
754
  const { client, connectorSlug } = await getClient(sqlDef.connectionId);
304
- const isExternalConnector = connectorSlug === "snowflake" || connectorSlug === "bigquery";
755
+ const isLiteralConnector = connectorSlug === "snowflake" || connectorSlug === "bigquery" || connectorSlug === "athena" || connectorSlug === "redshift" || connectorSlug === "databricks";
305
756
  let queryText;
306
757
  let queryValues;
307
- if (isExternalConnector) {
758
+ if (isLiteralConnector) {
308
759
  const defaults = new Map(
309
760
  (sqlDef.parameters ?? []).map((p) => [p.name, p.default ?? null])
310
761
  );
@@ -322,6 +773,14 @@ async function initialize() {
322
773
  }
323
774
  );
324
775
  queryValues = [];
776
+ } else if (connectorSlug === "mysql") {
777
+ const built = buildQuery(
778
+ sqlDef.query,
779
+ sqlDef.parameters ?? [],
780
+ runtimeParams
781
+ );
782
+ queryText = built.text.replace(/\$(\d+)/g, "?");
783
+ queryValues = built.values;
325
784
  } else {
326
785
  const built = buildQuery(
327
786
  sqlDef.query,
@@ -726,7 +1185,7 @@ apiApp.route("/data-source", data_source_default);
726
1185
  apiApp.route("/data-source-meta", data_source_meta_default);
727
1186
  apiApp.route("/cache", cache_default);
728
1187
  apiApp.route("/", pages_default);
729
- reloadEnvFile(path4.join(process.cwd(), "..", "..", ".env"));
1188
+ reloadEnvFile(path4.join(process.cwd(), ".env"));
730
1189
  await initialize();
731
1190
  startWatching();
732
1191
  watchConnectionsFile();
@@ -735,5 +1194,12 @@ app5.get("/healthz", (c) => c.json({ status: "ok" }));
735
1194
  app5.route("/api", apiApp);
736
1195
  var src_default = app5;
737
1196
  export {
738
- src_default as default
1197
+ createAirtableClient,
1198
+ createDbtClient,
1199
+ createGoogleAnalyticsClient,
1200
+ createKintoneClient,
1201
+ createWixStoreClient,
1202
+ src_default as default,
1203
+ getClient,
1204
+ loadConnections
739
1205
  };