@squadbase/vite-server 0.1.12-dev.a9ac647 → 0.1.17-dev.3b633bb

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 +14375 -1652
  2. package/dist/connectors/airtable-oauth.js +282 -46
  3. package/dist/connectors/airtable.js +319 -51
  4. package/dist/connectors/amplitude.js +322 -47
  5. package/dist/connectors/anthropic.js +135 -47
  6. package/dist/connectors/asana.js +327 -49
  7. package/dist/connectors/attio.js +302 -49
  8. package/dist/connectors/aws-billing.js +287 -46
  9. package/dist/connectors/azure-sql.js +421 -102
  10. package/dist/connectors/backlog-api-key.js +317 -47
  11. package/dist/connectors/clickup.js +338 -49
  12. package/dist/connectors/cosmosdb.js +305 -50
  13. package/dist/connectors/customerio.js +319 -47
  14. package/dist/connectors/dbt.js +340 -47
  15. package/dist/connectors/freshdesk.js +342 -53
  16. package/dist/connectors/freshsales.js +333 -52
  17. package/dist/connectors/freshservice.js +361 -53
  18. package/dist/connectors/gamma.js +327 -52
  19. package/dist/connectors/gemini.js +134 -47
  20. package/dist/connectors/github.js +386 -49
  21. package/dist/connectors/gmail-oauth.js +204 -7
  22. package/dist/connectors/gmail.js +350 -47
  23. package/dist/connectors/google-ads.js +288 -46
  24. package/dist/connectors/google-analytics-oauth.js +310 -46
  25. package/dist/connectors/google-analytics.js +547 -87
  26. package/dist/connectors/google-audit-log.js +438 -47
  27. package/dist/connectors/google-calendar-oauth.js +259 -46
  28. package/dist/connectors/google-calendar.js +359 -47
  29. package/dist/connectors/google-docs.js +220 -6
  30. package/dist/connectors/google-drive.js +262 -5
  31. package/dist/connectors/google-search-console-oauth.js +256 -46
  32. package/dist/connectors/google-sheets.js +272 -47
  33. package/dist/connectors/google-slides.js +205 -6
  34. package/dist/connectors/grafana.js +332 -49
  35. package/dist/connectors/hubspot-oauth.js +208 -5
  36. package/dist/connectors/hubspot.js +306 -49
  37. package/dist/connectors/influxdb.js +416 -51
  38. package/dist/connectors/intercom-oauth.js +210 -5
  39. package/dist/connectors/intercom.js +302 -49
  40. package/dist/connectors/jdbc.js +762 -110
  41. package/dist/connectors/jira-api-key.js +326 -47
  42. package/dist/connectors/kintone-api-token.js +281 -47
  43. package/dist/connectors/kintone.js +328 -47
  44. package/dist/connectors/linear.js +330 -49
  45. package/dist/connectors/linkedin-ads.js +268 -50
  46. package/dist/connectors/mailchimp-oauth.js +268 -46
  47. package/dist/connectors/mailchimp.js +320 -49
  48. package/dist/connectors/meta-ads-oauth.js +273 -48
  49. package/dist/connectors/meta-ads.js +285 -50
  50. package/dist/connectors/mixpanel.js +338 -47
  51. package/dist/connectors/monday.js +360 -49
  52. package/dist/connectors/mongodb.js +319 -57
  53. package/dist/connectors/notion-oauth.js +231 -5
  54. package/dist/connectors/notion.js +323 -51
  55. package/dist/connectors/openai.js +134 -47
  56. package/dist/connectors/oracle.js +454 -103
  57. package/dist/connectors/outlook-oauth.js +204 -5
  58. package/dist/connectors/powerbi-oauth.js +498 -5
  59. package/dist/connectors/salesforce.js +384 -49
  60. package/dist/connectors/semrush.js +609 -49
  61. package/dist/connectors/sentry.js +289 -50
  62. package/dist/connectors/shopify-oauth.js +187 -5
  63. package/dist/connectors/shopify.js +357 -47
  64. package/dist/connectors/sqlserver.js +415 -102
  65. package/dist/connectors/stripe-api-key.js +269 -46
  66. package/dist/connectors/stripe-oauth.js +202 -5
  67. package/dist/connectors/supabase.js +303 -48
  68. package/dist/connectors/tableau.js +536 -163
  69. package/dist/connectors/tiktok-ads.js +279 -48
  70. package/dist/connectors/wix-store.js +320 -49
  71. package/dist/connectors/zendesk-oauth.js +239 -5
  72. package/dist/connectors/zendesk.js +358 -47
  73. package/dist/index.d.ts +149 -1
  74. package/dist/index.js +15057 -2117
  75. package/dist/main.js +15005 -2073
  76. package/dist/vite-plugin.js +14752 -2019
  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",
