@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,46 +1,57 @@
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/google-sheets/sdk/index.ts
46
57
  var SHEETS_BASE_URL = "https://sheets.googleapis.com/v4/spreadsheets";
@@ -183,6 +194,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
183
194
  tools;
184
195
  query;
185
196
  checkConnection;
197
+ /**
198
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
199
+ * implement this expose a step-by-step exploration flow (database/schema/
200
+ * table/etc. discovery) that the dashboard backend drives via the
201
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
202
+ * `runSetupFlow` from `setup-flow.ts`.
203
+ */
204
+ setup;
205
+ /**
206
+ * Opt-out of the default "verify before save" behavior on connection
207
+ * creation. The backend invokes `checkConnection` synchronously while
208
+ * creating the connection and aborts (no row inserted) if it fails — this
209
+ * flag disables that for connectors where the check cannot succeed pre-save:
210
+ *
211
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
212
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
213
+ * connectionId, which doesn't exist until the row is saved
214
+ *
215
+ * Exceptions are the explicit position; new credential-input connectors get
216
+ * the default verify-on-create behavior without opt-in.
217
+ */
218
+ skipConnectionCheckOnCreate;
186
219
  constructor(config) {
187
220
  this.slug = config.slug;
188
221
  this.authType = config.authType;
@@ -199,6 +232,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
199
232
  this.tools = config.tools;
200
233
  this.query = config.query;
201
234
  this.checkConnection = config.checkConnection;
235
+ this.setup = config.setup;
236
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
202
237
  }
203
238
  get connectorKey() {
204
239
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -263,6 +298,76 @@ var ConnectorPlugin = class _ConnectorPlugin {
263
298
  }
264
299
  };
265
300
 
301
+ // ../connectors/src/setup-flow.ts
302
+ async function runSetupFlow(flow, params, ctx, config) {
303
+ const runtime = {
304
+ params,
305
+ language: ctx.language,
306
+ config
307
+ };
308
+ let state = flow.initialState();
309
+ let answerIdx = 0;
310
+ const pendingParameterUpdates = [];
311
+ for (const step of flow.steps) {
312
+ const ans = ctx.answers[answerIdx];
313
+ if (ans && ans.questionSlug === step.slug) {
314
+ state = step.applyAnswer(state, ans.answer);
315
+ if (step.toParameterUpdates) {
316
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
317
+ }
318
+ answerIdx += 1;
319
+ continue;
320
+ }
321
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
322
+ if (step.type === "text") {
323
+ if (step.fetchOptions) {
324
+ const options2 = await step.fetchOptions(state, runtime);
325
+ if (options2.length === 0) {
326
+ continue;
327
+ }
328
+ }
329
+ return {
330
+ type: "nextQuestion",
331
+ questionSlug: step.slug,
332
+ question: step.question[ctx.language],
333
+ questionType: "text",
334
+ allowFreeText: resolvedAllowFreeText,
335
+ ...pendingParameterUpdates.length > 0 && {
336
+ parameterUpdates: pendingParameterUpdates
337
+ }
338
+ };
339
+ }
340
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
341
+ if (options.length === 0) {
342
+ continue;
343
+ }
344
+ return {
345
+ type: "nextQuestion",
346
+ questionSlug: step.slug,
347
+ question: step.question[ctx.language],
348
+ questionType: step.type,
349
+ options,
350
+ allowFreeText: resolvedAllowFreeText,
351
+ ...pendingParameterUpdates.length > 0 && {
352
+ parameterUpdates: pendingParameterUpdates
353
+ }
354
+ };
355
+ }
356
+ const dataInvestigationResult = await flow.finalize(state, runtime);
357
+ return {
358
+ type: "fulfilled",
359
+ dataInvestigationResult,
360
+ ...pendingParameterUpdates.length > 0 && {
361
+ parameterUpdates: pendingParameterUpdates
362
+ }
363
+ };
364
+ }
365
+ async function resolveSetupSelection(params) {
366
+ const { selected, allSentinel, fetchAll, limit } = params;
367
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
368
+ return resolved.slice(0, limit);
369
+ }
370
+
266
371
  // ../connectors/src/auth-types.ts
