@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/amplitude/parameters.ts
57
+ init_parameter_definition();
46
58
  var parameters = {
47
59
  apiKey: new ParameterDefinition({
48
60
  slug: "api-key",
@@ -224,6 +236,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
224
236
  * `runSetupFlow` from `setup-flow.ts`.
225
237
  */
226
238
  setup;
239
+ /**
240
+ * Opt-out of the default "verify before save" behavior on connection
241
+ * creation. The backend invokes `checkConnection` synchronously while
242
+ * creating the connection and aborts (no row inserted) if it fails — this
243
+ * flag disables that for connectors where the check cannot succeed pre-save:
244
+ *
245
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
246
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
247
+ * connectionId, which doesn't exist until the row is saved
248
+ *
249
+ * Exceptions are the explicit position; new credential-input connectors get
250
+ * the default verify-on-create behavior without opt-in.
251
+ */
252
+ skipConnectionCheckOnCreate;
227
253
  constructor(config) {
228
254
  this.slug = config.slug;
229
255
  this.authType = config.authType;
@@ -241,6 +267,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
241
267
  this.query = config.query;
242
268
  this.checkConnection = config.checkConnection;
243
269
  this.setup = config.setup;
270
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
244
271
  }
245
272
  get connectorKey() {
246
273
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -305,6 +332,46 @@ var ConnectorPlugin = class _ConnectorPlugin {
305
332
  }
306
333
  };
307
334
 
335
+ // ../connectors/src/setup-flow.ts
336
+ async function runSetupFlow(flow, params, ctx, config) {
337
+ const runtime = {
338
+ params,
339
+ language: ctx.language,
340
+ config
341
+ };
342
+ let state = flow.initialState();
343
+ let answerIdx = 0;
344
+ for (const step of flow.steps) {
345
+ const ans = ctx.answers[answerIdx];
346
+ if (ans && ans.questionSlug === step.slug) {
347
+ state = step.applyAnswer(state, ans.answer);
348
+ answerIdx += 1;
349
+ continue;
350
+ }
351
+ if (step.type === "text") {
352
+ return {
353
+ type: "nextQuestion",
354
+ questionSlug: step.slug,
355
+ question: step.question[ctx.language],
356
+ questionType: "text"
357
+ };
358
+ }
359
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
360
+ if (options.length === 0) {
361
+ continue;
362
+ }
363
+ return {
364
+ type: "nextQuestion",
365
+ questionSlug: step.slug,
366
+ question: step.question[ctx.language],
367
+ questionType: step.type,
368
+ options
369
+ };
370
+ }
371
+ const dataInvestigationResult = await flow.finalize(state, runtime);
372
+ return { type: "fulfilled", dataInvestigationResult };
373
+ }
374
+
308
375
  // ../connectors/src/auth-types.ts
309
376
  var AUTH_TYPES = {
310
377
  OAUTH: "oauth",
@@ -331,6 +398,125 @@ NOTE: The Dashboard REST API endpoints (events/segmentation, funnels, retention,
331
398
  }
332
399
  });
333
400
 
401
+ // ../connectors/src/connectors/amplitude/utils.ts
402
+ function getBaseUrl(params) {
403
+ const region = params[parameters.region.slug];
404
+ return region === "eu" ? "https://analytics.eu.amplitude.com" : "https://amplitude.com";
405
+ }
406
+ async function apiFetch(params, path2, init) {
407
+ const apiKey = params[parameters.apiKey.slug];
408
+ const secretKey = params[parameters.secretKey.slug];
409
+ if (!apiKey || !secretKey) {
410
+ throw new Error(
411
+ "amplitude: missing required parameters: api-key and secret-key"
412
+ );
413
+ }
414
+ const url = `${getBaseUrl(params)}${path2.startsWith("/") ? "" : "/"}${path2}`;
415
+ const headers = new Headers(init?.headers);
416
+ headers.set("Authorization", `Basic ${btoa(`${apiKey}:${secretKey}`)}`);
417
+ return fetch(url, { ...init, headers });
418
+ }
419
+
420
+ // ../connectors/src/connectors/amplitude/setup-flow.ts
421
+ var AMPLITUDE_SETUP_MAX_ENTITIES = 10;
422
+ var AMPLITUDE_SETUP_MAX_EVENTS = 50;
423
+ var ENTITY_LABELS = {
424
+ events: { en: "Events", ja: "Events (\u30A4\u30D9\u30F3\u30C8)" },
425
+ userProperties: {
426
+ en: "User properties",
427
+ ja: "User properties (\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D1\u30C6\u30A3)"
428
+ },
429
+ cohorts: { en: "Cohorts", ja: "Cohorts (\u30B3\u30DB\u30FC\u30C8)" },
430
+ charts: { en: "Charts", ja: "Charts (\u30C1\u30E3\u30FC\u30C8)" },
431
+ dashboards: { en: "Dashboards", ja: "Dashboards (\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9)" }
432
+ };
433
+ var ENTITY_DESCRIPTIONS = {
434
+ events: {
435
+ en: "Tracked event types with metadata.",
436
+ ja: "\u30E1\u30BF\u30C7\u30FC\u30BF\u4ED8\u304D\u3067\u8FFD\u8DE1\u3055\u308C\u3066\u3044\u308B\u30A4\u30D9\u30F3\u30C8\u30BF\u30A4\u30D7\u3002"
437
+ },
438
+ userProperties: {
439
+ en: "User-level properties used for segmentation.",
440
+ ja: "\u30BB\u30B0\u30E1\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3\u306B\u4F7F\u308F\u308C\u308B\u30E6\u30FC\u30B6\u30FC\u30EC\u30D9\u30EB\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3002"
441
+ },
442
+ cohorts: {
443
+ en: "Saved user cohorts.",
444
+ ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30E6\u30FC\u30B6\u30FC\u30B3\u30DB\u30FC\u30C8\u3002"
445
+ },
446
+ charts: {
447
+ en: "Saved analytics charts.",
448
+ ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30A2\u30CA\u30EA\u30C6\u30A3\u30AF\u30B9\u30C1\u30E3\u30FC\u30C8\u3002"
449
+ },
450
+ dashboards: {
451
+ en: "Saved dashboards.",
452
+ ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3002"
453
+ }
454
+ };
455
+ var ENTITY_VALUES = [
456
+ "events",
457
+ "userProperties",
458
+ "cohorts",
459
+ "charts",
460
+ "dashboards"
461
+ ];
462
+ async function fetchEventNames(params) {
463
+ try {
464
+ const res = await apiFetch(params, "/api/2/taxonomy/event");
465
+ if (!res.ok) return [];
466
+ const data = await res.json();
467
+ return (data.data ?? []).map((e) => e.event_type ?? "").filter((name) => name);
468
+ } catch {
469
+ return [];
470
+ }
471
+ }
472
+ var amplitudeSetupFlow = {
473
+ initialState: () => ({}),
474
+ steps: [
475
+ {
476
+ slug: "entities",
477
+ type: "multiSelect",
478
+ question: {
479
+ ja: "\u5BFE\u8C61\u306E\u30A8\u30F3\u30C6\u30A3\u30C6\u30A3\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
480
+ en: "Select target entities (multi-select allowed)"
481
+ },
482
+ async fetchOptions(_state, rt) {
483
+ return ENTITY_VALUES.map((value) => ({
484
+ value,
485
+ label: ENTITY_LABELS[value][rt.language]
486
+ }));
487
+ },
488
+ applyAnswer: (state, answer) => ({ ...state, entities: answer })
489
+ }
490
+ ],
491
+ async finalize(state, rt) {
492
+ if (!state.entities) {
493
+ throw new Error("Amplitude setup: incomplete state on finalize");
494
+ }
495
+ const selected = state.entities.filter(
496
+ (e) => ENTITY_VALUES.includes(e)
497
+ ).slice(0, AMPLITUDE_SETUP_MAX_ENTITIES);
498
+ const sections = ["## Amplitude", ""];
499
+ for (const entity of selected) {
500
+ sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
501
+ sections.push(ENTITY_DESCRIPTIONS[entity][rt.language], "");
502
+ if (entity === "events") {
503
+ const names = (await fetchEventNames(rt.params)).slice(
504
+ 0,
505
+ AMPLITUDE_SETUP_MAX_EVENTS
506
+ );
507
+ if (names.length > 0) {
508
+ sections.push("Event names:", "");
509
+ for (const name of names) {
510
+ sections.push(`- ${name}`);
511
+ }
512
+ sections.push("");
513
+ }
514
+ }
515
+ }
516
+ return sections.join("\n");
517
+ }
518
+ };
519
+
334
520
  // ../connectors/src/connectors/amplitude/tools/request.ts
335
521
  import { z } from "zod";
336
522
  var REQUEST_TIMEOUT_MS = 6e4;
@@ -559,7 +745,42 @@ export default async function handler(c: Context) {
559
745
  - \`i\` \u2014 \u30A4\u30F3\u30BF\u30FC\u30D0\u30EB\uFF081=\u65E5\u6B21\u30017=\u9031\u6B21\u300130=\u6708\u6B21\uFF09
560
746
  - \`g\` \u2014 \u30B0\u30EB\u30FC\u30D7\u5316\u30D7\u30ED\u30D1\u30C6\u30A3`
561
747
  },
562
- tools
748
+ tools,
749
+ setup: (params, ctx, config) => runSetupFlow(amplitudeSetupFlow, params, ctx, config),
750
+ async checkConnection(params, _config) {
751
+ const apiKey = params[parameters.apiKey.slug];
752
+ const secretKey = params[parameters.secretKey.slug];
753
+ if (!apiKey || !secretKey) {
754
+ return {
755
+ success: false,
756
+ error: "Missing required parameters: api-key and secret-key"
757
+ };
758
+ }
759
+ const region = params[parameters.region.slug];
760
+ const baseUrl = region === "eu" ? "https://analytics.eu.amplitude.com" : "https://amplitude.com";
761
+ try {
762
+ const res = await fetch(`${baseUrl}/api/2/events/list`, {
763
+ method: "GET",
764
+ headers: {
765
+ Authorization: `Basic ${btoa(`${apiKey}:${secretKey}`)}`,
766
+ Accept: "application/json"
767
+ }
768
+ });
769
+ if (!res.ok) {
770
+ const errorText = await res.text().catch(() => res.statusText);
771
+ return {
772
+ success: false,
773
+ error: `Amplitude API failed: HTTP ${res.status} ${errorText}`
774
+ };
775
+ }
776
+ return { success: true };
777
+ } catch (error) {
778
+ return {
779
+ success: false,
780
+ error: error instanceof Error ? error.message : String(error)
781
+ };
782
+ }
783
+ }
563
784
  });