@@ -216,6 +228,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
216
228
  tools;
217
229
  query;
218
230
  checkConnection;
231
+ /**
232
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
233
+ * implement this expose a step-by-step exploration flow (database/schema/
234
+ * table/etc. discovery) that the dashboard backend drives via the
235
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
236
+ * `runSetupFlow` from `setup-flow.ts`.
237
+ */
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;
219
253
  constructor(config) {
220
254
  this.slug = config.slug;
221
255
  this.authType = config.authType;
@@ -232,6 +266,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
232
266
  this.tools = config.tools;
233
267
  this.query = config.query;
234
268
  this.checkConnection = config.checkConnection;
269
+ this.setup = config.setup;
270
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
235
271
  }
236
272
  get connectorKey() {
237
273
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -296,6 +332,71 @@ var ConnectorPlugin = class _ConnectorPlugin {
296
332
  }
297
333
  };
298
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
+ const pendingParameterUpdates = [];
345
+ for (const step of flow.steps) {
346
+ const ans = ctx.answers[answerIdx];
347
+ if (ans && ans.questionSlug === step.slug) {
348
+ state = step.applyAnswer(state, ans.answer);
349
+ if (step.toParameterUpdates) {
350
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
351
+ }
352
+ answerIdx += 1;
353
+ continue;
354
+ }
355
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
356
+ if (step.type === "text") {
357
+ if (step.fetchOptions) {
358
+ const options2 = await step.fetchOptions(state, runtime);
359
+ if (options2.length === 0) {
360
+ continue;
361
+ }
362
+ }
363
+ return {
364
+ type: "nextQuestion",
365
+ questionSlug: step.slug,
366
+ question: step.question[ctx.language],
367
+ questionType: "text",
368
+ allowFreeText: resolvedAllowFreeText,
369
+ ...pendingParameterUpdates.length > 0 && {
370
+ parameterUpdates: pendingParameterUpdates
371
+ }
372
+ };
373
+ }
374
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
375
+ if (options.length === 0) {
376
+ continue;
377
+ }
378
+ return {
379
+ type: "nextQuestion",
380
+ questionSlug: step.slug,
381
+ question: step.question[ctx.language],
382
+ questionType: step.type,
383
+ options,
384
+ allowFreeText: resolvedAllowFreeText,
385
+ ...pendingParameterUpdates.length > 0 && {
386
+ parameterUpdates: pendingParameterUpdates
387
+ }
388
+ };
389
+ }
390
+ const dataInvestigationResult = await flow.finalize(state, runtime);
391
+ return {
392
+ type: "fulfilled",
393
+ dataInvestigationResult,
394
+ ...pendingParameterUpdates.length > 0 && {
395
+ parameterUpdates: pendingParameterUpdates
396
+ }
397
+ };
398
+ }
399
+
299
400
  // ../connectors/src/auth-types.ts
300
401
  var AUTH_TYPES = {
301
402
  OAUTH: "oauth",
@@ -322,6 +423,125 @@ NOTE: The Dashboard REST API endpoints (events/segmentation, funnels, retention,
322
423
  }
323
424
  });
324
425
 
