@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/grafana/parameters.ts
57
+ init_parameter_definition();
46
58
  var parameters = {
47
59
  url: new ParameterDefinition({
48
60
  slug: "url",
@@ -83,7 +95,7 @@ function createClient(params) {
83
95
  headers.set("Accept", "application/json");
84
96
  return fetch(url, { ...init, headers });
85
97
  }
86
- async function listDatasources() {
98
+ async function listDatasources2() {
87
99
  const response = await request("/api/datasources");
88
100
  if (!response.ok) {
89
101
  const body = await response.text();
@@ -155,7 +167,7 @@ function createClient(params) {
155
167
  }
156
168
  return {
157
169
  request,
158
- listDatasources,
170
+ listDatasources: listDatasources2,
159
171
  getDatasource,
160
172
  queryDatasource,
161
173
  searchDashboards,
@@ -230,6 +242,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
230
242
  * `runSetupFlow` from `setup-flow.ts`.
231
243
  */
232
244
  setup;
245
+ /**
246
+ * Opt-out of the default "verify before save" behavior on connection
247
+ * creation. The backend invokes `checkConnection` synchronously while
248
+ * creating the connection and aborts (no row inserted) if it fails — this
249
+ * flag disables that for connectors where the check cannot succeed pre-save:
250
+ *
251
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
252
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
253
+ * connectionId, which doesn't exist until the row is saved
254
+ *
255
+ * Exceptions are the explicit position; new credential-input connectors get
256
+ * the default verify-on-create behavior without opt-in.
257
+ */
258
+ skipConnectionCheckOnCreate;
233
259
  constructor(config) {
234
260
  this.slug = config.slug;
235
261
  this.authType = config.authType;
@@ -247,6 +273,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
247
273
  this.query = config.query;
248
274
  this.checkConnection = config.checkConnection;
249
275
  this.setup = config.setup;
276
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
250
277
  }
251
278
  get connectorKey() {
252
279
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -311,6 +338,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
311
338
  }
312
339
  };
313
340
 
341
+ // ../connectors/src/setup-flow.ts
342
+ async function runSetupFlow(flow, params, ctx, config) {
343
+ const runtime = {
344
+ params,
345
+ language: ctx.language,
346
+ config
347
+ };
348
+ let state = flow.initialState();
349
+ let answerIdx = 0;
350
+ for (const step of flow.steps) {
351
+ const ans = ctx.answers[answerIdx];
352
+ if (ans && ans.questionSlug === step.slug) {
353
+ state = step.applyAnswer(state, ans.answer);
354
+ answerIdx += 1;
355
+ continue;
356
+ }
357
+ if (step.type === "text") {
358
+ return {
359
+ type: "nextQuestion",
360
+ questionSlug: step.slug,
361
+ question: step.question[ctx.language],
362
+ questionType: "text"
363
+ };
364
+ }
365
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
366
+ if (options.length === 0) {
367
+ continue;
368
+ }
369
+ return {
370
+ type: "nextQuestion",
371
+ questionSlug: step.slug,
372
+ question: step.question[ctx.language],
373
+ questionType: step.type,
374
+ options
375
+ };
376
+ }
377
+ const dataInvestigationResult = await flow.finalize(state, runtime);
378
+ return { type: "fulfilled", dataInvestigationResult };
379
+ }
380
+ async function resolveSetupSelection(params) {
381
+ const { selected, allSentinel, fetchAll, limit } = params;
382
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
383
+ return resolved.slice(0, limit);
384
+ }
385
+
314
386
  // ../connectors/src/auth-types.ts
315
387
  var AUTH_TYPES = {
316
388
  OAUTH: "oauth",
@@ -333,6 +405,129 @@ var grafanaOnboarding = new ConnectorOnboarding({
333
405
  }
334
406
  });
335
407
 
408
+ // ../connectors/src/connectors/grafana/utils.ts
409
+ async function apiFetch(params, path2, init) {
410
+ const apiKey = params[parameters.apiKey.slug];
411
+ const rawUrl = params[parameters.url.slug];
412
+ if (!apiKey || !rawUrl) {
413
+ throw new Error("grafana: missing required parameters: url and api-key");
414
+ }
415
+ const baseUrl = rawUrl.replace(/\/+$/, "");
416
+ const url = `${baseUrl}${path2.startsWith("/") ? path2 : `/${path2}`}`;
417
+ const headers = new Headers(init?.headers);
418
+ headers.set("Authorization", `Bearer ${apiKey}`);
419
+ if (!headers.has("Accept")) headers.set("Accept", "application/json");
420
+ return fetch(url, { ...init, headers });
421
+ }
422
+
423
+ // ../connectors/src/connectors/grafana/setup-flow.ts
424
+ var ALL_DATASOURCES = "__ALL_DATASOURCES__";
425
+ var GRAFANA_SETUP_MAX_DATASOURCES = 10;
426
+ async function listOrgs(params) {
427
+ try {
428
+ const res = await apiFetch(params, "/api/orgs");
429
+ if (res.ok) {
430
+ const data = await res.json();
431
+ if (Array.isArray(data)) return data;
432
+ }
433
+ } catch {
434
+ }
435
+ try {
436
+ const res = await apiFetch(params, "/api/org");
437
+ if (!res.ok) return [];
438
+ const data = await res.json();
439
+ if (data && typeof data.id === "number" && typeof data.name === "string") {
440
+ return [data];
441
+ }
442
+ } catch {
443
+ }
444
+ return [];
445
+ }
446
+ async function listDatasources(params) {
447
+ const res = await apiFetch(params, "/api/datasources");
448
+ if (!res.ok) {
449
+ const body = await res.text().catch(() => res.statusText);
450
+ throw new Error(`grafana: listDatasources failed (${res.status}): ${body}`);
451
+ }
452
+ const data = await res.json();
453
+ return data ?? [];
454
+ }
455
+ var grafanaSetupFlow = {
456
+ initialState: () => ({}),
457
+ steps: [
458
+ {
459
+ slug: "organization",
460
+ type: "select",
461
+ question: {
462
+ ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u4F7F\u3046\u7D44\u7E54\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
463
+ en: "Select the organization to use for setup"
464
+ },
465
+ async fetchOptions(_state, rt) {
466
+ const orgs = await listOrgs(rt.params);
467
+ return orgs.map((o) => ({ value: String(o.id), label: o.name }));
468
+ },
469
+ applyAnswer: (state, answer) => ({ ...state, organization: answer[0] })
470
+ },
471
+ {
472
+ slug: "datasources",
473
+ type: "multiSelect",
474
+ question: {
475
+ ja: "\u5BFE\u8C61\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
476
+ en: "Select target datasources (multi-select allowed)"
477
+ },
478
+ async fetchOptions(_state, rt) {
479
+ const datasources = await listDatasources(rt.params);
480
+ const opts = datasources.filter((d) => d.uid && d.name).map((d) => ({
481
+ value: d.uid,
482
+ label: `${d.name} (${d.type})`
483
+ }));
484
+ if (opts.length === 0) return [];
485
+ return [
486
+ {
487
+ value: ALL_DATASOURCES,
488
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9" : "All datasources"
489
+ },
490
+ ...opts
491
+ ];
492
+ },
493
+ applyAnswer: (state, answer) => ({ ...state, datasources: answer })
494
+ }
495
+ ],
496
+ async finalize(state, rt) {
497
+ if (!state.datasources) {
498
+ throw new Error("Grafana setup: incomplete state on finalize");
499
+ }
500
+ const datasources = await listDatasources(rt.params);
501
+ const byUid = new Map(datasources.map((d) => [d.uid, d]));
502
+ const targetUids = await resolveSetupSelection({
503
+ selected: state.datasources,
504
+ allSentinel: ALL_DATASOURCES,
505
+ fetchAll: async () => datasources.map((d) => d.uid).filter((u) => u),
506
+ limit: GRAFANA_SETUP_MAX_DATASOURCES
507
+ });
508
+ const sections = ["## Grafana", ""];
509
+ if (state.organization) {
510
+ sections.push(`### Organization: ${state.organization}`, "");
511
+ }
512
+ for (const uid of targetUids) {
513
+ const ds = byUid.get(uid);
514
+ if (!ds) {
515
+ sections.push(`#### Datasource: ${uid}`, "", "_Not found._", "");
516
+ continue;
517
+ }
518
+ sections.push(`#### Datasource: ${ds.name}`, "");
519
+ sections.push("| Field | Value |");
520
+ sections.push("|-------|-------|");
521
+ sections.push(`| UID | ${ds.uid} |`);
522
+ sections.push(`| Type | ${ds.type} |`);
523
+ sections.push(`| URL | ${ds.url ?? "-"} |`);
524
+ sections.push(`| Default | ${ds.isDefault ? "yes" : "no"} |`);
525
+ sections.push("");
526
+ }
527
+ return sections.join("\n");
528
+ }
529
+ };
530
+
336
531
  // ../connectors/src/connectors/grafana/tools/request.ts
337
532
  import { z } from "zod";
338
533
  var REQUEST_TIMEOUT_MS = 6e4;
@@ -545,7 +740,41 @@ export default async function handler(c: Context) {
545
740
  - \`GET /api/org\` \u2014 \u73FE\u5728\u306E\u7D44\u7E54\u3092\u53D6\u5F97
546
741
  - \`GET /api/health\` \u2014 \u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF`
547
742
  },
548
- tools
743
+ tools,
744
+ setup: (params, ctx, config) => runSetupFlow(grafanaSetupFlow, params, ctx, config),
745
+ async checkConnection(params, _config) {
746
+ const apiKey = params[parameters.apiKey.slug];
747
+ const rawUrl = params[parameters.url.slug];
748
+ if (!apiKey || !rawUrl) {
749
+ return {
750
+ success: false,
751
+ error: "Missing required parameters: url and api-key"
752
+ };
753
+ }
754
+ const baseUrl = rawUrl.replace(/\/+$/, "");
755
+ try {
756
+ const res = await fetch(`${baseUrl}/api/org`, {
757
+ method: "GET",
758
+ headers: {
759
+ Authorization: `Bearer ${apiKey}`,
760
+ Accept: "application/json"
761
+ }
762
+ });
763
+ if (!res.ok) {
764
+ const errorText = await res.text().catch(() => res.statusText);
765
+ return {
766
+ success: false,
767
+ error: `Grafana API failed: HTTP ${res.status} ${errorText}`
768
+ };
769
+ }
770
+ return { success: true };
771
+ } catch (error) {
772
+ return {
773
+ success: false,
774
+ error: error instanceof Error ? error.message : String(error)
775
+ };
776
+ }
777
+ }
549
778
  });
550
779
 
551
780
  // src/connectors/create-connector-sdk.ts
@@ -574,6 +803,7 @@ function resolveEnvVarOptional(entry, key) {
574
803
  import { getContext } from "hono/context-storage";
575
804
  import { getCookie } from "hono/cookie";
576
805
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
806
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
577
807
  function normalizeHeaders(input) {
578
808
  const out = {};
579
809
  if (!input) return out;
@@ -582,6 +812,11 @@ function normalizeHeaders(input) {
582
812
  });
583
813
  return out;
584
814
  }
815
+ function extractInputUrl(input) {
816
+ if (typeof input === "string") return input;
817
+ if (input instanceof URL) return input.href;
818
+ return input.url;
819
+ }
585
820
  function createSandboxProxyFetch(connectionId) {
586
821
  return async (input, init) => {
587
822
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -591,10 +826,17 @@ function createSandboxProxyFetch(connectionId) {
591
826
  "Connection proxy is not configured. Please check your deployment settings."
592
827
  );
593
828
  }
594
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
829
+ const originalUrl = extractInputUrl(input);
830
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
831
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
832
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
833
+ return fetch(sessionUrl, {
834
+ method: "POST",
835
+ headers: { Authorization: `Bearer ${token}` }
836
+ });
837
+ }
595
838
  const originalMethod = init?.method ?? "GET";
596
839
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
597
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
598
840
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
599
841
  return fetch(proxyUrl, {
600
842
  method: "POST",
@@ -620,10 +862,9 @@ function createDeployedAppProxyFetch(connectionId) {
620
862
  }
621
863
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
622
864
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
865
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
623
866
  return async (input, init) => {
624
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
625
- const originalMethod = init?.method ?? "GET";
626
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
867
+ const originalUrl = extractInputUrl(input);
627
868
  const c = getContext();
628
869
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
629
870
  if (!appSession) {
@@ -631,6 +872,14 @@ function createDeployedAppProxyFetch(connectionId) {
631
872
  "No authentication method available for connection proxy."
632
873
  );
633
874
  }
875
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
876
+ return fetch(sessionUrl, {
877
+ method: "POST",
878
+ headers: { Authorization: `Bearer ${appSession}` }
879
+ });
880
+ }
881
+ const originalMethod = init?.method ?? "GET";
882
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
634
883
  return fetch(proxyUrl, {
635
884
  method: "POST",
636
885
  headers: {
@@ -75,6 +75,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
75
75
  * `runSetupFlow` from `setup-flow.ts`.
76
76
  */
77
77
  setup;
78
+ /**
79
+ * Opt-out of the default "verify before save" behavior on connection
80
+ * creation. The backend invokes `checkConnection` synchronously while
81
+ * creating the connection and aborts (no row inserted) if it fails — this
82
+ * flag disables that for connectors where the check cannot succeed pre-save:
83
+ *
84
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
85
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
86
+ * connectionId, which doesn't exist until the row is saved
87
+ *
88
+ * Exceptions are the explicit position; new credential-input connectors get
89
+ * the default verify-on-create behavior without opt-in.
90
+ */
91
+ skipConnectionCheckOnCreate;
78
92
  constructor(config) {
79
93
  this.slug = config.slug;
80
94
  this.authType = config.authType;
@@ -92,6 +106,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
92
106
  this.query = config.query;
93
107
  this.checkConnection = config.checkConnection;
94
108
  this.setup = config.setup;
109
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
95
110
  }
96
111
  get connectorKey() {
97
112
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -156,6 +171,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
156
171
  }
157
172
  };
158
173
 
174
+ // ../connectors/src/setup-flow.ts
175
+ async function runSetupFlow(flow, params, ctx, config) {
176
+ const runtime = {
177
+ params,
178
+ language: ctx.language,
179
+ config
180
+ };
181
+ let state = flow.initialState();
182
+ let answerIdx = 0;
183
+ for (const step of flow.steps) {
184
+ const ans = ctx.answers[answerIdx];
185
+ if (ans && ans.questionSlug === step.slug) {
186
+ state = step.applyAnswer(state, ans.answer);
187
+ answerIdx += 1;
188
+ continue;
189
+ }
190
+ if (step.type === "text") {
191
+ return {
192
+ type: "nextQuestion",
193
+ questionSlug: step.slug,
194
+ question: step.question[ctx.language],
195
+ questionType: "text"
196
+ };
197
+ }
198
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
199
+ if (options.length === 0) {
200
+ continue;
201
+ }
202
+ return {
203
+ type: "nextQuestion",
204
+ questionSlug: step.slug,
205
+ question: step.question[ctx.language],
206
+ questionType: step.type,
207
+ options
208
+ };
209
+ }
210
+ const dataInvestigationResult = await flow.finalize(state, runtime);
211
+ return { type: "fulfilled", dataInvestigationResult };
212
+ }
213
+ async function resolveSetupSelection(params) {
214
+ const { selected, allSentinel, fetchAll, limit } = params;
215
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
216
+ return resolved.slice(0, limit);
217
+ }
218
+
159
219
  // ../connectors/src/auth-types.ts
160
220
  var AUTH_TYPES = {
161
221
  OAUTH: "oauth",
@@ -316,6 +376,93 @@ var hubspotOnboarding = new ConnectorOnboarding({
316
376
  }
317
377
  });
318
378
 
379
+ // ../connectors/src/connectors/hubspot-oauth/utils.ts
380
+ var BASE_URL3 = "https://api.hubapi.com";
381
+ function apiFetch(proxyFetch, path2, init) {
382
+ const url = `${BASE_URL3}${path2.startsWith("/") ? "" : "/"}${path2}`;
383
+ return proxyFetch(url, init);
384
+ }
385
+
386
+ // ../connectors/src/connectors/hubspot-oauth/setup-flow.ts
387
+ var HUBSPOT_SETUP_MAX_OBJECT_TYPES = 10;
388
+ var HUBSPOT_SETUP_MAX_PROPERTIES = 50;
389
+ var HUBSPOT_OBJECT_TYPES = [
390
+ { value: "contacts", label: "Contacts" },
391
+ { value: "companies", label: "Companies" },
392
+ { value: "deals", label: "Deals" },
393
+ { value: "tickets", label: "Tickets" },
394
+ { value: "products", label: "Products" },
395
+ { value: "notes", label: "Notes" },
396
+ { value: "calls", label: "Calls" },
397
+ { value: "emails", label: "Emails" },
398
+ { value: "meetings", label: "Meetings" },
399
+ { value: "tasks", label: "Tasks" }
400
+ ];
401
+ async function listProperties(proxyFetch, objectType) {
402
+ const res = await apiFetch(proxyFetch, `/crm/v3/properties/${objectType}`);
403
+ if (!res.ok) {
404
+ const body = await res.text().catch(() => res.statusText);
405
+ throw new Error(
406
+ `hubspot-oauth: listProperties(${objectType}) failed (${res.status}): ${body}`
407
+ );
408
+ }
409
+ const data = await res.json();
410
+ return data.results ?? [];
411
+ }
412
+ var hubspotOauthSetupFlow = {
413
+ initialState: () => ({}),
414
+ steps: [
415
+ {
416
+ slug: "objectTypes",
417
+ type: "multiSelect",
418
+ question: {
419
+ ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3067\u6982\u89B3\u3057\u305F\u3044CRM\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
420
+ en: "Select the CRM object types to include in setup (multi-select allowed)"
421
+ },
422
+ async fetchOptions(_state, _rt) {
423
+ return HUBSPOT_OBJECT_TYPES.map((o) => ({
424
+ value: o.value,
425
+ label: o.label
426
+ }));
427
+ },
428
+ applyAnswer: (state, answer) => ({ ...state, objectTypes: answer })
429
+ }
430
+ ],
431
+ async finalize(state, rt) {
432
+ if (!state.objectTypes) {
433
+ throw new Error("HubSpot setup: incomplete state on finalize");
434
+ }
435
+ const targetObjectTypes = await resolveSetupSelection({
436
+ selected: state.objectTypes,
437
+ allSentinel: "__ALL__",
438
+ fetchAll: async () => HUBSPOT_OBJECT_TYPES.map((o) => o.value),
439
+ limit: HUBSPOT_SETUP_MAX_OBJECT_TYPES
440
+ });
441
+ const sections = ["## HubSpot", ""];
442
+ for (const objectType of targetObjectTypes) {
443
+ sections.push(`### Object: ${objectType}`, "");
444
+ const props = await listProperties(rt.config.proxyFetch, objectType);
445
+ const limited = props.slice(0, HUBSPOT_SETUP_MAX_PROPERTIES);
446
+ sections.push("| Property | Type | Label |");
447
+ sections.push("|----------|------|-------|");
448
+ for (const p of limited) {
449
+ const name = (p.name ?? "").replace(/\|/g, "\\|");
450
+ const type = (p.type ?? "").replace(/\|/g, "\\|");
451
+ const label = (p.label ?? "").replace(/\|/g, "\\|");
452
+ sections.push(`| ${name} | ${type} | ${label || "-"} |`);
453
+ }
454
+ if (props.length > HUBSPOT_SETUP_MAX_PROPERTIES) {
455
+ sections.push(
456
+ "",
457
+ `_Showing first ${HUBSPOT_SETUP_MAX_PROPERTIES} of ${props.length} properties._`
458
+ );
459
+ }
460
+ sections.push("");
461
+ }
462
+ return sections.join("\n");
463
+ }
464
+ };
465
+
319
466
  // ../connectors/src/connectors/hubspot-oauth/parameters.ts
320
467
  var parameters = {};
321
468
 
@@ -324,6 +471,7 @@ var tools = { request: requestTool };
324
471
  var hubspotOauthConnector = new ConnectorPlugin({
325
472
  slug: "hubspot",
326
473
  authType: AUTH_TYPES.OAUTH,
474
+ skipConnectionCheckOnCreate: true,
327
475
  name: "HubSpot",
328
476
  description: "Connect to HubSpot CRM for contacts, deals, companies, and marketing data using OAuth.",
329
477
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5UcSkKkzhUMA4RsM45ynuo/43b967e36915ca0fc5d277684b204320/hubspot.svg",
@@ -432,6 +580,7 @@ const data = await res.json();
432
580
  \`\`\``
433
581
  },
434
582
  tools,
583
+ setup: (params, ctx, config) => runSetupFlow(hubspotOauthSetupFlow, params, ctx, config),
435
584
  async checkConnection(_params, config) {
436
585
  const { proxyFetch } = config;
437
586
  try {
@@ -482,6 +631,7 @@ function resolveEnvVarOptional(entry, key) {
482
631
  import { getContext } from "hono/context-storage";
483
632
  import { getCookie } from "hono/cookie";
484
633
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
634
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
485
635
  function normalizeHeaders(input) {
486
636
  const out = {};
487
637
  if (!input) return out;
@@ -490,6 +640,11 @@ function normalizeHeaders(input) {
490
640
  });
491
641
  return out;
492
642
  }
643
+ function extractInputUrl(input) {
644
+ if (typeof input === "string") return input;
645
+ if (input instanceof URL) return input.href;
646
+ return input.url;
647
+ }
493
648
  function createSandboxProxyFetch(connectionId) {
494
649
  return async (input, init) => {
495
650
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -499,10 +654,17 @@ function createSandboxProxyFetch(connectionId) {
499
654
  "Connection proxy is not configured. Please check your deployment settings."
500
655
  );
501
656
  }
502
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
657
+ const originalUrl = extractInputUrl(input);
658
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
659
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
660
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
661
+ return fetch(sessionUrl, {
662
+ method: "POST",
663
+ headers: { Authorization: `Bearer ${token}` }
664
+ });
665
+ }
503
666
  const originalMethod = init?.method ?? "GET";
504
667
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
505
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
506
668
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
507
669
  return fetch(proxyUrl, {
508
670
  method: "POST",
@@ -528,10 +690,9 @@ function createDeployedAppProxyFetch(connectionId) {
528
690
  }
529
691
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
530
692
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
693
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
531
694
  return async (input, init) => {
532
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
533
- const originalMethod = init?.method ?? "GET";
534
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
695
+ const originalUrl = extractInputUrl(input);
535
696
  const c = getContext();
536
697
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
537
698
  if (!appSession) {
@@ -539,6 +700,14 @@ function createDeployedAppProxyFetch(connectionId) {
539
700
  "No authentication method available for connection proxy."
540
701
  );
541
702
  }
703
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
704
+ return fetch(sessionUrl, {
705
+ method: "POST",
706
+ headers: { Authorization: `Bearer ${appSession}` }
707
+ });
708
+ }
709
+ const originalMethod = init?.method ?? "GET";
710
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
542
711
  return fetch(proxyUrl, {
543
712
  method: "POST",
544
713
  headers: {