267
372
  var AUTH_TYPES = {
268
373
  OAUTH: "oauth",
@@ -461,7 +566,105 @@ var googleSheetsOnboarding = new ConnectorOnboarding({
461
566
  }
462
567
  });
463
568
 
569
+ // ../connectors/src/connectors/google-sheets/utils.ts
570
+ async function googleApiFetch(config, url) {
571
+ const res = await config.proxyFetch(url, { method: "GET" });
572
+ if (!res.ok) {
573
+ const text = await res.text().catch(() => res.statusText);
574
+ throw new Error(`Google API ${url} failed: HTTP ${res.status} ${text}`);
575
+ }
576
+ return await res.json();
577
+ }
578
+
579
+ // ../connectors/src/connectors/google-sheets/setup-flow.ts
580
+ var ALL_SPREADSHEETS = "__ALL_SPREADSHEETS__";
581
+ var GOOGLE_SHEETS_SETUP_MAX_SPREADSHEETS = 10;
582
+ var DRIVE_LIST_PAGE_SIZE = 50;
583
+ async function listSpreadsheets(config) {
584
+ const q = encodeURIComponent(
585
+ "mimeType='application/vnd.google-apps.spreadsheet' and trashed=false"
586
+ );
587
+ const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
588
+ const data = await googleApiFetch(config, url);
589
+ return data.files ?? [];
590
+ }
591
+ var googleSheetsSetupFlow = {
592
+ initialState: () => ({}),
593
+ steps: [
594
+ {
595
+ slug: "spreadsheets",
596
+ type: "multiSelect",
597
+ question: {
598
+ ja: "\u5BFE\u8C61\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
599
+ en: "Select target spreadsheets (multi-select allowed)"
600
+ },
601
+ async fetchOptions(_state, rt) {
602
+ const files = await listSpreadsheets(rt.config);
603
+ const fileOptions = files.map((f) => ({
604
+ value: f.id,
605
+ label: f.name
606
+ }));
607
+ return [
608
+ {
609
+ value: ALL_SPREADSHEETS,
610
+ label: rt.language === "ja" ? "\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u3059\u3079\u3066\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8" : "All accessible spreadsheets"
611
+ },
612
+ ...fileOptions
613
+ ];
614
+ },
615
+ applyAnswer: (state, answer) => ({ ...state, spreadsheets: answer })
616
+ }
617
+ ],
618
+ async finalize(state, rt) {
619
+ if (!state.spreadsheets) {
620
+ throw new Error("Google Sheets setup: incomplete state on finalize");
621
+ }
622
+ const targetIds = await resolveSetupSelection({
623
+ selected: state.spreadsheets,
624
+ allSentinel: ALL_SPREADSHEETS,
625
+ fetchAll: async () => {
626
+ const files = await listSpreadsheets(rt.config);
627
+ return files.map((f) => f.id);
628
+ },
629
+ limit: GOOGLE_SHEETS_SETUP_MAX_SPREADSHEETS
630
+ });
631
+ const sections = ["## Google Sheets", ""];
632
+ if (targetIds.length === 0) {
633
+ sections.push(
634
+ rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No spreadsheets selected."
635
+ );
636
+ return sections.join("\n");
637
+ }
638
+ for (const id of targetIds) {
639
+ const url = `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(id)}?fields=spreadsheetId,properties(title),sheets(properties(title,sheetId,gridProperties))`;
640
+ const meta = await googleApiFetch(
641
+ rt.config,
642
+ url
643
+ );
644
+ const title = meta.properties?.title ?? id;
645
+ sections.push(`### Spreadsheet: ${title}`, "", `- ID: ${id}`, "");
646
+ const sheets = meta.sheets ?? [];
647
+ if (sheets.length === 0) {
648
+ sections.push("- (no sheet tabs)", "");
649
+ continue;
650
+ }
651
+ sections.push("| Sheet | Rows | Columns |");
652
+ sections.push("|-------|------|---------|");
653
+ for (const s of sheets) {
654
+ const p = s.properties ?? {};
655
+ const sheetTitle = p.title ?? "(untitled)";
656
+ const rows = p.gridProperties?.rowCount ?? "-";
657
+ const cols = p.gridProperties?.columnCount ?? "-";
658
+ sections.push(`| ${sheetTitle} | ${rows} | ${cols} |`);
659
+ }
660
+ sections.push("");
661
+ }
662
+ return sections.join("\n");
663
+ }
664
+ };
665
+
464
666
  // ../connectors/src/connectors/google-sheets/parameters.ts