426
+ // ../connectors/src/connectors/amplitude/utils.ts
427
+ function getBaseUrl(params) {
428
+ const region = params[parameters.region.slug];
429
+ return region === "eu" ? "https://analytics.eu.amplitude.com" : "https://amplitude.com";
430
+ }
431
+ async function apiFetch(params, path2, init) {
432
+ const apiKey = params[parameters.apiKey.slug];
433
+ const secretKey = params[parameters.secretKey.slug];
434
+ if (!apiKey || !secretKey) {
435
+ throw new Error(
436
+ "amplitude: missing required parameters: api-key and secret-key"
437
+ );
438
+ }
439
+ const url = `${getBaseUrl(params)}${path2.startsWith("/") ? "" : "/"}${path2}`;
440
+ const headers = new Headers(init?.headers);
441
+ headers.set("Authorization", `Basic ${btoa(`${apiKey}:${secretKey}`)}`);
442
+ return fetch(url, { ...init, headers });
443
+ }
444
+
445
+ // ../connectors/src/connectors/amplitude/setup-flow.ts
446
+ var AMPLITUDE_SETUP_MAX_ENTITIES = 10;
447
+ var AMPLITUDE_SETUP_MAX_EVENTS = 50;
448
+ var ENTITY_LABELS = {
449
+ events: { en: "Events", ja: "Events (\u30A4\u30D9\u30F3\u30C8)" },
450
+ userProperties: {
451
+ en: "User properties",
452
+ ja: "User properties (\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D1\u30C6\u30A3)"
453
+ },
454
+ cohorts: { en: "Cohorts", ja: "Cohorts (\u30B3\u30DB\u30FC\u30C8)" },
455
+ charts: { en: "Charts", ja: "Charts (\u30C1\u30E3\u30FC\u30C8)" },
456
+ dashboards: { en: "Dashboards", ja: "Dashboards (\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9)" }
457
+ };
458
+ var ENTITY_DESCRIPTIONS = {
459
+ events: {
460
+ en: "Tracked event types with metadata.",
461
+ ja: "\u30E1\u30BF\u30C7\u30FC\u30BF\u4ED8\u304D\u3067\u8FFD\u8DE1\u3055\u308C\u3066\u3044\u308B\u30A4\u30D9\u30F3\u30C8\u30BF\u30A4\u30D7\u3002"
462
+ },
463
+ userProperties: {
464
+ en: "User-level properties used for segmentation.",
465
+ 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"
466
+ },
467
+ cohorts: {
468
+ en: "Saved user cohorts.",
469
+ ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30E6\u30FC\u30B6\u30FC\u30B3\u30DB\u30FC\u30C8\u3002"
470
+ },
471
+ charts: {
472
+ en: "Saved analytics charts.",
473
+ ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30A2\u30CA\u30EA\u30C6\u30A3\u30AF\u30B9\u30C1\u30E3\u30FC\u30C8\u3002"
474
+ },
475
+ dashboards: {
476
+ en: "Saved dashboards.",
477
+ ja: "\u4FDD\u5B58\u6E08\u307F\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3002"
478
+ }
479
+ };
480
+ var ENTITY_VALUES = [
481
+ "events",
482
+ "userProperties",
483
+ "cohorts",
484
+ "charts",
485
+ "dashboards"
486
+ ];
487
+ async function fetchEventNames(params) {
488
+ try {
489
+ const res = await apiFetch(params, "/api/2/taxonomy/event");
490
+ if (!res.ok) return [];
491
+ const data = await res.json();
492
+ return (data.data ?? []).map((e) => e.event_type ?? "").filter((name) => name);
493
+ } catch {
494
+ return [];
495
+ }
496
+ }
497
+ var amplitudeSetupFlow = {
498
+ initialState: () => ({}),
499
+ steps: [
500
+ {
501
+ slug: "entities",
502
+ type: "multiSelect",
503
+ question: {
504
+ 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",
505
+ en: "Select target entities (multi-select allowed)"
506
+ },
507
+ async fetchOptions(_state, rt) {
508
+ return ENTITY_VALUES.map((value) => ({
509
+ value,
510
+ label: ENTITY_LABELS[value][rt.language]
511
+ }));
512
+ },
513
+ applyAnswer: (state, answer) => ({ ...state, entities: answer })
514
+ }
515
+ ],
516
+ async finalize(state, rt) {
517
+ if (!state.entities) {
518
+ throw new Error("Amplitude setup: incomplete state on finalize");
519
+ }
520
+ const selected = state.entities.filter(
521
+ (e) => ENTITY_VALUES.includes(e)
522
+ ).slice(0, AMPLITUDE_SETUP_MAX_ENTITIES);
523
+ const sections = ["## Amplitude", ""];
524
+ for (const entity of selected) {
525
+ sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
526
+ sections.push(ENTITY_DESCRIPTIONS[entity][rt.language], "");
527
+ if (entity === "events") {
528
+ const names = (await fetchEventNames(rt.params)).slice(
529
+ 0,
530
+ AMPLITUDE_SETUP_MAX_EVENTS
531
+ );
532
+ if (names.length > 0) {
533
+ sections.push("Event names:", "");
534
+ for (const name of names) {
535
+ sections.push(`- ${name}`);
536
+ }
537
+ sections.push("");
538
+ }
539
+ }
540
+ }
541
+ return sections.join("\n");
542
+ }
543
+ };
544
+
325
545
  // ../connectors/src/connectors/amplitude/tools/request.ts
