@squadbase/vite-server 0.0.1-build-12 → 0.0.1-build-14

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
@@ -13,19 +13,7 @@ import path2 from "path";
13
13
  import { readFileSync, watch as fsWatch } from "fs";
14
14
  import { readFile } from "fs/promises";
15
15
  import path from "path";
16
-
17
- // src/connector-client/postgresql.ts
18
- import pg from "pg";
19
- var { Pool } = pg;
20
- function createPostgreSQLClient(connectionString) {
21
- const pool = new Pool({ connectionString, ssl: { rejectUnauthorized: false } });
22
- return {
23
- async query(sql, params) {
24
- const result = await pool.query(sql, params);
25
- return { rows: result.rows };
26
- }
27
- };
28
- }
16
+ import { connectors } from "@squadbase/connectors";
29
17
 
30
18
  // src/connector-client/env.ts
31
19
  function resolveEnvVar(entry, key, connectionId) {
@@ -45,392 +33,8 @@ function resolveEnvVarOptional(entry, key) {
45
33
  return process.env[envVarName] || void 0;
46
34
  }
47
35
 
48
- // src/connector-client/bigquery.ts
49
- function createBigQueryClient(entry, connectionId) {
50
- const projectId = resolveEnvVar(entry, "project-id", connectionId);
51
- const serviceAccountJsonBase64 = resolveEnvVar(entry, "service-account-key-json-base64", connectionId);
52
- const serviceAccountJson = Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8");
53
- let gcpCredentials;
54
- try {
55
- gcpCredentials = JSON.parse(serviceAccountJson);
56
- } catch {
57
- throw new Error(
58
- `BigQuery service account JSON (decoded from base64) is not valid JSON for connectionId "${connectionId}"`
59
- );
60
- }
61
- return {
62
- async query(sql) {
63
- const { BigQuery } = await import("@google-cloud/bigquery");
64
- const bq = new BigQuery({ projectId, credentials: gcpCredentials });
65
- const [job] = await bq.createQueryJob({ query: sql });
66
- const [allRows] = await job.getQueryResults({ timeoutMs: 3e4 });
67
- return { rows: allRows };
68
- }
69
- };
70
- }
71
-
72
- // src/connection.ts
73
- import { getContext } from "hono/context-storage";
74
- import { getCookie } from "hono/cookie";
75
- var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
76
- var PREVIEW_SESSION_COOKIE_NAME = "squadbase-preview-session";
77
- var APP_BASE_DOMAIN = "squadbase.app";
78
- var PREVIEW_BASE_DOMAIN = "preview.app.squadbase.dev";
79
- var SANDBOX_ID_ENV_NAME = "INTERNAL_SQUADBASE_SANDBOX_ID";
80
- var MACHINE_CREDENTIAL_ENV_NAME = "INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL";
81
- function resolveProxyUrl(connectionId) {
82
- const connectionPath = `/_sqcore/connections/${connectionId}/request`;
83
- const sandboxId = process.env[SANDBOX_ID_ENV_NAME];
84
- if (sandboxId) {
85
- const baseDomain2 = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? PREVIEW_BASE_DOMAIN;
86
- return `https://${sandboxId}.${baseDomain2}${connectionPath}`;
87
- }
88
- const projectId = process.env["SQUADBASE_PROJECT_ID"];
89
- if (!projectId) {
90
- throw new Error(
91
- "Project ID is required. Please set SQUADBASE_PROJECT_ID environment variable."
92
- );
93
- }
94
- const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? APP_BASE_DOMAIN;
95
- return `https://${projectId}.${baseDomain}${connectionPath}`;
96
- }
97
- function resolveAuthHeaders() {
98
- const machineCredential = process.env[MACHINE_CREDENTIAL_ENV_NAME];
99
- if (machineCredential) {
100
- return { Authorization: `Bearer ${machineCredential}` };
101
- }
102
- const c = getContext();
103
- const cookies = getCookie(c);
104
- const previewSession = cookies[PREVIEW_SESSION_COOKIE_NAME];
105
- if (previewSession) {
106
- return {
107
- Cookie: `${PREVIEW_SESSION_COOKIE_NAME}=${previewSession}`
108
- };
109
- }
110
- const appSession = cookies[APP_SESSION_COOKIE_NAME];
111
- if (appSession) {
112
- return { Authorization: `Bearer ${appSession}` };
113
- }
114
- throw new Error(
115
- "No authentication method available for connection proxy. Expected one of: INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL env var, preview session cookie, or app session cookie."
116
- );
117
- }
118
- function connection(connectionId) {
119
- return {
120
- async fetch(url, options) {
121
- const proxyUrl = resolveProxyUrl(connectionId);
122
- const authHeaders = resolveAuthHeaders();
123
- return await fetch(proxyUrl, {
124
- method: "POST",
125
- headers: {
126
- "Content-Type": "application/json",
127
- ...authHeaders
128
- },
129
- body: JSON.stringify({
130
- url,
131
- method: options?.method,
132
- headers: options?.headers,
133
- body: options?.body,
134
- timeoutMs: options?.timeoutMs
135
- })
136
- });
137
- }
138
- };
139
- }
140
-
141
- // src/connector-client/bigquery-oauth.ts
142
- var MAX_RESULTS = 1e4;
143
- var POLL_INTERVAL_MS = 1e3;
144
- var POLL_TIMEOUT_MS = 12e4;
145
- function flattenRows(fields, rows) {
146
- return rows.map((row) => {
147
- const obj = {};
148
- for (let i = 0; i < fields.length; i++) {
149
- obj[fields[i].name] = row.f[i].v;
150
- }
151
- return obj;
152
- });
153
- }
154
- function createBigQueryOAuthClient(entry, connectionId) {
155
- const projectId = resolveEnvVar(entry, "project-id", connectionId);
156
- const baseUrl = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}`;
157
- return {
158
- async query(sql) {
159
- const conn = connection(connectionId);
160
- const res = await conn.fetch(`${baseUrl}/queries`, {
161
- method: "POST",
162
- body: {
163
- query: sql,
164
- useLegacySql: false,
165
- maxResults: MAX_RESULTS
166
- }
167
- });
168
- if (!res.ok) {
169
- const text = await res.text().catch(() => res.statusText);
170
- throw new Error(`BigQuery query failed: HTTP ${res.status} ${text}`);
171
- }
172
- let data = await res.json();
173
- if (data.errors?.length) {
174
- throw new Error(
175
- `BigQuery query error: ${data.errors.map((e) => e.message).join("; ")}`
176
- );
177
- }
178
- if (!data.jobComplete) {
179
- const jobId = data.jobReference.jobId;
180
- const location = data.jobReference.location;
181
- const deadline = Date.now() + POLL_TIMEOUT_MS;
182
- while (!data.jobComplete) {
183
- if (Date.now() > deadline) {
184
- throw new Error(
185
- `BigQuery query timed out after ${POLL_TIMEOUT_MS / 1e3}s (jobId: ${jobId})`
186
- );
187
- }
188
- await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
189
- const params = new URLSearchParams({
190
- maxResults: String(MAX_RESULTS)
191
- });
192
- if (location) params.set("location", location);
193
- const pollRes = await conn.fetch(
194
- `${baseUrl}/queries/${jobId}?${params}`,
195
- { method: "GET" }
196
- );
197
- if (!pollRes.ok) {
198
- const text = await pollRes.text().catch(() => pollRes.statusText);
199
- throw new Error(
200
- `BigQuery poll failed: HTTP ${pollRes.status} ${text}`
201
- );
202
- }
203
- data = await pollRes.json();
204
- if (data.errors?.length) {
205
- throw new Error(
206
- `BigQuery query error: ${data.errors.map((e) => e.message).join("; ")}`
207
- );
208
- }
209
- }
210
- }
211
- const fields = data.schema?.fields ?? [];
212
- const rawRows = data.rows ?? [];
213
- return { rows: flattenRows(fields, rawRows) };
214
- }
215
- };
216
- }
217
-
218
- // src/connector-client/snowflake.ts
219
- function createSnowflakeClient(entry, connectionId) {
220
- const accountIdentifier = resolveEnvVar(entry, "account", connectionId);
221
- const user = resolveEnvVar(entry, "user", connectionId);
222
- const role = resolveEnvVar(entry, "role", connectionId);
223
- const warehouse = resolveEnvVar(entry, "warehouse", connectionId);
224
- const privateKeyBase64 = resolveEnvVar(entry, "private-key-base64", connectionId);
225
- const privateKey = Buffer.from(privateKeyBase64, "base64").toString("utf-8");
226
- return {
227
- async query(sql) {
228
- const snowflake = (await import("snowflake-sdk")).default;
229
- snowflake.configure({ logLevel: "ERROR" });
230
- const connection2 = snowflake.createConnection({
231
- account: accountIdentifier,
232
- username: user,
233
- role,
234
- warehouse,
235
- authenticator: "SNOWFLAKE_JWT",
236
- privateKey
237
- });
238
- await new Promise((resolve, reject) => {
239
- connection2.connect((err) => {
240
- if (err) reject(new Error(`Snowflake connect failed: ${err.message}`));
241
- else resolve();
242
- });
243
- });
244
- const rows = await new Promise((resolve, reject) => {
245
- connection2.execute({
246
- sqlText: sql,
247
- complete: (err, _stmt, rows2) => {
248
- if (err) reject(new Error(`Snowflake query failed: ${err.message}`));
249
- else resolve(rows2 ?? []);
250
- }
251
- });
252
- });
253
- connection2.destroy((err) => {
254
- if (err) console.warn(`[connector-client] Snowflake destroy error: ${err.message}`);
255
- });
256
- return { rows };
257
- }
258
- };
259
- }
260
-
261
- // src/connector-client/mysql.ts
262
- function createMySQLClient(entry, connectionId) {
263
- const connectionUrl = resolveEnvVar(entry, "connection-url", connectionId);
264
- let poolPromise = null;
265
- function getPool() {
266
- if (!poolPromise) {
267
- poolPromise = import("mysql2/promise").then(
268
- (mysql) => mysql.default.createPool(connectionUrl)
269
- );
270
- }
271
- return poolPromise;
272
- }
273
- return {
274
- async query(sql, params) {
275
- const pool = await getPool();
276
- const [rows] = await pool.execute(sql, params);
277
- return { rows };
278
- }
279
- };
280
- }
281
-
282
- // src/connector-client/aws-athena.ts
283
- function createAthenaClient(entry, connectionId) {
284
- const region = resolveEnvVar(entry, "aws-region", connectionId);
285
- const accessKeyId = resolveEnvVar(entry, "aws-access-key-id", connectionId);
286
- const secretAccessKey = resolveEnvVar(entry, "aws-secret-access-key", connectionId);
287
- const workgroup = resolveEnvVarOptional(entry, "workgroup") ?? "primary";
288
- const outputLocation = resolveEnvVarOptional(entry, "output-location");
289
- return {
290
- async query(sql) {
291
- const {
292
- AthenaClient,
293
- StartQueryExecutionCommand,
294
- GetQueryExecutionCommand,
295
- GetQueryResultsCommand
296
- } = await import("@aws-sdk/client-athena");
297
- const client = new AthenaClient({
298
- region,
299
- credentials: { accessKeyId, secretAccessKey }
300
- });
301
- const startParams = {
302
- QueryString: sql,
303
- WorkGroup: workgroup
304
- };
305
- if (outputLocation) {
306
- startParams.ResultConfiguration = { OutputLocation: outputLocation };
307
- }
308
- const { QueryExecutionId } = await client.send(
309
- new StartQueryExecutionCommand(startParams)
310
- );
311
- if (!QueryExecutionId) throw new Error("Athena: failed to start query execution");
312
- while (true) {
313
- const { QueryExecution } = await client.send(
314
- new GetQueryExecutionCommand({ QueryExecutionId })
315
- );
316
- const state = QueryExecution?.Status?.State;
317
- if (state === "SUCCEEDED") break;
318
- if (state === "FAILED") {
319
- throw new Error(
320
- `Athena query failed: ${QueryExecution?.Status?.StateChangeReason ?? "unknown"}`
321
- );
322
- }
323
- if (state === "CANCELLED") throw new Error("Athena query was cancelled");
324
- await new Promise((r) => setTimeout(r, 500));
325
- }
326
- const { ResultSet } = await client.send(
327
- new GetQueryResultsCommand({ QueryExecutionId })
328
- );
329
- const resultRows = ResultSet?.Rows ?? [];
330
- if (resultRows.length === 0) return { rows: [] };
331
- const headers = resultRows[0].Data?.map((d) => d.VarCharValue ?? "") ?? [];
332
- const rows = resultRows.slice(1).map((row) => {
333
- const obj = {};
334
- row.Data?.forEach((d, i) => {
335
- obj[headers[i]] = d.VarCharValue ?? null;
336
- });
337
- return obj;
338
- });
339
- return { rows };
340
- }
341
- };
342
- }
343
-
344
- // src/connector-client/redshift.ts
345
- function createRedshiftClient(entry, connectionId) {
346
- const region = resolveEnvVar(entry, "aws-region", connectionId);
347
- const accessKeyId = resolveEnvVar(entry, "aws-access-key-id", connectionId);
348
- const secretAccessKey = resolveEnvVar(entry, "aws-secret-access-key", connectionId);
349
- const database = resolveEnvVar(entry, "database", connectionId);
350
- const clusterIdentifier = resolveEnvVarOptional(entry, "cluster-identifier");
351
- const workgroupName = resolveEnvVarOptional(entry, "workgroup-name");
352
- const secretArn = resolveEnvVarOptional(entry, "secret-arn");
353
- const dbUser = resolveEnvVarOptional(entry, "db-user");
354
- return {
355
- async query(sql) {
356
- const {
357
- RedshiftDataClient,
358
- ExecuteStatementCommand,
359
- DescribeStatementCommand,
360
- GetStatementResultCommand
361
- } = await import("@aws-sdk/client-redshift-data");
362
- const client = new RedshiftDataClient({
363
- region,
364
- credentials: { accessKeyId, secretAccessKey }
365
- });
366
- const executeParams = {
367
- Sql: sql,
368
- Database: database
369
- };
370
- if (clusterIdentifier) executeParams.ClusterIdentifier = clusterIdentifier;
371
- if (workgroupName) executeParams.WorkgroupName = workgroupName;
372
- if (secretArn) executeParams.SecretArn = secretArn;
373
- if (dbUser) executeParams.DbUser = dbUser;
374
- const { Id } = await client.send(
375
- new ExecuteStatementCommand(executeParams)
376
- );
377
- if (!Id) throw new Error("Redshift: failed to start statement execution");
378
- while (true) {
379
- const desc = await client.send(new DescribeStatementCommand({ Id }));
380
- const status = desc.Status;
381
- if (status === "FINISHED") break;
382
- if (status === "FAILED") {
383
- throw new Error(`Redshift query failed: ${desc.Error ?? "unknown"}`);
384
- }
385
- if (status === "ABORTED") throw new Error("Redshift query was aborted");
386
- await new Promise((r) => setTimeout(r, 500));
387
- }
388
- const result = await client.send(new GetStatementResultCommand({ Id }));
389
- const columns = result.ColumnMetadata?.map((c) => c.name ?? "") ?? [];
390
- const rows = (result.Records ?? []).map((record) => {
391
- const obj = {};
392
- record.forEach((field, i) => {
393
- const col = columns[i];
394
- const value = field.stringValue ?? field.longValue ?? field.doubleValue ?? field.booleanValue ?? (field.isNull ? null : field.blobValue ?? null);
395
- obj[col] = value;
396
- });
397
- return obj;
398
- });
399
- return { rows };
400
- }
401
- };
402
- }
403
-
404
- // src/connector-client/databricks.ts
405
- function createDatabricksClient(entry, connectionId) {
406
- const host = resolveEnvVar(entry, "host", connectionId);
407
- const httpPath = resolveEnvVar(entry, "http-path", connectionId);
408
- const token = resolveEnvVar(entry, "token", connectionId);
409
- return {
410
- async query(sql) {
411
- const { DBSQLClient } = await import("@databricks/sql");
412
- const client = new DBSQLClient();
413
- await client.connect({ host, path: httpPath, token });
414
- try {
415
- const session = await client.openSession();
416
- try {
417
- const operation = await session.executeStatement(sql);
418
- const result = await operation.fetchAll();
419
- await operation.close();
420
- return { rows: result };
421
- } finally {
422
- await session.close();
423
- }
424
- } finally {
425
- await client.close();
426
- }
427
- }
428
- };
429
- }
430
-
431
36
  // src/connector-client/registry.ts
432
37
  function createConnectorRegistry() {
433
- const clientCache = /* @__PURE__ */ new Map();
434
38
  function getConnectionsFilePath() {
435
39
  return process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
436
40
  }
@@ -443,56 +47,28 @@ function createConnectorRegistry() {
443
47
  return {};
444
48
  }
445
49
  }
446
- async function getClient2(connectionId) {
50
+ async function getQuery2(connectionId) {
447
51
  const connections = await loadConnections2();
448
52
  const entry = connections[connectionId];
449
53
  if (!entry) {
450
- throw new Error(`connection '${connectionId}' not found in .squadbase/connections.json`);
451
- }
452
- const connectorSlug = entry.connector.slug;
453
- const cached = clientCache.get(connectionId);
454
- if (cached) return { client: cached, connectorSlug };
455
- if (connectorSlug === "snowflake") {
456
- return { client: createSnowflakeClient(entry, connectionId), connectorSlug };
457
- }
458
- if (connectorSlug === "bigquery") {
459
- if (entry.connector.authType === "oauth") {
460
- return { client: createBigQueryOAuthClient(entry, connectionId), connectorSlug };
461
- }
462
- return { client: createBigQueryClient(entry, connectionId), connectorSlug };
463
- }
464
- if (connectorSlug === "athena") {
465
- return { client: createAthenaClient(entry, connectionId), connectorSlug };
466
- }
467
- if (connectorSlug === "redshift") {
468
- return { client: createRedshiftClient(entry, connectionId), connectorSlug };
469
- }
470
- if (connectorSlug === "databricks") {
471
- return { client: createDatabricksClient(entry, connectionId), connectorSlug };
54
+ throw new Error(
55
+ `connection '${connectionId}' not found in .squadbase/connections.json`
56
+ );
472
57
  }
473
- if (connectorSlug === "mysql") {
474
- const client = createMySQLClient(entry, connectionId);
475
- clientCache.set(connectionId, client);
476
- return { client, connectorSlug };
58
+ const { slug, authType } = entry.connector;
59
+ const plugin = connectors.findByKey(slug, authType);
60
+ if (!plugin) {
61
+ throw new Error(
62
+ `connector "${slug}" (authType: ${authType ?? "none"}) is not registered in @squadbase/connectors`
63
+ );
477
64
  }
478
- if (connectorSlug === "postgresql" || connectorSlug === "squadbase-db") {
479
- const urlEnvName = entry.envVars["connection-url"];
480
- if (!urlEnvName) {
481
- throw new Error(`'connection-url' is not defined in envVars for connection '${connectionId}'`);
482
- }
483
- const connectionUrl = process.env[urlEnvName];
484
- if (!connectionUrl) {
485
- throw new Error(
486
- `environment variable '${urlEnvName}' (mapped from connection '${connectionId}') is not set`
487
- );
488
- }
489
- const client = createPostgreSQLClient(connectionUrl);
490
- clientCache.set(connectionId, client);
491
- return { client, connectorSlug };
65
+ if (!plugin.query) {
66
+ throw new Error(
67
+ `connector "${plugin.connectorKey}" does not support SQL queries. Non-SQL connectors (airtable, google-analytics, kintone, wix-store, dbt) should be used via TypeScript handlers.`
68
+ );
492
69
  }
493
- throw new Error(
494
- `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.`
495
- );
70
+ const params = resolveParams(entry, connectionId, plugin);
71
+ return (sql, namedParams) => plugin.query(params, sql, namedParams);
496
72
  }
497
73
  function reloadEnvFile2(envPath) {
498
74
  try {
@@ -515,14 +91,27 @@ function createConnectorRegistry() {
515
91
  const envPath = path.join(process.cwd(), ".env");
516
92
  try {
517
93
  fsWatch(filePath, { persistent: false }, () => {
518
- console.log("[connector-client] connections.json changed, clearing client cache");
519
- clientCache.clear();
94
+ console.log(
95
+ "[connector-client] connections.json changed"
96
+ );
520
97
  setImmediate(() => reloadEnvFile2(envPath));
521
98
  });
522
99
  } catch {
523
100
  }
524
101
  }
525
- return { getClient: getClient2, loadConnections: loadConnections2, reloadEnvFile: reloadEnvFile2, watchConnectionsFile: watchConnectionsFile2 };
102
+ return { getQuery: getQuery2, loadConnections: loadConnections2, reloadEnvFile: reloadEnvFile2, watchConnectionsFile: watchConnectionsFile2 };
103
+ }
104
+ function resolveParams(entry, connectionId, plugin) {
105
+ const params = {};
106
+ for (const param of Object.values(plugin.parameters)) {
107
+ if (param.required) {
108
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
109
+ } else {
110
+ const val = resolveEnvVarOptional(entry, param.slug);
111
+ if (val !== void 0) params[param.slug] = val;
112
+ }
113
+ }
114
+ return params;
526
115
  }
527
116
 
528
117
  // src/connector-client/airtable.ts
@@ -788,7 +377,7 @@ function createDbtClient(entry, slug) {
788
377
  }
789
378
 
790
379
  // src/connector-client/index.ts
791
- var { getClient, loadConnections, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
380
+ var { getQuery, loadConnections, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
792
381
 
793
382
  // src/types/data-source.ts
794
383
  import { z } from "zod";
@@ -883,24 +472,20 @@ async function loadTypeScriptHandler(absolutePath) {
883
472
  }
884
473
  return handler;
885
474
  }
886
- function buildQuery(queryTemplate, parameterMeta, runtimeParams) {
475
+ function applyDefaults(parameterMeta, runtimeParams) {
887
476
  const defaults = new Map(
888
477
  parameterMeta.map((p) => [p.name, p.default ?? null])
889
478
  );
890
- const placeholderToIndex = /* @__PURE__ */ new Map();
891
- const values = [];
892
- const text = queryTemplate.replace(
893
- /\{\{(\w+)\}\}/g,
894
- (_match, name) => {
895
- if (!placeholderToIndex.has(name)) {
896
- const value = Object.prototype.hasOwnProperty.call(runtimeParams, name) ? runtimeParams[name] : defaults.get(name) ?? null;
897
- values.push(value);
898
- placeholderToIndex.set(name, values.length);
899
- }
900
- return `$${placeholderToIndex.get(name)}`;
479
+ const result = {};
480
+ for (const [key, value] of Object.entries(runtimeParams)) {
481
+ result[key] = value;
482
+ }
483
+ for (const [key, defaultVal] of defaults) {
484
+ if (!(key in result)) {
485
+ result[key] = defaultVal;
901
486
  }
902
- );
903
- return { text, values };
487
+ }
488
+ return result;
904
489
  }
905
490
  var defaultDataSourceDir = path2.join(process.cwd(), "data-source");
906
491
  async function initialize() {
@@ -948,46 +533,12 @@ async function initialize() {
948
533
  cacheConfig: sqlDef.cache,
949
534
  _query: sqlDef.query,
950
535
  handler: async (runtimeParams) => {
951
- const { client, connectorSlug } = await getClient(sqlDef.connectionId);
952
- const isLiteralConnector = connectorSlug === "snowflake" || connectorSlug === "bigquery" || connectorSlug === "athena" || connectorSlug === "redshift" || connectorSlug === "databricks";
953
- let queryText;
954
- let queryValues;
955
- if (isLiteralConnector) {
956
- const defaults = new Map(
957
- (sqlDef.parameters ?? []).map((p) => [p.name, p.default ?? null])
958
- );
959
- queryText = sqlDef.query.replace(
960
- /\{\{(\w+)\}\}/g,
961
- (_match, name) => {
962
- const value = Object.prototype.hasOwnProperty.call(
963
- runtimeParams,
964
- name
965
- ) ? runtimeParams[name] : defaults.get(name) ?? "";
966
- if (typeof value === "string")
967
- return `'${value.replace(/'/g, "''")}'`;
968
- if (value === null || value === void 0) return "NULL";
969
- return String(value);
970
- }
971
- );
972
- queryValues = [];
973
- } else if (connectorSlug === "mysql") {
974
- const built = buildQuery(
975
- sqlDef.query,
976
- sqlDef.parameters ?? [],
977
- runtimeParams
978
- );
979
- queryText = built.text.replace(/\$(\d+)/g, "?");
980
- queryValues = built.values;
981
- } else {
982
- const built = buildQuery(
983
- sqlDef.query,
984
- sqlDef.parameters ?? [],
985
- runtimeParams
986
- );
987
- queryText = built.text;
988
- queryValues = built.values;
989
- }
990
- const result = await client.query(queryText, queryValues);
536
+ const query = await getQuery(sqlDef.connectionId);
537
+ const namedParams = applyDefaults(
538
+ sqlDef.parameters ?? [],
539
+ runtimeParams
540
+ );
541
+ const result = await query(sqlDef.query, namedParams);
991
542
  return result.rows;
