@squadbase/vite-server 0.0.1-build-1 → 0.0.1-build-3

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/cli/index.js CHANGED
@@ -113,6 +113,11 @@ function resolveEnvVar(entry, key, slug) {
113
113
  }
114
114
  return value;
115
115
  }
116
+ function resolveEnvVarOptional(entry, key) {
117
+ const envVarName = entry.envVars[key];
118
+ if (!envVarName) return void 0;
119
+ return process.env[envVarName] || void 0;
120
+ }
116
121
 
117
122
  // src/connector-client/bigquery.ts
118
123
  function createBigQueryClient(entry, slug) {
@@ -181,6 +186,176 @@ function createSnowflakeClient(entry, slug) {
181
186
  };
182
187
  }
183
188
 
189
+ // src/connector-client/mysql.ts
190
+ function createMySQLClient(entry, slug) {
191
+ const connectionUrl = resolveEnvVar(entry, "connection-url", slug);
192
+ let poolPromise = null;
193
+ function getPool() {
194
+ if (!poolPromise) {
195
+ poolPromise = import("mysql2/promise").then(
196
+ (mysql) => mysql.default.createPool(connectionUrl)
197
+ );
198
+ }
199
+ return poolPromise;
200
+ }
201
+ return {
202
+ async query(sql, params) {
203
+ const pool = await getPool();
204
+ const [rows] = await pool.execute(sql, params);
205
+ return { rows };
206
+ }
207
+ };
208
+ }
209
+
210
+ // src/connector-client/aws-athena.ts
211
+ function createAthenaClient(entry, slug) {
212
+ const region = resolveEnvVar(entry, "aws-region", slug);
213
+ const accessKeyId = resolveEnvVar(entry, "aws-access-key-id", slug);
214
+ const secretAccessKey = resolveEnvVar(entry, "aws-secret-access-key", slug);
215
+ const workgroup = resolveEnvVarOptional(entry, "workgroup") ?? "primary";
216
+ const outputLocation = resolveEnvVarOptional(entry, "output-location");
217
+ return {
218
+ async query(sql) {
219
+ const {
220
+ AthenaClient,
221
+ StartQueryExecutionCommand,
222
+ GetQueryExecutionCommand,
223
+ GetQueryResultsCommand
224
+ } = await import("@aws-sdk/client-athena");
225
+ const client = new AthenaClient({
226
+ region,
227
+ credentials: { accessKeyId, secretAccessKey }
228
+ });
229
+ const startParams = {
230
+ QueryString: sql,
231
+ WorkGroup: workgroup
232
+ };
233
+ if (outputLocation) {
234
+ startParams.ResultConfiguration = { OutputLocation: outputLocation };
235
+ }
236
+ const { QueryExecutionId } = await client.send(
237
+ new StartQueryExecutionCommand(startParams)
238
+ );
239
+ if (!QueryExecutionId) throw new Error("Athena: failed to start query execution");
240
+ while (true) {
241
+ const { QueryExecution } = await client.send(
242
+ new GetQueryExecutionCommand({ QueryExecutionId })
243
+ );
244
+ const state = QueryExecution?.Status?.State;
245
+ if (state === "SUCCEEDED") break;
246
+ if (state === "FAILED") {
247
+ throw new Error(
248
+ `Athena query failed: ${QueryExecution?.Status?.StateChangeReason ?? "unknown"}`
249
+ );
250
+ }
251
+ if (state === "CANCELLED") throw new Error("Athena query was cancelled");
252
+ await new Promise((r) => setTimeout(r, 500));
253
+ }
254
+ const { ResultSet } = await client.send(
255
+ new GetQueryResultsCommand({ QueryExecutionId })
256
+ );
257
+ const resultRows = ResultSet?.Rows ?? [];
258
+ if (resultRows.length === 0) return { rows: [] };
259
+ const headers = resultRows[0].Data?.map((d) => d.VarCharValue ?? "") ?? [];
260
+ const rows = resultRows.slice(1).map((row) => {
261
+ const obj = {};
262
+ row.Data?.forEach((d, i) => {
263
+ obj[headers[i]] = d.VarCharValue ?? null;
264
+ });
265
+ return obj;
266
+ });
267
+ return { rows };
268
+ }
269
+ };
270
+ }
271
+
272
+ // src/connector-client/redshift.ts
273
+ function createRedshiftClient(entry, slug) {
274
+ const region = resolveEnvVar(entry, "aws-region", slug);
275
+ const accessKeyId = resolveEnvVar(entry, "aws-access-key-id", slug);
276
+ const secretAccessKey = resolveEnvVar(entry, "aws-secret-access-key", slug);
277
+ const database = resolveEnvVar(entry, "database", slug);
278
+ const clusterIdentifier = resolveEnvVarOptional(entry, "cluster-identifier");
279
+ const workgroupName = resolveEnvVarOptional(entry, "workgroup-name");
280
+ const secretArn = resolveEnvVarOptional(entry, "secret-arn");
281
+ const dbUser = resolveEnvVarOptional(entry, "db-user");
282
+ return {
283
+ async query(sql) {
284
+ const {
285
+ RedshiftDataClient,
286
+ ExecuteStatementCommand,
287
+ DescribeStatementCommand,
288
+ GetStatementResultCommand
289
+ } = await import("@aws-sdk/client-redshift-data");
290
+ const client = new RedshiftDataClient({
291
+ region,
292
+ credentials: { accessKeyId, secretAccessKey }
293
+ });
294
+ const executeParams = {
295
+ Sql: sql,
296
+ Database: database
297
+ };
298
+ if (clusterIdentifier) executeParams.ClusterIdentifier = clusterIdentifier;
299
+ if (workgroupName) executeParams.WorkgroupName = workgroupName;
300
+ if (secretArn) executeParams.SecretArn = secretArn;
301
+ if (dbUser) executeParams.DbUser = dbUser;
302
+ const { Id } = await client.send(
303
+ new ExecuteStatementCommand(executeParams)
304
+ );
305
+ if (!Id) throw new Error("Redshift: failed to start statement execution");
306
+ while (true) {
307
+ const desc = await client.send(new DescribeStatementCommand({ Id }));
308
+ const status = desc.Status;
309
+ if (status === "FINISHED") break;
310
+ if (status === "FAILED") {
311
+ throw new Error(`Redshift query failed: ${desc.Error ?? "unknown"}`);
312
+ }
313
+ if (status === "ABORTED") throw new Error("Redshift query was aborted");
314
+ await new Promise((r) => setTimeout(r, 500));
315
+ }
316
+ const result = await client.send(new GetStatementResultCommand({ Id }));
317
+ const columns = result.ColumnMetadata?.map((c) => c.name ?? "") ?? [];
318
+ const rows = (result.Records ?? []).map((record) => {
319
+ const obj = {};
320
+ record.forEach((field, i) => {
321
+ const col = columns[i];
322
+ const value = field.stringValue ?? field.longValue ?? field.doubleValue ?? field.booleanValue ?? (field.isNull ? null : field.blobValue ?? null);
323
+ obj[col] = value;
324
+ });
325
+ return obj;
326
+ });
327
+ return { rows };
328
+ }
329
+ };
330
+ }
331
+
332
+ // src/connector-client/databricks.ts
333
+ function createDatabricksClient(entry, slug) {
334
+ const host = resolveEnvVar(entry, "host", slug);
335
+ const httpPath = resolveEnvVar(entry, "http-path", slug);
336
+ const token = resolveEnvVar(entry, "token", slug);
337
+ return {
338
+ async query(sql) {
339
+ const { DBSQLClient } = await import("@databricks/sql");
340
+ const client = new DBSQLClient();
341
+ await client.connect({ host, path: httpPath, token });
342
+ try {
343
+ const session = await client.openSession();
344
+ try {
345
+ const operation = await session.executeStatement(sql);
346
+ const result = await operation.fetchAll();
347
+ await operation.close();
348
+ return { rows: result };
349
+ } finally {
350
+ await session.close();
351
+ }
352
+ } finally {
353
+ await client.close();
354
+ }
355
+ }
356
+ };
357
+ }
358
+
184
359
  // src/connector-client/registry.ts
