@squadbase/vite-server 0.1.12-dev.93b8799 → 0.1.17-dev.24af54e

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.
Files changed (77) hide show
  1. package/dist/cli/index.js +12128 -934
  2. package/dist/connectors/airtable-oauth.js +248 -46
  3. package/dist/connectors/airtable.js +285 -51
  4. package/dist/connectors/amplitude.js +288 -47
  5. package/dist/connectors/anthropic.js +126 -47
  6. package/dist/connectors/asana.js +293 -49
  7. package/dist/connectors/attio.js +268 -49
  8. package/dist/connectors/aws-billing.js +253 -46
  9. package/dist/connectors/azure-sql.js +387 -102
  10. package/dist/connectors/backlog-api-key.js +283 -47
  11. package/dist/connectors/clickup.js +304 -49
  12. package/dist/connectors/cosmosdb.js +271 -50
  13. package/dist/connectors/customerio.js +285 -47
  14. package/dist/connectors/dbt.js +306 -47
  15. package/dist/connectors/freshdesk.js +308 -53
  16. package/dist/connectors/freshsales.js +299 -52
  17. package/dist/connectors/freshservice.js +327 -53
  18. package/dist/connectors/gamma.js +293 -52
  19. package/dist/connectors/gemini.js +125 -47
  20. package/dist/connectors/github.js +352 -49
  21. package/dist/connectors/gmail-oauth.js +170 -7
  22. package/dist/connectors/gmail.js +316 -47
  23. package/dist/connectors/google-ads.js +254 -46
  24. package/dist/connectors/google-analytics-oauth.js +276 -46
  25. package/dist/connectors/google-analytics.js +378 -49
  26. package/dist/connectors/google-audit-log.js +404 -47
  27. package/dist/connectors/google-calendar-oauth.js +225 -46
  28. package/dist/connectors/google-calendar.js +325 -47
  29. package/dist/connectors/google-docs.js +186 -6
  30. package/dist/connectors/google-drive.js +228 -5
  31. package/dist/connectors/google-search-console-oauth.js +222 -46
  32. package/dist/connectors/google-sheets.js +238 -47
  33. package/dist/connectors/google-slides.js +171 -6
  34. package/dist/connectors/grafana.js +298 -49
  35. package/dist/connectors/hubspot-oauth.js +174 -5
  36. package/dist/connectors/hubspot.js +272 -49
  37. package/dist/connectors/influxdb.js +382 -51
  38. package/dist/connectors/intercom-oauth.js +176 -5
  39. package/dist/connectors/intercom.js +268 -49
  40. package/dist/connectors/jdbc.js +728 -110
  41. package/dist/connectors/jira-api-key.js +292 -47
  42. package/dist/connectors/kintone-api-token.js +247 -47
  43. package/dist/connectors/kintone.js +294 -47
  44. package/dist/connectors/linear.js +296 -49
  45. package/dist/connectors/linkedin-ads.js +234 -50
  46. package/dist/connectors/mailchimp-oauth.js +234 -46
  47. package/dist/connectors/mailchimp.js +286 -49
  48. package/dist/connectors/meta-ads-oauth.js +239 -48
  49. package/dist/connectors/meta-ads.js +251 -50
  50. package/dist/connectors/mixpanel.js +304 -47
  51. package/dist/connectors/monday.js +326 -49
  52. package/dist/connectors/mongodb.js +285 -57
  53. package/dist/connectors/notion-oauth.js +197 -5
  54. package/dist/connectors/notion.js +289 -51
  55. package/dist/connectors/openai.js +125 -47
  56. package/dist/connectors/oracle.js +405 -103
  57. package/dist/connectors/outlook-oauth.js +170 -5
  58. package/dist/connectors/powerbi-oauth.js +217 -5
  59. package/dist/connectors/salesforce.js +350 -49
  60. package/dist/connectors/semrush.js +280 -49
  61. package/dist/connectors/sentry.js +255 -50
  62. package/dist/connectors/shopify-oauth.js +153 -5
  63. package/dist/connectors/shopify.js +323 -47
  64. package/dist/connectors/sqlserver.js +381 -102
  65. package/dist/connectors/stripe-api-key.js +235 -46
  66. package/dist/connectors/stripe-oauth.js +168 -5
  67. package/dist/connectors/supabase.js +269 -48
  68. package/dist/connectors/tableau.js +337 -206
  69. package/dist/connectors/tiktok-ads.js +245 -48
  70. package/dist/connectors/wix-store.js +286 -49
  71. package/dist/connectors/zendesk-oauth.js +205 -5
  72. package/dist/connectors/zendesk.js +324 -47
  73. package/dist/index.d.ts +149 -1
  74. package/dist/index.js +18297 -6886
  75. package/dist/main.js +12785 -1382
  76. package/dist/vite-plugin.js +12140 -936
  77. package/package.json +1 -1