992
543
  }
993
544
  };
@@ -1384,6 +935,75 @@ app4.get("/runtime-data", (c) => {
1384
935
  });
1385
936
  var pages_default = app4;
1386
937
 
938
+ // src/connection.ts
939
+ import { getContext } from "hono/context-storage";
940
+ import { getCookie } from "hono/cookie";
941
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
942
+ var PREVIEW_SESSION_COOKIE_NAME = "squadbase-preview-session";
943
+ var APP_BASE_DOMAIN = "squadbase.app";
944
+ var PREVIEW_BASE_DOMAIN = "preview.app.squadbase.dev";
945
+ var SANDBOX_ID_ENV_NAME = "INTERNAL_SQUADBASE_SANDBOX_ID";
946
+ var MACHINE_CREDENTIAL_ENV_NAME = "INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL";
947
+ function resolveProxyUrl(connectionId) {
948
+ const connectionPath = `/_sqcore/connections/${connectionId}/request`;
949
+ const sandboxId = process.env[SANDBOX_ID_ENV_NAME];
950
+ if (sandboxId) {
951
+ const baseDomain2 = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? PREVIEW_BASE_DOMAIN;
952
+ return `https://${sandboxId}.${baseDomain2}${connectionPath}`;
953
+ }
954
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
955
+ if (!projectId) {
956
+ throw new Error(
957
+ "Project ID is required. Please set SQUADBASE_PROJECT_ID environment variable."
958
+ );
959
+ }
960
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? APP_BASE_DOMAIN;
961
+ return `https://${projectId}.${baseDomain}${connectionPath}`;
962
+ }
963
+ function resolveAuthHeaders() {
964
+ const machineCredential = process.env[MACHINE_CREDENTIAL_ENV_NAME];
965
+ if (machineCredential) {
966
+ return { Authorization: `Bearer ${machineCredential}` };
967
+ }
968
+ const c = getContext();
969
+ const cookies = getCookie(c);
970
+ const previewSession = cookies[PREVIEW_SESSION_COOKIE_NAME];
971
+ if (previewSession) {
972
+ return {
973
+ Cookie: `${PREVIEW_SESSION_COOKIE_NAME}=${previewSession}`
974
+ };
975
+ }
976
+ const appSession = cookies[APP_SESSION_COOKIE_NAME];
977
+ if (appSession) {
978
+ return { Authorization: `Bearer ${appSession}` };
979
+ }
980
+ throw new Error(
981
+ "No authentication method available for connection proxy. Expected one of: INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL env var, preview session cookie, or app session cookie."
982
+ );
983
+ }
984
+ function connection(connectionId) {
985
+ return {
986
+ async fetch(url, options) {
987
+ const proxyUrl = resolveProxyUrl(connectionId);
988
+ const authHeaders = resolveAuthHeaders();
989
+ return await fetch(proxyUrl, {
990
+ method: "POST",
991
+ headers: {
992
+ "Content-Type": "application/json",
993
+ ...authHeaders
994
+ },
995
+ body: JSON.stringify({
996
+ url,
997
+ method: options?.method,
998
+ headers: options?.headers,
999
+ body: options?.body,
1000
+ timeoutMs: options?.timeoutMs
1001
+ })
1002
+ });
1003
+ }
1004
+ };
1005
+ }
1006
+
1387
1007
  // src/index.ts
1388
1008
  var apiApp = new Hono5();
1389
1009
  apiApp.use("/*", contextStorage());
@@ -1408,6 +1028,6 @@ export {
1408
1028
  createKintoneClient,
1409
1029
  createWixStoreClient,
1410
1030
  src_default as default,
1411
- getClient,
1031
+ getQuery,
1412
1032
  loadConnections
1413
1033
  };