185
360
  function createConnectorRegistry() {
186
361
  let connectionsCache = null;
@@ -188,7 +363,7 @@ function createConnectorRegistry() {
188
363
  function getConnectionsFilePath() {
189
364
  return process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), "../../.squadbase/connections.json");
190
365
  }
191
- function loadConnections() {
366
+ function loadConnections2() {
192
367
  if (connectionsCache !== null) return connectionsCache;
193
368
  const filePath = getConnectionsFilePath();
194
369
  try {
@@ -212,7 +387,7 @@ function createConnectorRegistry() {
212
387
  }
213
388
  const cached = clientCache.get(connectorSlug);
214
389
  if (cached) return cached;
215
- const connections = loadConnections();
390
+ const connections = loadConnections2();
216
391
  const entry = connections[connectorSlug];
217
392
  if (!entry) {
218
393
  throw new Error(`connector slug '${connectorSlug}' not found in .squadbase/connections.json`);
@@ -229,6 +404,20 @@ function createConnectorRegistry() {
229
404
  if (resolvedType === "bigquery") {
230
405
  return createBigQueryClient(entry, connectorSlug);
231
406
  }
407
+ if (resolvedType === "athena") {
408
+ return createAthenaClient(entry, connectorSlug);
409
+ }
410
+ if (resolvedType === "redshift") {
411
+ return createRedshiftClient(entry, connectorSlug);
412
+ }
413
+ if (resolvedType === "databricks") {
414
+ return createDatabricksClient(entry, connectorSlug);
415
+ }
416
+ if (resolvedType === "mysql") {
417
+ const client = createMySQLClient(entry, connectorSlug);
418
+ clientCache.set(connectorSlug, client);
419
+ return client;
420
+ }
232
421
  if (resolvedType === "postgresql" || resolvedType === "squadbase-db") {
233
422
  const urlEnvName = entry.envVars["connection-url"];
234
423
  if (!urlEnvName) {
@@ -245,7 +434,7 @@ function createConnectorRegistry() {
245
434
  return client;
246
435
  }
247
436
  throw new Error(
248
- `connector type '${resolvedType}' is not supported. Supported: "snowflake", "bigquery", "postgresql", "squadbase-db"`
437
+ `connector type '${resolvedType}' 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.`
249
438
  );
250
439
  }
251
440
  function reloadEnvFile2(envPath) {
@@ -277,11 +466,11 @@ function createConnectorRegistry() {
277
466
  } catch {
278
467
  }
279
468
  }
280
- return { getClient: getClient2, reloadEnvFile: reloadEnvFile2, watchConnectionsFile: watchConnectionsFile2 };
469
+ return { getClient: getClient2, loadConnections: loadConnections2, reloadEnvFile: reloadEnvFile2, watchConnectionsFile: watchConnectionsFile2 };
281
470
  }
282
471
 
283
472
  // src/connector-client/index.ts
284
- var { getClient, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
473
+ var { getClient, loadConnections, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
285
474
 
286
475
  // src/cli/env-loader.ts
287
476
  import { readFileSync as readFileSync2 } from "fs";
package/dist/index.d.ts CHANGED
@@ -1,6 +1,125 @@
1
1
  import * as hono_types from 'hono/types';
2
2
  import { Hono } from 'hono';
3
3
 
4
+ interface DatabaseClient {
5
+ query(sql: string, params?: unknown[]): Promise<{
6
+ rows: Record<string, unknown>[];
7
+ }>;
8
+ }
9
+ interface ConnectionEntry {
10
+ connectorType: string;
11
+ envVars: Record<string, string>;
12
+ }
13
+ type ConnectionsMap = Record<string, ConnectionEntry>;
14
+
15
+ interface AirtableClient {
16
+ listRecords(tableIdOrName: string, options?: {
17
+ fields?: string[];
18
+ filterByFormula?: string;
19
+ maxRecords?: number;
20
+ sort?: {
21
+ field: string;
22
+ direction?: "asc" | "desc";
23
+ }[];
24
+ pageSize?: number;
25
+ offset?: string;
26
+ }): Promise<{
27
+ records: AirtableRecord[];
28
+ offset?: string;
29
+ }>;
30
+ getRecord(tableIdOrName: string, recordId: string): Promise<AirtableRecord>;
31
+ }
32
+ interface AirtableRecord {
33
+ id: string;
34
+ fields: Record<string, unknown>;
35
+ createdTime: string;
36
+ }
37
+ declare function createAirtableClient(entry: ConnectionEntry, slug: string): AirtableClient;
38
+
39
+ interface GoogleAnalyticsClient {
40
+ runReport(request: {
41
+ dateRanges: {
42
+ startDate: string;
43
+ endDate: string;
44
+ }[];
45
+ dimensions?: {
46
+ name: string;
47
+ }[];
48
+ metrics: {
49
+ name: string;
50
+ }[];
51
+ limit?: number;
52
+ offset?: number;
53
+ orderBys?: unknown[];
54
+ }): Promise<{
55
+ rows: {
56
+ dimensionValues: {
57
+ value: string;
58
+ }[];
59
+ metricValues: {
60
+ value: string;
61
+ }[];
62
+ }[];
63
+ rowCount: number;
64
+ }>;
65
+ }
66
+ declare function createGoogleAnalyticsClient(entry: ConnectionEntry, slug: string): GoogleAnalyticsClient;
67
+
68
+ interface KintoneClient {
69
+ getRecords(appId: string | number, options?: {
70
+ query?: string;
71
+ fields?: string[];
72
+ totalCount?: boolean;
73
+ }): Promise<{
74
+ records: Record<string, unknown>[];
75
+ totalCount: string | null;
76
+ }>;
77
+ getRecord(appId: string | number, recordId: string | number): Promise<{
78
+ record: Record<string, unknown>;
79
+ }>;
80
+ listApps(options?: {
81
+ ids?: (string | number)[];
82
+ name?: string;
83
+ limit?: number;
84
+ offset?: number;
85
+ }): Promise<{
86
+ apps: Record<string, unknown>[];
87
+ }>;
88
+ }
89
+ declare function createKintoneClient(entry: ConnectionEntry, slug: string): KintoneClient;
90
+
91
+ interface WixStoreClient {
92
+ queryProducts(options?: {
93
+ query?: Record<string, unknown>;
94
+ limit?: number;
95
+ offset?: number;
96
+ }): Promise<{
97
+ products: Record<string, unknown>[];
98
+ totalResults: number;
99
+ }>;
100
+ queryOrders(options?: {
101
+ query?: Record<string, unknown>;
102
+ limit?: number;
103
+ offset?: number;
104
+ }): Promise<{
105
+ orders: Record<string, unknown>[];
106
+ totalResults: number;
107
+ }>;
108
+ }
109
+ declare function createWixStoreClient(entry: ConnectionEntry, slug: string): WixStoreClient;
110
+
111
+ interface DbtClient {
112
+ query(graphqlQuery: string, variables?: Record<string, unknown>): Promise<Record<string, unknown>>;
113
+ getModels(options?: {
114
+ limit?: number;
115
+ }): Promise<Record<string, unknown>[]>;
116
+ getModelByName(uniqueId: string): Promise<Record<string, unknown> | null>;
117
+ }
118
+ declare function createDbtClient(entry: ConnectionEntry, slug: string): DbtClient;
119
+
120
+ declare const getClient: (connectorSlug?: string, connectorType?: string) => Promise<DatabaseClient>;
121
+ declare const loadConnections: () => ConnectionsMap;
122
+
4
123
  declare const app: Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
5
124
 
6
- export { app as default };
125
+ export { type AirtableClient, type AirtableRecord, type ConnectionEntry, type ConnectionsMap, type DatabaseClient, type DbtClient, type GoogleAnalyticsClient, type KintoneClient, type WixStoreClient, createAirtableClient, createDbtClient, createGoogleAnalyticsClient, createKintoneClient, createWixStoreClient, app as default, getClient, loadConnections };