@@ -1,48 +1,60 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
1
6
  // ../connectors/src/parameter-definition.ts
2
- var ParameterDefinition = class {
3
- slug;
4
- name;
5
- description;
6
- envVarBaseKey;
7
- type;
8
- secret;
9
- required;
10
- constructor(config) {
11
- this.slug = config.slug;
12
- this.name = config.name;
13
- this.description = config.description;
14
- this.envVarBaseKey = config.envVarBaseKey;
15
- this.type = config.type;
16
- this.secret = config.secret;
17
- this.required = config.required;
18
- }
19
- /**
20
- * Get the parameter value from a ConnectorConnectionObject.
21
- */
22
- getValue(connection2) {
23
- const param = connection2.parameters.find(
24
- (p) => p.parameterSlug === this.slug
25
- );
26
- if (!param || param.value == null) {
27
- throw new Error(
28
- `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
29
- );
30
- }
31
- return param.value;
32
- }
33
- /**
34
- * Try to get the parameter value. Returns undefined if not found (for optional params).
35
- */
36
- tryGetValue(connection2) {
37
- const param = connection2.parameters.find(
38
- (p) => p.parameterSlug === this.slug
39
- );
40
- if (!param || param.value == null) return void 0;
41
- return param.value;
7
+ var ParameterDefinition;
8
+ var init_parameter_definition = __esm({
9
+ "../connectors/src/parameter-definition.ts"() {
10
+ "use strict";
11
+ ParameterDefinition = class {
12
+ slug;
13
+ name;
14
+ description;
15
+ envVarBaseKey;
16
+ type;
17
+ secret;
18
+ required;
19
+ constructor(config) {
20
+ this.slug = config.slug;
21
+ this.name = config.name;
22
+ this.description = config.description;
23
+ this.envVarBaseKey = config.envVarBaseKey;
24
+ this.type = config.type;
25
+ this.secret = config.secret;
26
+ this.required = config.required;
27
+ }
28
+ /**
29
+ * Get the parameter value from a ConnectorConnectionObject.
30
+ */
31
+ getValue(connection2) {
32
+ const param = connection2.parameters.find(
33
+ (p) => p.parameterSlug === this.slug
34
+ );
35
+ if (!param || param.value == null) {
36
+ throw new Error(
37
+ `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
38
+ );
39
+ }
40
+ return param.value;
41
+ }
42
+ /**
43
+ * Try to get the parameter value. Returns undefined if not found (for optional params).
44
+ */
45
+ tryGetValue(connection2) {
46
+ const param = connection2.parameters.find(
47
+ (p) => p.parameterSlug === this.slug
48
+ );
49
+ if (!param || param.value == null) return void 0;
50
+ return param.value;
51
+ }
52
+ };
42
53
  }
43
- };
54
+ });
44
55
 
45
56
  // ../connectors/src/connectors/gamma/parameters.ts