564
785
 
565
786
  // src/connectors/create-connector-sdk.ts
@@ -588,6 +809,7 @@ function resolveEnvVarOptional(entry, key) {
588
809
  import { getContext } from "hono/context-storage";
589
810
  import { getCookie } from "hono/cookie";
590
811
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
812
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
591
813
  function normalizeHeaders(input) {
592
814
  const out = {};
593
815
  if (!input) return out;
@@ -596,6 +818,11 @@ function normalizeHeaders(input) {
596
818
  });
597
819
  return out;
598
820
  }
821
+ function extractInputUrl(input) {
822
+ if (typeof input === "string") return input;
823
+ if (input instanceof URL) return input.href;
824
+ return input.url;
825
+ }
599
826
  function createSandboxProxyFetch(connectionId) {
600
827
  return async (input, init) => {
601
828
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -605,10 +832,17 @@ function createSandboxProxyFetch(connectionId) {
605
832
  "Connection proxy is not configured. Please check your deployment settings."
606
833
  );
607
834
  }
608
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
835
+ const originalUrl = extractInputUrl(input);
836
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
837
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
838
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
839
+ return fetch(sessionUrl, {
840
+ method: "POST",
841
+ headers: { Authorization: `Bearer ${token}` }
842
+ });
843
+ }
609
844
  const originalMethod = init?.method ?? "GET";