326
546
  import { z } from "zod";
327
547
  var REQUEST_TIMEOUT_MS = 6e4;
@@ -550,7 +770,42 @@ export default async function handler(c: Context) {
550
770
  - \`i\` \u2014 \u30A4\u30F3\u30BF\u30FC\u30D0\u30EB\uFF081=\u65E5\u6B21\u30017=\u9031\u6B21\u300130=\u6708\u6B21\uFF09
551
771
  - \`g\` \u2014 \u30B0\u30EB\u30FC\u30D7\u5316\u30D7\u30ED\u30D1\u30C6\u30A3`
552
772
  },
553
- tools
773
+ tools,
774
+ setup: (params, ctx, config) => runSetupFlow(amplitudeSetupFlow, params, ctx, config),
775
+ async checkConnection(params, _config) {
776
+ const apiKey = params[parameters.apiKey.slug];
777
+ const secretKey = params[parameters.secretKey.slug];
778
+ if (!apiKey || !secretKey) {
779
+ return {
780
+ success: false,
781
+ error: "Missing required parameters: api-key and secret-key"
782
+ };
783
+ }
784
+ const region = params[parameters.region.slug];
785
+ const baseUrl = region === "eu" ? "https://analytics.eu.amplitude.com" : "https://amplitude.com";
786
+ try {
787
+ const res = await fetch(`${baseUrl}/api/2/events/list`, {
788
+ method: "GET",
789
+ headers: {
790
+ Authorization: `Basic ${btoa(`${apiKey}:${secretKey}`)}`,
791
+ Accept: "application/json"
792
+ }
793
+ });
794
+ if (!res.ok) {
795
+ const errorText = await res.text().catch(() => res.statusText);
796
+ return {
797
+ success: false,
798
+ error: `Amplitude API failed: HTTP ${res.status} ${errorText}`
799
+ };
800
+ }
801
+ return { success: true };
802
+ } catch (error) {
803
+ return {
804
+ success: false,
805
+ error: error instanceof Error ? error.message : String(error)
806
+ };
807
+ }
808
+ }
554
809
  });
555
810
 
556
811
  // src/connectors/create-connector-sdk.ts
@@ -579,6 +834,7 @@ function resolveEnvVarOptional(entry, key) {
579
834
  import { getContext } from "hono/context-storage";
580
835
  import { getCookie } from "hono/cookie";
581
836
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
837
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
582
838
  function normalizeHeaders(input) {
583
839
  const out = {};
584
840
  if (!input) return out;
@@ -587,6 +843,11 @@ function normalizeHeaders(input) {
587
843
  });
588
844
  return out;
589
845
  }
846
+ function extractInputUrl(input) {
847
+ if (typeof input === "string") return input;
848
+ if (input instanceof URL) return input.href;
849
+ return input.url;
850
+ }
590
851
  function createSandboxProxyFetch(connectionId) {
591
852
  return async (input, init) => {
592
853
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -596,10 +857,17 @@ function createSandboxProxyFetch(connectionId) {
596
857
  "Connection proxy is not configured. Please check your deployment settings."
597
858
  );
598
859
  }
599
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
860
+ const originalUrl = extractInputUrl(input);
861
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
862
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
863
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
864
+ return fetch(sessionUrl, {
865
+ method: "POST",
866
+ headers: { Authorization: `Bearer ${token}` }
867
+ });
868
+ }
600
869
  const originalMethod = init?.method ?? "GET";
