@squadbase/vite-server 0.0.1-build-10 → 0.0.1-build-12
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 +230 -7
- package/dist/index.d.ts +11 -1
- package/dist/index.js +236 -25
- package/dist/main.js +235 -25
- package/dist/types/data-source.d.ts +176 -54
- package/dist/types/data-source.js +71 -0
- package/dist/vite-plugin.js +215 -4
- package/package.json +3 -2
package/dist/vite-plugin.js
CHANGED
|
@@ -70,6 +70,152 @@ function createBigQueryClient(entry, connectionId) {
|
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// src/connection.ts
|
|
74
|
+
import { getContext } from "hono/context-storage";
|
|
75
|
+
import { getCookie } from "hono/cookie";
|
|
76
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
77
|
+
var PREVIEW_SESSION_COOKIE_NAME = "squadbase-preview-session";
|
|
78
|
+
var APP_BASE_DOMAIN = "squadbase.app";
|
|
79
|
+
var PREVIEW_BASE_DOMAIN = "preview.app.squadbase.dev";
|
|
80
|
+
var SANDBOX_ID_ENV_NAME = "INTERNAL_SQUADBASE_SANDBOX_ID";
|
|
81
|
+
var MACHINE_CREDENTIAL_ENV_NAME = "INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL";
|
|
82
|
+
function resolveProxyUrl(connectionId) {
|
|
83
|
+
const connectionPath = `/_sqcore/connections/${connectionId}/request`;
|
|
84
|
+
const sandboxId = process.env[SANDBOX_ID_ENV_NAME];
|
|
85
|
+
if (sandboxId) {
|
|
86
|
+
const baseDomain2 = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? PREVIEW_BASE_DOMAIN;
|
|
87
|
+
return `https://${sandboxId}.${baseDomain2}${connectionPath}`;
|
|
88
|
+
}
|
|
89
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
90
|
+
if (!projectId) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"Project ID is required. Please set SQUADBASE_PROJECT_ID environment variable."
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? APP_BASE_DOMAIN;
|
|
96
|
+
return `https://${projectId}.${baseDomain}${connectionPath}`;
|
|
97
|
+
}
|
|
98
|
+
function resolveAuthHeaders() {
|
|
99
|
+
const machineCredential = process.env[MACHINE_CREDENTIAL_ENV_NAME];
|
|
100
|
+
if (machineCredential) {
|
|
101
|
+
return { Authorization: `Bearer ${machineCredential}` };
|
|
102
|
+
}
|
|
103
|
+
const c = getContext();
|
|
104
|
+
const cookies = getCookie(c);
|
|
105
|
+
const previewSession = cookies[PREVIEW_SESSION_COOKIE_NAME];
|
|
106
|
+
if (previewSession) {
|
|
107
|
+
return {
|
|
108
|
+
Cookie: `${PREVIEW_SESSION_COOKIE_NAME}=${previewSession}`
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const appSession = cookies[APP_SESSION_COOKIE_NAME];
|
|
112
|
+
if (appSession) {
|
|
113
|
+
return { Authorization: `Bearer ${appSession}` };
|
|
114
|
+
}
|
|
115
|
+
throw new Error(
|
|
116
|
+
"No authentication method available for connection proxy. Expected one of: INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL env var, preview session cookie, or app session cookie."
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
function connection(connectionId) {
|
|
120
|
+
return {
|
|
121
|
+
async fetch(url, options) {
|
|
122
|
+
const proxyUrl = resolveProxyUrl(connectionId);
|
|
123
|
+
const authHeaders = resolveAuthHeaders();
|
|
124
|
+
return await fetch(proxyUrl, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: {
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
...authHeaders
|
|
129
|
+
},
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
url,
|
|
132
|
+
method: options?.method,
|
|
133
|
+
headers: options?.headers,
|
|
134
|
+
body: options?.body,
|
|
135
|
+
timeoutMs: options?.timeoutMs
|
|
136
|
+
})
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/connector-client/bigquery-oauth.ts
|
|
143
|
+
var MAX_RESULTS = 1e4;
|
|
144
|
+
var POLL_INTERVAL_MS = 1e3;
|
|
145
|
+
var POLL_TIMEOUT_MS = 12e4;
|
|
146
|
+
function flattenRows(fields, rows) {
|
|
147
|
+
return rows.map((row) => {
|
|
148
|
+
const obj = {};
|
|
149
|
+
for (let i = 0; i < fields.length; i++) {
|
|
150
|
+
obj[fields[i].name] = row.f[i].v;
|
|
151
|
+
}
|
|
152
|
+
return obj;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function createBigQueryOAuthClient(entry, connectionId) {
|
|
156
|
+
const projectId = resolveEnvVar(entry, "project-id", connectionId);
|
|
157
|
+
const baseUrl = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}`;
|
|
158
|
+
return {
|
|
159
|
+
async query(sql) {
|
|
160
|
+
const conn = connection(connectionId);
|
|
161
|
+
const res = await conn.fetch(`${baseUrl}/queries`, {
|
|
162
|
+
method: "POST",
|
|
163
|
+
body: {
|
|
164
|
+
query: sql,
|
|
165
|
+
useLegacySql: false,
|
|
166
|
+
maxResults: MAX_RESULTS
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
if (!res.ok) {
|
|
170
|
+
const text = await res.text().catch(() => res.statusText);
|
|
171
|
+
throw new Error(`BigQuery query failed: HTTP ${res.status} ${text}`);
|
|
172
|
+
}
|
|
173
|
+
let data = await res.json();
|
|
174
|
+
if (data.errors?.length) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`BigQuery query error: ${data.errors.map((e) => e.message).join("; ")}`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (!data.jobComplete) {
|
|
180
|
+
const jobId = data.jobReference.jobId;
|
|
181
|
+
const location = data.jobReference.location;
|
|
182
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
183
|
+
while (!data.jobComplete) {
|
|
184
|
+
if (Date.now() > deadline) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`BigQuery query timed out after ${POLL_TIMEOUT_MS / 1e3}s (jobId: ${jobId})`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
190
|
+
const params = new URLSearchParams({
|
|
191
|
+
maxResults: String(MAX_RESULTS)
|
|
192
|
+
});
|
|
193
|
+
if (location) params.set("location", location);
|
|
194
|
+
const pollRes = await conn.fetch(
|
|
195
|
+
`${baseUrl}/queries/${jobId}?${params}`,
|
|
196
|
+
{ method: "GET" }
|
|
197
|
+
);
|
|
198
|
+
if (!pollRes.ok) {
|
|
199
|
+
const text = await pollRes.text().catch(() => pollRes.statusText);
|
|
200
|
+
throw new Error(
|
|
201
|
+
`BigQuery poll failed: HTTP ${pollRes.status} ${text}`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
data = await pollRes.json();
|
|
205
|
+
if (data.errors?.length) {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`BigQuery query error: ${data.errors.map((e) => e.message).join("; ")}`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const fields = data.schema?.fields ?? [];
|
|
213
|
+
const rawRows = data.rows ?? [];
|
|
214
|
+
return { rows: flattenRows(fields, rawRows) };
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
73
219
|
// src/connector-client/snowflake.ts
|
|
74
220
|
function createSnowflakeClient(entry, connectionId) {
|
|
75
221
|
const accountIdentifier = resolveEnvVar(entry, "account", connectionId);
|
|
@@ -82,7 +228,7 @@ function createSnowflakeClient(entry, connectionId) {
|
|
|
82
228
|
async query(sql) {
|
|
83
229
|
const snowflake = (await import("snowflake-sdk")).default;
|
|
84
230
|
snowflake.configure({ logLevel: "ERROR" });
|
|
85
|
-
const
|
|
231
|
+
const connection2 = snowflake.createConnection({
|
|
86
232
|
account: accountIdentifier,
|
|
87
233
|
username: user,
|
|
88
234
|
role,
|
|
@@ -91,13 +237,13 @@ function createSnowflakeClient(entry, connectionId) {
|
|
|
91
237
|
privateKey
|
|
92
238
|
});
|
|
93
239
|
await new Promise((resolve, reject) => {
|
|
94
|
-
|
|
240
|
+
connection2.connect((err) => {
|
|
95
241
|
if (err) reject(new Error(`Snowflake connect failed: ${err.message}`));
|
|
96
242
|
else resolve();
|
|
97
243
|
});
|
|
98
244
|
});
|
|
99
245
|
const rows = await new Promise((resolve, reject) => {
|
|
100
|
-
|
|
246
|
+
connection2.execute({
|
|
101
247
|
sqlText: sql,
|
|
102
248
|
complete: (err, _stmt, rows2) => {
|
|
103
249
|
if (err) reject(new Error(`Snowflake query failed: ${err.message}`));
|
|
@@ -105,7 +251,7 @@ function createSnowflakeClient(entry, connectionId) {
|
|
|
105
251
|
}
|
|
106
252
|
});
|
|
107
253
|
});
|
|
108
|
-
|
|
254
|
+
connection2.destroy((err) => {
|
|
109
255
|
if (err) console.warn(`[connector-client] Snowflake destroy error: ${err.message}`);
|
|
110
256
|
});
|
|
111
257
|
return { rows };
|
|
@@ -311,6 +457,9 @@ function createConnectorRegistry() {
|
|
|
311
457
|
return { client: createSnowflakeClient(entry, connectionId), connectorSlug };
|
|
312
458
|
}
|
|
313
459
|
if (connectorSlug === "bigquery") {
|
|
460
|
+
if (entry.connector.authType === "oauth") {
|
|
461
|
+
return { client: createBigQueryOAuthClient(entry, connectionId), connectorSlug };
|
|
462
|
+
}
|
|
314
463
|
return { client: createBigQueryClient(entry, connectionId), connectorSlug };
|
|
315
464
|
}
|
|
316
465
|
if (connectorSlug === "athena") {
|
|
@@ -380,6 +529,68 @@ function createConnectorRegistry() {
|
|
|
380
529
|
// src/connector-client/index.ts
|
|
381
530
|
var { getClient, loadConnections, reloadEnvFile, watchConnectionsFile } = createConnectorRegistry();
|
|
382
531
|
|
|
532
|
+
// src/types/data-source.ts
|
|
533
|
+
import { z } from "zod";
|
|
534
|
+
var parameterMetaSchema = z.object({
|
|
535
|
+
name: z.string(),
|
|
536
|
+
type: z.enum(["string", "number", "boolean"]),
|
|
537
|
+
description: z.string(),
|
|
538
|
+
required: z.boolean().optional(),
|
|
539
|
+
default: z.union([z.string(), z.number(), z.boolean()]).optional()
|
|
540
|
+
});
|
|
541
|
+
var dataSourceCacheConfigSchema = z.object({
|
|
542
|
+
ttl: z.number(),
|
|
543
|
+
staleWhileRevalidate: z.boolean().optional()
|
|
544
|
+
});
|
|
545
|
+
var dataSourceSchemaObjectSchema = z.lazy(
|
|
546
|
+
() => z.object({
|
|
547
|
+
type: z.enum(["string", "number", "integer", "boolean", "object", "array", "null"]).optional(),
|
|
548
|
+
format: z.string().optional(),
|
|
549
|
+
description: z.string().optional(),
|
|
550
|
+
nullable: z.boolean().optional(),
|
|
551
|
+
enum: z.array(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional(),
|
|
552
|
+
items: dataSourceSchemaObjectSchema.optional(),
|
|
553
|
+
properties: z.record(z.string(), dataSourceSchemaObjectSchema).optional(),
|
|
554
|
+
required: z.array(z.string()).optional(),
|
|
555
|
+
additionalProperties: z.union([z.boolean(), dataSourceSchemaObjectSchema]).optional(),
|
|
556
|
+
minimum: z.number().optional(),
|
|
557
|
+
maximum: z.number().optional(),
|
|
558
|
+
minLength: z.number().optional(),
|
|
559
|
+
maxLength: z.number().optional(),
|
|
560
|
+
pattern: z.string().optional()
|
|
561
|
+
})
|
|
562
|
+
);
|
|
563
|
+
var dataSourceMediaTypeSchema = z.object({
|
|
564
|
+
schema: dataSourceSchemaObjectSchema.optional(),
|
|
565
|
+
example: z.unknown().optional()
|
|
566
|
+
});
|
|
567
|
+
var dataSourceResponseSchema = z.object({
|
|
568
|
+
description: z.string().optional(),
|
|
569
|
+
defaultContentType: z.string().optional(),
|
|
570
|
+
content: z.record(z.string(), dataSourceMediaTypeSchema).optional()
|
|
571
|
+
});
|
|
572
|
+
var jsonBaseFields = {
|
|
573
|
+
description: z.string(),
|
|
574
|
+
parameters: z.array(parameterMetaSchema).optional(),
|
|
575
|
+
response: dataSourceResponseSchema.optional(),
|
|
576
|
+
cache: dataSourceCacheConfigSchema.optional()
|
|
577
|
+
};
|
|
578
|
+
var jsonSqlDataSourceSchema = z.object({
|
|
579
|
+
...jsonBaseFields,
|
|
580
|
+
type: z.literal("sql").optional(),
|
|
581
|
+
query: z.string(),
|
|
582
|
+
connectionId: z.string()
|
|
583
|
+
});
|
|
584
|
+
var jsonTypeScriptDataSourceSchema = z.object({
|
|
585
|
+
...jsonBaseFields,
|
|
586
|
+
type: z.literal("typescript"),
|
|
587
|
+
handlerPath: z.string()
|
|
588
|
+
});
|
|
589
|
+
var anyJsonDataSourceSchema = z.union([
|
|
590
|
+
jsonTypeScriptDataSourceSchema,
|
|
591
|
+
jsonSqlDataSourceSchema
|
|
592
|
+
]);
|
|
593
|
+
|
|
383
594
|
// src/registry.ts
|
|
384
595
|
var viteServer = null;
|
|
385
596
|
function setViteServer(server) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squadbase/vite-server",
|
|
3
|
-
"version": "0.0.1-build-
|
|
3
|
+
"version": "0.0.1-build-12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
"hono": "^4.11.9",
|
|
48
48
|
"mysql2": "^3.11.0",
|
|
49
49
|
"pg": "^8.18.0",
|
|
50
|
-
"snowflake-sdk": "^1.15.0"
|
|
50
|
+
"snowflake-sdk": "^1.15.0",
|
|
51
|
+
"zod": "^4.3.6"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@clack/prompts": "^0.9.1",
|