610
845
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
611
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
612
846
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
613
847
  return fetch(proxyUrl, {
614
848
  method: "POST",
@@ -634,10 +868,9 @@ function createDeployedAppProxyFetch(connectionId) {
634
868
  }
635
869
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
636
870
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
871
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
637
872
  return async (input, init) => {
638
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
639
- const originalMethod = init?.method ?? "GET";
640
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
873
+ const originalUrl = extractInputUrl(input);
641
874
  const c = getContext();
642
875
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
643
876
  if (!appSession) {
@@ -645,6 +878,14 @@ function createDeployedAppProxyFetch(connectionId) {
645
878
  "No authentication method available for connection proxy."
646
879
  );
647
880
  }
881
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
882
+ return fetch(sessionUrl, {
883
+ method: "POST",
884
+ headers: { Authorization: `Bearer ${appSession}` }
885
+ });
886
+ }
887
+ const originalMethod = init?.method ?? "GET";
888
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
648
889
  return fetch(proxyUrl, {
649
890
  method: "POST",
650
891
  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/anthropic/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);
@@ -243,7 +270,39 @@ export default async function handler(c: Context) {
243
270
  }
244
271
  \`\`\``
245
272
  },
246
- tools
273
+ tools,
274
+ async checkConnection(params, _config) {
275
+ try {
276
+ const apiKey = params[parameters.apiKey.slug];
277
+ if (!apiKey) {
278
+ return {
279
+ success: false,
280
+ error: "Missing required parameter: api-key"
281
+ };
282
+ }
283
+ const res = await fetch("https://api.anthropic.com/v1/models", {
284
+ method: "GET",
285
+ headers: {
286
+ "x-api-key": apiKey,
287
+ "anthropic-version": "2023-06-01",
288
+ Accept: "application/json"
289
+ }
290
+ });
291
+ if (!res.ok) {
292
+ const errorText = await res.text().catch(() => res.statusText);
293
+ return {
294
+ success: false,
295
+ error: `Anthropic API failed: HTTP ${res.status} ${errorText}`
296
+ };
297
+ }
298
+ return { success: true };
299
+ } catch (error) {
300
+ return {
301
+ success: false,
302
+ error: error instanceof Error ? error.message : String(error)
303
+ };
304
+ }
305
+ }
247
306
  });