601
870
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
602
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
603
871
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
604
872
  return fetch(proxyUrl, {
605
873
  method: "POST",
@@ -625,10 +893,9 @@ function createDeployedAppProxyFetch(connectionId) {
625
893
  }
626
894
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
627
895
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
896
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
628
897
  return async (input, init) => {
629
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
630
- const originalMethod = init?.method ?? "GET";
631
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
898
+ const originalUrl = extractInputUrl(input);
632
899
  const c = getContext();
633
900
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
634
901
  if (!appSession) {
@@ -636,6 +903,14 @@ function createDeployedAppProxyFetch(connectionId) {
636
903
  "No authentication method available for connection proxy."
637
904
  );
638
905
  }
906
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
907
+ return fetch(sessionUrl, {
908
+ method: "POST",
909
+ headers: { Authorization: `Bearer ${appSession}` }
910
+ });
911
+ }
912
+ const originalMethod = init?.method ?? "GET";
913
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
639
914
  return fetch(proxyUrl, {
640
915
  method: "POST",
641
916
  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",
@@ -83,6 +95,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
83
95
  tools;
84
96
  query;
85
97
  checkConnection;
98
+ /**
99
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
100
+ * implement this expose a step-by-step exploration flow (database/schema/
101
+ * table/etc. discovery) that the dashboard backend drives via the
102
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
103
+ * `runSetupFlow` from `setup-flow.ts`.
104
+ */
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;
86
120
  constructor(config) {
87
121
  this.slug = config.slug;
88
122
  this.authType = config.authType;
@@ -99,6 +133,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
99
133
  this.tools = config.tools;
100
134
  this.query = config.query;
101
135
  this.checkConnection = config.checkConnection;
136
+ this.setup = config.setup;
137
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
102
138
  }
103
139
  get connectorKey() {
104
140
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -234,7 +270,39 @@ export default async function handler(c: Context) {
234
270
  }
235
271
  \`\`\``
236
272
  },
237
- 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
+ }
238
306
  });
239
307
 
240
308
  // src/connectors/create-connector-sdk.ts
@@ -263,6 +331,7 @@ function resolveEnvVarOptional(entry, key) {
263
331
  import { getContext } from "hono/context-storage";
264
332
  import { getCookie } from "hono/cookie";
265
333
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
334
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
266
335
  function normalizeHeaders(input) {
267
336
  const out = {};
268
337
  if (!input) return out;
@@ -271,6 +340,11 @@ function normalizeHeaders(input) {
271
340
  });
272
341
  return out;
273
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
+ }
274
348
  function createSandboxProxyFetch(connectionId) {
275
349
  return async (input, init) => {
276
350
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -280,10 +354,17 @@ function createSandboxProxyFetch(connectionId) {
280
354
  "Connection proxy is not configured. Please check your deployment settings."
281
355
  );
282
356
  }
283
- 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
+ }
284
366
  const originalMethod = init?.method ?? "GET";
285
367
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
286
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
287
368
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
288
369
  return fetch(proxyUrl, {
289
370
  method: "POST",
@@ -309,10 +390,9 @@ function createDeployedAppProxyFetch(connectionId) {
309
390
  }
310
391
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
311
392
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
393
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
312
394
  return async (input, init) => {
313
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
314
- const originalMethod = init?.method ?? "GET";
315
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
395
+ const originalUrl = extractInputUrl(input);
316
396
  const c = getContext();
317
397
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
318
398
  if (!appSession) {
@@ -320,6 +400,14 @@ function createDeployedAppProxyFetch(connectionId) {
320
400
  "No authentication method available for connection proxy."
321
401
  );
322
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;
323
411
  return fetch(proxyUrl, {
324
412
  method: "POST",
325
413
  headers: {