667
+ init_parameter_definition();
465
668
  var parameters = {
466
669
  spreadsheetId: new ParameterDefinition({
467
670
  slug: "spreadsheet-id",
@@ -479,6 +682,7 @@ var tools = { request: requestTool };
479
682
  var googleSheetsConnector = new ConnectorPlugin({
480
683
  slug: "google-sheets",
481
684
  authType: AUTH_TYPES.OAUTH,
685
+ skipConnectionCheckOnCreate: true,
482
686
  name: "Google Sheets",
483
687
  description: "Connect to Google Sheets for read/write access via OAuth. Any spreadsheet the authenticated Google account can access is supported \u2014 the target spreadsheetId is passed per call.",
484
688
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
@@ -644,7 +848,8 @@ await sheets.batchUpdate(spreadsheetId, [
644
848
  ]);
645
849
  \`\`\``
646
850
  },
647
- tools
851
+ tools,
852
+ setup: (params, ctx, config) => runSetupFlow(googleSheetsSetupFlow, params, ctx, config)
648
853
  });
649
854
 
650
855
  // src/connectors/create-connector-sdk.ts
@@ -673,6 +878,7 @@ function resolveEnvVarOptional(entry, key) {
673
878
  import { getContext } from "hono/context-storage";
674
879
  import { getCookie } from "hono/cookie";
675
880
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
881
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
676
882
  function normalizeHeaders(input) {
677
883
  const out = {};
678
884
  if (!input) return out;
@@ -681,6 +887,11 @@ function normalizeHeaders(input) {
681
887
  });
682
888
  return out;
683
889
  }
890
+ function extractInputUrl(input) {
891
+ if (typeof input === "string") return input;
892
+ if (input instanceof URL) return input.href;
893
+ return input.url;
894
+ }
684
895
  function createSandboxProxyFetch(connectionId) {
685
896
  return async (input, init) => {
686
897
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -690,10 +901,17 @@ function createSandboxProxyFetch(connectionId) {
690
901
  "Connection proxy is not configured. Please check your deployment settings."
691
902
  );
692
903
  }
693
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
904
+ const originalUrl = extractInputUrl(input);
905
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
906
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
907
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
908
+ return fetch(sessionUrl, {
909
+ method: "POST",
910
+ headers: { Authorization: `Bearer ${token}` }
911
+ });
912
+ }
694
913
  const originalMethod = init?.method ?? "GET";
695
914
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
696
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
697
915
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
698
916
  return fetch(proxyUrl, {
699
917
  method: "POST",
@@ -719,10 +937,9 @@ function createDeployedAppProxyFetch(connectionId) {
719
937
  }
720
938
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
721
939
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
940
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
722
941
  return async (input, init) => {
723
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
724
- const originalMethod = init?.method ?? "GET";
725
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
942
+ const originalUrl = extractInputUrl(input);
726
943
  const c = getContext();
727
944
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
728
945
  if (!appSession) {
@@ -730,6 +947,14 @@ function createDeployedAppProxyFetch(connectionId) {
730
947
  "No authentication method available for connection proxy."
731
948
  );
732
949
  }
950
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
951
+ return fetch(sessionUrl, {
952
+ method: "POST",
953
+ headers: { Authorization: `Bearer ${appSession}` }
954
+ });
955
+ }
956
+ const originalMethod = init?.method ?? "GET";
957
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
733
958
  return fetch(proxyUrl, {
734
959
  method: "POST",
735
960
  headers: {
@@ -125,6 +125,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
125
125
  tools;
126
126
  query;
127
127
  checkConnection;
128
+ /**
129
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
130
+ * implement this expose a step-by-step exploration flow (database/schema/
131
+ * table/etc. discovery) that the dashboard backend drives via the
132
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
133
+ * `runSetupFlow` from `setup-flow.ts`.
134
+ */
135
+ setup;
136
+ /**
137
+ * Opt-out of the default "verify before save" behavior on connection
138
+ * creation. The backend invokes `checkConnection` synchronously while
139
+ * creating the connection and aborts (no row inserted) if it fails — this
140
+ * flag disables that for connectors where the check cannot succeed pre-save:
141
+ *
142
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
143
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
144
+ * connectionId, which doesn't exist until the row is saved
145
+ *
146
+ * Exceptions are the explicit position; new credential-input connectors get
147
+ * the default verify-on-create behavior without opt-in.
148
+ */
149
+ skipConnectionCheckOnCreate;
128
150
  constructor(config) {
129
151
  this.slug = config.slug;
130
152
  this.authType = config.authType;
@@ -141,6 +163,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
141
163
  this.tools = config.tools;
142
164
  this.query = config.query;
143
165
  this.checkConnection = config.checkConnection;
166
+ this.setup = config.setup;
167
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
144
168
  }
145
169
  get connectorKey() {
146
170
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -205,6 +229,76 @@ var ConnectorPlugin = class _ConnectorPlugin {
205
229
  }
206
230
  };
207
231
 
232
+ // ../connectors/src/setup-flow.ts
233
+ async function runSetupFlow(flow, params, ctx, config) {
234
+ const runtime = {
235
+ params,
236
+ language: ctx.language,
237
+ config
238
+ };
239
+ let state = flow.initialState();
240
+ let answerIdx = 0;
241
+ const pendingParameterUpdates = [];
242
+ for (const step of flow.steps) {
243
+ const ans = ctx.answers[answerIdx];
244
+ if (ans && ans.questionSlug === step.slug) {
245
+ state = step.applyAnswer(state, ans.answer);
246
+ if (step.toParameterUpdates) {
247
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
248
+ }
249
+ answerIdx += 1;
250
+ continue;
251
+ }
252
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
253
+ if (step.type === "text") {
254
+ if (step.fetchOptions) {
255
+ const options2 = await step.fetchOptions(state, runtime);
256
+ if (options2.length === 0) {
257
+ continue;
258
+ }
259
+ }
260
+ return {
261
+ type: "nextQuestion",
262
+ questionSlug: step.slug,
263
+ question: step.question[ctx.language],
264
+ questionType: "text",
265
+ allowFreeText: resolvedAllowFreeText,
266
+ ...pendingParameterUpdates.length > 0 && {
267
+ parameterUpdates: pendingParameterUpdates
268
+ }
269
+ };
270
+ }
271
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
272
+ if (options.length === 0) {
273
+ continue;
274
+ }
275
+ return {
276
+ type: "nextQuestion",
277
+ questionSlug: step.slug,
278
+ question: step.question[ctx.language],
279
+ questionType: step.type,
280
+ options,
281
+ allowFreeText: resolvedAllowFreeText,
282
+ ...pendingParameterUpdates.length > 0 && {
283
+ parameterUpdates: pendingParameterUpdates
284
+ }
285
+ };
286
+ }
287
+ const dataInvestigationResult = await flow.finalize(state, runtime);
288
+ return {
289
+ type: "fulfilled",
290
+ dataInvestigationResult,
291
+ ...pendingParameterUpdates.length > 0 && {
292
+ parameterUpdates: pendingParameterUpdates
293
+ }
294
+ };
295
+ }
296
+ async function resolveSetupSelection(params) {
297
+ const { selected, allSentinel, fetchAll, limit } = params;
298
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
299
+ return resolved.slice(0, limit);
300
+ }
301
+
208
302
  // ../connectors/src/auth-types.ts
209
303
  var AUTH_TYPES = {
210
304
  OAUTH: "oauth",
@@ -235,6 +329,89 @@ var googleSlidesOnboarding = new ConnectorOnboarding({
235
329
  }
236
330
  });
237
331
 
332
+ // ../connectors/src/connectors/google-slides/utils.ts
333
+ async function googleApiFetch(config, url) {
334
+ const res = await config.proxyFetch(url, { method: "GET" });
335
+ if (!res.ok) {
336
+ const text = await res.text().catch(() => res.statusText);
337
+ throw new Error(`Google Slides ${url} failed: HTTP ${res.status} ${text}`);
338
+ }
339
+ return await res.json();
340
+ }
341
+
342
+ // ../connectors/src/connectors/google-slides/setup-flow.ts
343
+ var ALL_PRESENTATIONS = "__ALL_PRESENTATIONS__";
344
+ var GOOGLE_SLIDES_SETUP_MAX_PRESENTATIONS = 10;
345
+ var DRIVE_LIST_PAGE_SIZE = 50;
346
+ async function listPresentations(config) {
347
+ const q = encodeURIComponent(
348
+ "mimeType='application/vnd.google-apps.presentation' and trashed=false"
349
+ );
350
+ const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
351
+ const data = await googleApiFetch(config, url);
352
+ return data.files ?? [];
353
+ }
354
+ var googleSlidesSetupFlow = {
355
+ initialState: () => ({}),
356
+ steps: [
357
+ {
358
+ slug: "presentations",
359
+ type: "multiSelect",
360
+ question: {
361
+ ja: "\u5BFE\u8C61\u306E\u30D7\u30EC\u30BC\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
362
+ en: "Select target presentations (multi-select allowed)"
363
+ },
364
+ async fetchOptions(_state, rt) {
365
+ const files = await listPresentations(rt.config);
366
+ return [
367
+ {
368
+ value: ALL_PRESENTATIONS,
369
+ label: rt.language === "ja" ? "\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u3059\u3079\u3066\u306E\u30D7\u30EC\u30BC\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3" : "All accessible presentations"
370
+ },
371
+ ...files.map((f) => ({ value: f.id, label: f.name }))
372
+ ];
373
+ },
374
+ applyAnswer: (state, answer) => ({ ...state, presentations: answer })
375
+ }
376
+ ],
377
+ async finalize(state, rt) {
378
+ if (!state.presentations) {
379
+ throw new Error("Google Slides setup: incomplete state on finalize");
380
+ }
381
+ const targetIds = await resolveSetupSelection({
382
+ selected: state.presentations,
383
+ allSentinel: ALL_PRESENTATIONS,
384
+ fetchAll: async () => {
385
+ const files = await listPresentations(rt.config);
386
+ return files.map((f) => f.id);
387
+ },
388
+ limit: GOOGLE_SLIDES_SETUP_MAX_PRESENTATIONS
389
+ });
390
+ const sections = ["## Google Slides", ""];
391
+ if (targetIds.length === 0) {
392
+ sections.push(
393
+ rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30D7\u30EC\u30BC\u30F3\u30C6\u30FC\u30B7\u30E7\u30F3\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No presentations selected."
394
+ );
395
+ return sections.join("\n");
396
+ }
397
+ for (const id of targetIds) {
398
+ const url = `https://slides.googleapis.com/v1/presentations/${encodeURIComponent(id)}?fields=presentationId,title,revisionId,slides(objectId)`;
399
+ const meta = await googleApiFetch(
400
+ rt.config,
401
+ url
402
+ );
403
+ const title = meta.title ?? id;
404
+ const slideCount = (meta.slides ?? []).length;
405
+ sections.push(`### Presentation: ${title}`, "");
406
+ sections.push(`- ID: ${id}`);
407
+ sections.push(`- Slides: ${slideCount}`);
408
+ if (meta.revisionId) sections.push(`- Revision: ${meta.revisionId}`);
409
+ sections.push("");
410
+ }
411
+ return sections.join("\n");
412
+ }
413
+ };
414
+
238
415
  // ../connectors/src/connectors/google-slides/parameters.ts
239
416
  var parameters = {};
240
417
 
@@ -365,6 +542,7 @@ var tools = { request: requestTool };
365
542
  var googleSlidesConnector = new ConnectorPlugin({
366
543
  slug: "google-slides",
367
544
  authType: AUTH_TYPES.OAUTH,
545
+ skipConnectionCheckOnCreate: true,
368
546
  name: "Google Slides",
369
547
  description: "Connect to Google Slides for presentation data access and creation using OAuth.",
370
548
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4oyF4yTRpemMA43X49masx/e1582d25e3b4c9a63ba83df2147c1968/google_slide.png",
@@ -540,7 +718,8 @@ await slides.batchUpdate(presentationId, [
540
718
 
541
719
  \u30CF\u30F3\u30C9\u30E9\u306E\u30C6\u30B9\u30C8\u304C \`Connection proxy is not configured\` \u3067\u5931\u6557\u3059\u308B\u5834\u5408\u306F\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u901A\u5E38\u306F\u30B5\u30F3\u30C9\u30DC\u30C3\u30AF\u30B9\u306E\u521D\u671F\u5316\u4E2D\u306B\u8D77\u304D\u307E\u3059\u3002SDK \u3092\u8AE6\u3081\u3066 OAuth \u30D7\u30ED\u30AD\u30B7\u306E URL \u3092\u81EA\u5206\u3067\u7D44\u307F\u7ACB\u3066\u308B\u3053\u3068\u306F **\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044**\u3002`
542
720
  },
543
- tools
721
+ tools,
722
+ setup: (params, ctx, config) => runSetupFlow(googleSlidesSetupFlow, params, ctx, config)
544
723
  });
545
724
 
546
725
  // src/connectors/create-connector-sdk.ts
@@ -569,6 +748,7 @@ function resolveEnvVarOptional(entry, key) {
569
748
  import { getContext } from "hono/context-storage";
570
749
  import { getCookie } from "hono/cookie";
571
750
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
751
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
572
752
  function normalizeHeaders(input) {
573
753
  const out = {};
574
754
  if (!input) return out;
@@ -577,6 +757,11 @@ function normalizeHeaders(input) {
577
757
  });
578
758
  return out;
579
759
  }
760
+ function extractInputUrl(input) {
761
+ if (typeof input === "string") return input;
762
+ if (input instanceof URL) return input.href;
763
+ return input.url;
764
+ }
580
765
  function createSandboxProxyFetch(connectionId) {
581
766
  return async (input, init) => {
582
767
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -586,10 +771,17 @@ function createSandboxProxyFetch(connectionId) {
586
771
  "Connection proxy is not configured. Please check your deployment settings."
587
772
  );
588
773
  }
589
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
774
+ const originalUrl = extractInputUrl(input);
775
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
776
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
777
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
778
+ return fetch(sessionUrl, {
779
+ method: "POST",
780
+ headers: { Authorization: `Bearer ${token}` }
781
+ });
782
+ }
590
783
  const originalMethod = init?.method ?? "GET";
591
784
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
592
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
593
785
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
594
786
  return fetch(proxyUrl, {
595
787
  method: "POST",
@@ -615,10 +807,9 @@ function createDeployedAppProxyFetch(connectionId) {
615
807
  }
616
808
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
617
809
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
810
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
618
811
  return async (input, init) => {
619
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
620
- const originalMethod = init?.method ?? "GET";
621
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
812
+ const originalUrl = extractInputUrl(input);
622
813
  const c = getContext();
623
814
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
624
815
  if (!appSession) {
@@ -626,6 +817,14 @@ function createDeployedAppProxyFetch(connectionId) {
626
817
  "No authentication method available for connection proxy."
627
818
  );
628
819
  }
820
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
821
+ return fetch(sessionUrl, {
822
+ method: "POST",
823
+ headers: { Authorization: `Bearer ${appSession}` }
824
+ });
825
+ }
826
+ const originalMethod = init?.method ?? "GET";
827
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
629
828
  return fetch(proxyUrl, {
630
829
  method: "POST",
631
830
  headers: {