248
307
 
249
308
  // src/connectors/create-connector-sdk.ts
@@ -272,6 +331,7 @@ function resolveEnvVarOptional(entry, key) {
272
331
  import { getContext } from "hono/context-storage";
273
332
  import { getCookie } from "hono/cookie";
274
333
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
334
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
275
335
  function normalizeHeaders(input) {
276
336
  const out = {};
277
337
  if (!input) return out;
@@ -280,6 +340,11 @@ function normalizeHeaders(input) {
280
340
  });
281
341
  return out;
282
342
  }
343
+ function extractInputUrl(input) {
344
+ if (typeof input === "string") return input;
345
+ if (input instanceof URL) return input.href;
346
+ return input.url;
347
+ }
283
348
  function createSandboxProxyFetch(connectionId) {
284
349
  return async (input, init) => {
285
350
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -289,10 +354,17 @@ function createSandboxProxyFetch(connectionId) {
289
354
  "Connection proxy is not configured. Please check your deployment settings."
290
355
  );
291
356
  }
292
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
357
+ const originalUrl = extractInputUrl(input);
358
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
359
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
360
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
361
+ return fetch(sessionUrl, {
362
+ method: "POST",
363
+ headers: { Authorization: `Bearer ${token}` }
364
+ });
365
+ }
293
366
  const originalMethod = init?.method ?? "GET";
294
367
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
295
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
296
368
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
297
369
  return fetch(proxyUrl, {
298
370
  method: "POST",
@@ -318,10 +390,9 @@ function createDeployedAppProxyFetch(connectionId) {
318
390
  }
319
391
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
320
392
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
393
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
321
394
  return async (input, init) => {
322
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
323
- const originalMethod = init?.method ?? "GET";
324
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
395
+ const originalUrl = extractInputUrl(input);
325
396
  const c = getContext();
326
397
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
327
398
  if (!appSession) {
@@ -329,6 +400,14 @@ function createDeployedAppProxyFetch(connectionId) {
329
400
  "No authentication method available for connection proxy."
330
401
  );
331
402
  }
403
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
404
+ return fetch(sessionUrl, {
405
+ method: "POST",
406
+ headers: { Authorization: `Bearer ${appSession}` }
407
+ });
408
+ }
409
+ const originalMethod = init?.method ?? "GET";
410
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
332
411
  return fetch(proxyUrl, {
333
412
  method: "POST",
334
413
  headers: {