57
+ init_parameter_definition();
46
58
  var parameters = {
47
59
  apiKey: new ParameterDefinition({
48
60
  slug: "api-key",
@@ -218,6 +230,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
218
230
  * `runSetupFlow` from `setup-flow.ts`.
219
231
  */
220
232
  setup;
233
+ /**
234
+ * Opt-out of the default "verify before save" behavior on connection
235
+ * creation. The backend invokes `checkConnection` synchronously while
236
+ * creating the connection and aborts (no row inserted) if it fails — this
237
+ * flag disables that for connectors where the check cannot succeed pre-save:
238
+ *
239
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
240
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
241
+ * connectionId, which doesn't exist until the row is saved
242
+ *
243
+ * Exceptions are the explicit position; new credential-input connectors get
244
+ * the default verify-on-create behavior without opt-in.
245
+ */
246
+ skipConnectionCheckOnCreate;
221
247
  constructor(config) {
222
248
  this.slug = config.slug;
223
249
  this.authType = config.authType;
@@ -235,6 +261,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
235
261
  this.query = config.query;
236
262
  this.checkConnection = config.checkConnection;
237
263
  this.setup = config.setup;
264
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
238
265
  }
239
266
  get connectorKey() {
240
267
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -299,6 +326,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
299
326
  }
300
327
  };
301
328
 
329
+ // ../connectors/src/setup-flow.ts
330
+ async function runSetupFlow(flow, params, ctx, config) {
331
+ const runtime = {
332
+ params,
333
+ language: ctx.language,
334
+ config
335
+ };
336
+ let state = flow.initialState();
337
+ let answerIdx = 0;
338
+ for (const step of flow.steps) {
339
+ const ans = ctx.answers[answerIdx];
340
+ if (ans && ans.questionSlug === step.slug) {
341
+ state = step.applyAnswer(state, ans.answer);
342
+ answerIdx += 1;
343
+ continue;
344
+ }
345
+ if (step.type === "text") {
346
+ return {
347
+ type: "nextQuestion",
348
+ questionSlug: step.slug,
349
+ question: step.question[ctx.language],
350
+ questionType: "text"
351
+ };
352
+ }
353
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
354
+ if (options.length === 0) {
355
+ continue;
356
+ }
357
+ return {
358
+ type: "nextQuestion",
359
+ questionSlug: step.slug,
360
+ question: step.question[ctx.language],
361
+ questionType: step.type,
362
+ options
363
+ };
364
+ }
365
+ const dataInvestigationResult = await flow.finalize(state, runtime);
366
+ return { type: "fulfilled", dataInvestigationResult };
367
+ }
368
+ async function resolveSetupSelection(params) {
369
+ const { selected, allSentinel, fetchAll, limit } = params;
370
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
371
+ return resolved.slice(0, limit);
372
+ }
373
+
302
374
  // ../connectors/src/auth-types.ts
303
375
  var AUTH_TYPES = {
304
376
  OAUTH: "oauth",
@@ -321,9 +393,122 @@ var gammaOnboarding = new ConnectorOnboarding({
321
393
  }
322
394
  });
323
395
 
396
+ // ../connectors/src/connectors/gamma/utils.ts
397
+ var BASE_URL2 = "https://public-api.gamma.app/v1.0";
398
+ function apiFetch(params, path2, init) {
399
+ const apiKey = params[parameters.apiKey.slug];
400
+ if (!apiKey) {
401
+ throw new Error(`gamma: missing required parameter: ${parameters.apiKey.slug}`);
402
+ }
403
+ const headers = new Headers(init?.headers);
404
+ headers.set("X-API-KEY", apiKey);
405
+ if (!headers.has("Content-Type")) headers.set("Content-Type", "application/json");
406
+ const trimmedPath = path2.startsWith("/") ? path2 : `/${path2}`;
407
+ return fetch(`${BASE_URL2}${trimmedPath}`, { ...init, headers });
408
+ }
409
+
410
+ // ../connectors/src/connectors/gamma/setup-flow.ts
411
+ var ALL_FOLDERS = "__ALL_FOLDERS__";
412
+ var GAMMA_SETUP_MAX_FOLDERS = 20;
413
+ var FOLDERS_PAGE_LIMIT = 100;
414
+ async function listAllFolders(params) {
415
+ const results = [];
416
+ let after;
417
+ for (let i = 0; i < 10; i++) {
418
+ const qs = new URLSearchParams();
419
+ qs.set("limit", String(FOLDERS_PAGE_LIMIT));
420
+ if (after) qs.set("after", after);
421
+ const res = await apiFetch(params, `/folders?${qs.toString()}`);
422
+ if (!res.ok) {
423
+ const body = await res.text().catch(() => res.statusText);
424
+ throw new Error(`gamma: listFolders failed (${res.status}): ${body}`);
425
+ }
426
+ const data = await res.json();
427
+ for (const item of data.data ?? []) results.push(item);
428
+ if (!data.hasMore || !data.nextCursor) break;
429
+ after = data.nextCursor;
430
+ }
431
+ return results;
432
+ }
433
+ async function listThemes(params) {
434
+ const res = await apiFetch(params, "/themes?limit=100");
435
+ if (!res.ok) {
436
+ return [];
437
+ }
438
+ const data = await res.json();
439
+ return data.data ?? [];
440
+ }
441
+ function folderLabel(f) {
442
+ return f.name ?? f.title ?? f.id ?? "(Untitled)";
443
+ }
444
+ var gammaSetupFlow = {
445
+ initialState: () => ({}),
446
+ steps: [
447
+ {
448
+ slug: "folders",
449
+ type: "multiSelect",
450
+ question: {
451
+ ja: "\u5BFE\u8C61\u306E\u30D5\u30A9\u30EB\u30C0\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
452
+ en: "Select target folders (multi-select allowed)"
453
+ },
454
+ async fetchOptions(_state, rt) {
455
+ const folders = await listAllFolders(rt.params);
456
+ const options = folders.filter((f) => f.id).map((f) => ({ value: f.id, label: folderLabel(f) }));
457
+ return [
458
+ {
459
+ value: ALL_FOLDERS,
460
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D5\u30A9\u30EB\u30C0" : "All folders"
461
+ },
462
+ ...options
463
+ ];
464
+ },
465
+ applyAnswer: (state, answer) => ({ ...state, folders: answer })
466
+ }
467
+ ],
468
+ async finalize(state, rt) {
469
+ if (!state.folders) {
470
+ throw new Error("Gamma setup: incomplete state on finalize");
471
+ }
472
+ const allFolders = await listAllFolders(rt.params);
473
+ const folderById = new Map(
474
+ allFolders.filter((f) => f.id).map((f) => [f.id, f])
475
+ );
476
+ const targetIds = await resolveSetupSelection({
477
+ selected: state.folders,
478
+ allSentinel: ALL_FOLDERS,
479
+ fetchAll: async () => allFolders.map((f) => f.id ?? "").filter((id) => id),
480
+ limit: GAMMA_SETUP_MAX_FOLDERS
481
+ });
482
+ const sections = ["## Gamma", ""];
483
+ if (!targetIds.length) {
484
+ sections.push("_No folders selected._", "");
485
+ } else {
486
+ sections.push(`### Folders (${targetIds.length})`, "");
487
+ for (const id of targetIds) {
488
+ const folder = folderById.get(id);
489
+ sections.push(`- ${folderLabel(folder ?? { id })} (id: \`${id}\`)`);
490
+ }
491
+ sections.push("");
492
+ }
493
+ const themes = await listThemes(rt.params);
494
+ if (themes.length) {
495
+ sections.push(`### Available themes (${themes.length})`, "");
496
+ for (const theme of themes.slice(0, 20)) {
497
+ const label = theme.name ?? theme.id ?? "(unnamed)";
498
+ sections.push(`- ${label}`);
499
+ }
500
+ if (themes.length > 20) {
501
+ sections.push(`- \u2026and ${themes.length - 20} more`);
502
+ }
503
+ sections.push("");
504
+ }
505
+ return sections.join("\n");
506
+ }
507
+ };
508
+
324
509
  // ../connectors/src/connectors/gamma/tools/request.ts
325
510
  import { z } from "zod";
326
- var BASE_URL2 = "https://public-api.gamma.app/v1.0";
511
+ var BASE_URL3 = "https://public-api.gamma.app/v1.0";
327
512
  var REQUEST_TIMEOUT_MS = 6e4;
328
513
  var inputSchema = z.object({
329
514
  toolUseIntent: z.string().optional().describe(
@@ -368,7 +553,7 @@ For creating presentations/documents, prefer the gamma_generate tool instead.`,
368
553
  );
369
554
  try {
370
555
  const apiKey = parameters.apiKey.getValue(connection2);
371
- const url = `${BASE_URL2}${path2}`;
556
+ const url = `${BASE_URL3}${path2}`;
372
557
  const controller = new AbortController();
373
558
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
374
559
  try {
@@ -400,7 +585,7 @@ For creating presentations/documents, prefer the gamma_generate tool instead.`,
400
585
 
401
586
  // ../connectors/src/connectors/gamma/tools/generate.ts
402
587
  import { z as z2 } from "zod";
403
- var BASE_URL3 = "https://public-api.gamma.app/v1.0";
588
+ var BASE_URL4 = "https://public-api.gamma.app/v1.0";
404
589
  var POLL_INTERVAL_MS = 5e3;
405
590
  var MAX_POLL_DURATION_MS = 3e5;
406
591
  var inputSchema2 = z2.object({
@@ -517,7 +702,7 @@ Gamma does NOT support image uploads. To visualize data, embed raw numbers direc
517
702
  if (textAmount) textOptions.amount = textAmount;
518
703
  if (Object.keys(textOptions).length > 0) body.textOptions = textOptions;
519
704
  if (imageSource) body.imageOptions = { source: imageSource };
520
- const createRes = await fetch(`${BASE_URL3}/generations`, {
705
+ const createRes = await fetch(`${BASE_URL4}/generations`, {
521
706
  method: "POST",
522
707
  headers,
523
708
  body: JSON.stringify(body)
@@ -537,7 +722,7 @@ Gamma does NOT support image uploads. To visualize data, embed raw numbers direc
537
722
  const deadline = Date.now() + MAX_POLL_DURATION_MS;
538
723
  while (Date.now() < deadline) {
539
724
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
540
- const pollRes = await fetch(`${BASE_URL3}/generations/${generationId}`, {
725
+ const pollRes = await fetch(`${BASE_URL4}/generations/${generationId}`, {
541
726
  method: "GET",
542
727
  headers
543
728
  });
@@ -736,7 +921,43 @@ export default async function handler(c: Context) {
736
921
  #### \u30C7\u30FC\u30BF\u306E\u53EF\u8996\u5316
737
922
  Gamma\u306F\u753B\u50CF\u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093\u3002\u30C7\u30FC\u30BF\u3092\u53EF\u8996\u5316\u3057\u305F\u3044\u5834\u5408\uFF08\u30C1\u30E3\u30FC\u30C8\u3001\u30B0\u30E9\u30D5\u3001\u30C6\u30FC\u30D6\u30EB\u306A\u3069\uFF09\u306F\u3001\`inputText\` \u306B\u6570\u5024\u3084\u30C7\u30FC\u30BF\u3092\u69CB\u9020\u5316\u30C6\u30AD\u30B9\u30C8\uFF08\u30DE\u30FC\u30AF\u30C0\u30A6\u30F3\u30C6\u30FC\u30D6\u30EB\u3001\u6570\u5024\u4ED8\u304D\u7B87\u6761\u66F8\u304D\u306A\u3069\uFF09\u3068\u3057\u3066\u76F4\u63A5\u57CB\u3081\u8FBC\u3093\u3067\u304F\u3060\u3055\u3044\u3002Gamma AI\u304C\u30C7\u30FC\u30BF\u304B\u3089\u9069\u5207\u306A\u30D3\u30B8\u30E5\u30A2\u30EB\u8981\u7D20\u3092\u751F\u6210\u3057\u307E\u3059\u3002\u30ED\u30FC\u30AB\u30EB\u3067\u30C1\u30E3\u30FC\u30C8\u753B\u50CF\u3092\u751F\u6210\u3057\u3066\u542B\u3081\u308B\u306E\u3067\u306F\u306A\u304F\u3001\u30C7\u30FC\u30BF\u306E\u5024\u3092\u30A4\u30F3\u30E9\u30A4\u30F3\u3067\u6E21\u3057\u3066Gamma\u306B\u53EF\u8996\u5316\u3055\u305B\u3066\u304F\u3060\u3055\u3044\u3002`
738
923
  },
739
- tools
924
+ tools,
925
+ setup: (params, ctx, config) => runSetupFlow(gammaSetupFlow, params, ctx, config),
926
+ async checkConnection(params, _config) {
927
+ const apiKey = params[parameters.apiKey.slug];
928
+ if (!apiKey) {
929
+ return {
930
+ success: false,
931
+ error: `Missing required parameter: ${parameters.apiKey.slug}`
932
+ };
933
+ }
934
+ try {
935
+ const res = await fetch(
936
+ "https://public-api.gamma.app/v1.0/folders?limit=1",
937
+ {
938
+ method: "GET",
939
+ headers: {
940
+ "X-API-KEY": apiKey,
941
+ Accept: "application/json"
942
+ }
943
+ }
944
+ );
945
+ if (!res.ok) {
946
+ const data = await res.json().catch(() => null);
947
+ const message = typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `HTTP ${res.status} ${res.statusText}`;
948
+ return {
949
+ success: false,
950
+ error: `Gamma API failed: ${message}`
951
+ };
952
+ }
953
+ return { success: true };
954
+ } catch (error) {
955
+ return {
956
+ success: false,
957
+ error: error instanceof Error ? error.message : String(error)
958
+ };
959
+ }
960
+ }
740
961
  });
741
962
 
742
963
  // src/connectors/create-connector-sdk.ts
@@ -765,6 +986,7 @@ function resolveEnvVarOptional(entry, key) {
765
986
  import { getContext } from "hono/context-storage";
766
987
  import { getCookie } from "hono/cookie";
767
988
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
989
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
768
990
  function normalizeHeaders(input) {
769
991
  const out = {};
770
992
  if (!input) return out;
@@ -773,6 +995,11 @@ function normalizeHeaders(input) {
773
995
  });
774
996
  return out;
775
997
  }
998
+ function extractInputUrl(input) {
999
+ if (typeof input === "string") return input;
1000
+ if (input instanceof URL) return input.href;
1001
+ return input.url;
1002
+ }
776
1003
  function createSandboxProxyFetch(connectionId) {
777
1004
  return async (input, init) => {
778
1005
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -782,10 +1009,17 @@ function createSandboxProxyFetch(connectionId) {
782
1009
  "Connection proxy is not configured. Please check your deployment settings."
783
1010
  );
784
1011
  }
785
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1012
+ const originalUrl = extractInputUrl(input);
1013
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
1014
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
1015
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
1016
+ return fetch(sessionUrl, {
1017
+ method: "POST",
1018
+ headers: { Authorization: `Bearer ${token}` }
1019
+ });
1020
+ }
786
1021
  const originalMethod = init?.method ?? "GET";
787
1022
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
788
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
789
1023
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
790
1024
  return fetch(proxyUrl, {
791
1025
  method: "POST",
@@ -811,10 +1045,9 @@ function createDeployedAppProxyFetch(connectionId) {
811
1045
  }
812
1046
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
813
1047
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
1048
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
814
1049
  return async (input, init) => {
815
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
816
- const originalMethod = init?.method ?? "GET";
817
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
1050
+ const originalUrl = extractInputUrl(input);
818
1051
  const c = getContext();
819
1052
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
820
1053
  if (!appSession) {
@@ -822,6 +1055,14 @@ function createDeployedAppProxyFetch(connectionId) {
822
1055
  "No authentication method available for connection proxy."
823
1056
  );
824
1057
  }
1058
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
1059
+ return fetch(sessionUrl, {
1060
+ method: "POST",
1061
+ headers: { Authorization: `Bearer ${appSession}` }
1062
+ });
1063
+ }
1064
+ const originalMethod = init?.method ?? "GET";
1065
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
825
1066
  return fetch(proxyUrl, {
826
1067
  method: "POST",
827
1068
  headers: {
@@ -1,48 +1,60 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
1
6
  // ../connectors/src/parameter-definition.ts
2
- var ParameterDefinition = class {
3
- slug;
4
- name;
5
- description;
6
- envVarBaseKey;
7
- type;
8
- secret;
9
- required;
10
- constructor(config) {
11
- this.slug = config.slug;
12
- this.name = config.name;
13
- this.description = config.description;
14
- this.envVarBaseKey = config.envVarBaseKey;
15
- this.type = config.type;
16
- this.secret = config.secret;
17
- this.required = config.required;
18
- }
19
- /**
20
- * Get the parameter value from a ConnectorConnectionObject.
21
- */
22
- getValue(connection2) {
23
- const param = connection2.parameters.find(
24
- (p) => p.parameterSlug === this.slug
25
- );
26
- if (!param || param.value == null) {
27
- throw new Error(
28
- `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
29
- );
30
- }
31
- return param.value;
32
- }
33
- /**
34
- * Try to get the parameter value. Returns undefined if not found (for optional params).
35
- */
36
- tryGetValue(connection2) {
37
- const param = connection2.parameters.find(
38
- (p) => p.parameterSlug === this.slug
39
- );
40
- if (!param || param.value == null) return void 0;
41
- return param.value;
7
+ var ParameterDefinition;
8
+ var init_parameter_definition = __esm({
9
+ "../connectors/src/parameter-definition.ts"() {
10
+ "use strict";
11
+ ParameterDefinition = class {
12
+ slug;
13
+ name;
14
+ description;
15
+ envVarBaseKey;
16
+ type;
17
+ secret;
18
+ required;
19
+ constructor(config) {
20
+ this.slug = config.slug;
21
+ this.name = config.name;
22
+ this.description = config.description;
23
+ this.envVarBaseKey = config.envVarBaseKey;
24
+ this.type = config.type;
25
+ this.secret = config.secret;
26
+ this.required = config.required;
27
+ }
28
+ /**
29
+ * Get the parameter value from a ConnectorConnectionObject.
30
+ */
31
+ getValue(connection2) {
32
+ const param = connection2.parameters.find(
33
+ (p) => p.parameterSlug === this.slug
34
+ );
35
+ if (!param || param.value == null) {
36
+ throw new Error(
37
+ `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
38
+ );
39
+ }
40
+ return param.value;
41
+ }
42
+ /**
43
+ * Try to get the parameter value. Returns undefined if not found (for optional params).
44
+ */
45
+ tryGetValue(connection2) {
46
+ const param = connection2.parameters.find(
47
+ (p) => p.parameterSlug === this.slug
48
+ );
49
+ if (!param || param.value == null) return void 0;
50
+ return param.value;
51
+ }
52
+ };
42
53
  }
43
- };
54
+ });
44
55
 
45
56
  // ../connectors/src/connectors/gemini/parameters.ts
57
+ init_parameter_definition();
46
58
  var parameters = {
47
59
  apiKey: new ParameterDefinition({
48
60
  slug: "api-key",
@@ -91,6 +103,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
91
103
  * `runSetupFlow` from `setup-flow.ts`.
92
104
  */
93
105
  setup;
106
+ /**
107
+ * Opt-out of the default "verify before save" behavior on connection
108
+ * creation. The backend invokes `checkConnection` synchronously while
109
+ * creating the connection and aborts (no row inserted) if it fails — this
110
+ * flag disables that for connectors where the check cannot succeed pre-save:
111
+ *
112
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
113
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
114
+ * connectionId, which doesn't exist until the row is saved
115
+ *
116
+ * Exceptions are the explicit position; new credential-input connectors get
117
+ * the default verify-on-create behavior without opt-in.
118
+ */
119
+ skipConnectionCheckOnCreate;
94
120
  constructor(config) {
95
121
  this.slug = config.slug;
96
122
  this.authType = config.authType;
@@ -108,6 +134,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
108
134
  this.query = config.query;
109
135
  this.checkConnection = config.checkConnection;
110
136
  this.setup = config.setup;
137
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
111
138
  }
112
139
  get connectorKey() {
113
140
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -235,7 +262,38 @@ export default async function handler(c: Context) {
235
262
  }
236
263
  \`\`\``
237
264
  },
238
- tools
265
+ tools,
266
+ async checkConnection(params, _config) {
267
+ try {
268
+ const apiKey = params[parameters.apiKey.slug];
269
+ if (!apiKey) {
270
+ return {
271
+ success: false,
272
+ error: "Missing required parameter: api-key"
273
+ };
274
+ }
275
+ const url = `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`;
276
+ const res = await fetch(url, {
277
+ method: "GET",
278
+ headers: {
279
+ Accept: "application/json"
280
+ }
281
+ });
282
+ if (!res.ok) {
283
+ const errorText = await res.text().catch(() => res.statusText);
284
+ return {
285
+ success: false,
286
+ error: `Gemini API failed: HTTP ${res.status} ${errorText}`
287
+ };
288
+ }
289
+ return { success: true };
290
+ } catch (error) {
291
+ return {
292
+ success: false,
293
+ error: error instanceof Error ? error.message : String(error)
294
+ };
295
+ }
296
+ }
239
297
  });
240
298
 
241
299
  // src/connectors/create-connector-sdk.ts
@@ -264,6 +322,7 @@ function resolveEnvVarOptional(entry, key) {
264
322
  import { getContext } from "hono/context-storage";
265
323
  import { getCookie } from "hono/cookie";
266
324
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
325
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
267
326
  function normalizeHeaders(input) {
268
327
  const out = {};
269
328
  if (!input) return out;
@@ -272,6 +331,11 @@ function normalizeHeaders(input) {
272
331
  });
273
332
  return out;
274
333
  }
334
+ function extractInputUrl(input) {
335
+ if (typeof input === "string") return input;
336
+ if (input instanceof URL) return input.href;
337
+ return input.url;
338
+ }
275
339
  function createSandboxProxyFetch(connectionId) {
276
340
  return async (input, init) => {
277
341
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -281,10 +345,17 @@ function createSandboxProxyFetch(connectionId) {
281
345
  "Connection proxy is not configured. Please check your deployment settings."
282
346
  );
283
347
  }
284
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
348
+ const originalUrl = extractInputUrl(input);
349
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
350
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
351
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
352
+ return fetch(sessionUrl, {
353
+ method: "POST",
354
+ headers: { Authorization: `Bearer ${token}` }
355
+ });
356
+ }
285
357
  const originalMethod = init?.method ?? "GET";
286
358
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
287
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
288
359
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
289
360
  return fetch(proxyUrl, {
290
361
  method: "POST",
@@ -310,10 +381,9 @@ function createDeployedAppProxyFetch(connectionId) {
310
381
  }
311
382
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
312
383
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
384
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
313
385
  return async (input, init) => {
314
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
315
- const originalMethod = init?.method ?? "GET";
316
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
386
+ const originalUrl = extractInputUrl(input);
317
387
  const c = getContext();
318
388
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
319
389
  if (!appSession) {
@@ -321,6 +391,14 @@ function createDeployedAppProxyFetch(connectionId) {
321
391
  "No authentication method available for connection proxy."
322
392
  );
323
393
  }
394
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
395
+ return fetch(sessionUrl, {
396
+ method: "POST",
397
+ headers: { Authorization: `Bearer ${appSession}` }
398
+ });
399
+ }
400
+ const originalMethod = init?.method ?? "GET";
401
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
324
402
  return fetch(proxyUrl, {
325
403
  method: "POST",
326
404
  headers: {