@squadbase/vite-server 0.1.12-dev.a9ac647 → 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 +12374 -883
  2. package/dist/connectors/airtable-oauth.js +257 -46
  3. package/dist/connectors/airtable.js +294 -51
  4. package/dist/connectors/amplitude.js +297 -47
  5. package/dist/connectors/anthropic.js +135 -47
  6. package/dist/connectors/asana.js +302 -49
  7. package/dist/connectors/attio.js +277 -49
  8. package/dist/connectors/aws-billing.js +262 -46
  9. package/dist/connectors/azure-sql.js +396 -102
  10. package/dist/connectors/backlog-api-key.js +292 -47
  11. package/dist/connectors/clickup.js +313 -49
  12. package/dist/connectors/cosmosdb.js +280 -50
  13. package/dist/connectors/customerio.js +294 -47
  14. package/dist/connectors/dbt.js +315 -47
  15. package/dist/connectors/freshdesk.js +317 -53
  16. package/dist/connectors/freshsales.js +308 -52
  17. package/dist/connectors/freshservice.js +336 -53
  18. package/dist/connectors/gamma.js +302 -52
  19. package/dist/connectors/gemini.js +134 -47
  20. package/dist/connectors/github.js +361 -49
  21. package/dist/connectors/gmail-oauth.js +179 -7
  22. package/dist/connectors/gmail.js +325 -47
  23. package/dist/connectors/google-ads.js +263 -46
  24. package/dist/connectors/google-analytics-oauth.js +285 -46
  25. package/dist/connectors/google-analytics.js +387 -49
  26. package/dist/connectors/google-audit-log.js +413 -47
  27. package/dist/connectors/google-calendar-oauth.js +234 -46
  28. package/dist/connectors/google-calendar.js +334 -47
  29. package/dist/connectors/google-docs.js +195 -6
  30. package/dist/connectors/google-drive.js +237 -5
  31. package/dist/connectors/google-search-console-oauth.js +231 -46
  32. package/dist/connectors/google-sheets.js +247 -47
  33. package/dist/connectors/google-slides.js +180 -6
  34. package/dist/connectors/grafana.js +307 -49
  35. package/dist/connectors/hubspot-oauth.js +183 -5
  36. package/dist/connectors/hubspot.js +281 -49
  37. package/dist/connectors/influxdb.js +391 -51
  38. package/dist/connectors/intercom-oauth.js +185 -5
  39. package/dist/connectors/intercom.js +277 -49
  40. package/dist/connectors/jdbc.js +737 -110
  41. package/dist/connectors/jira-api-key.js +301 -47
  42. package/dist/connectors/kintone-api-token.js +256 -47
  43. package/dist/connectors/kintone.js +303 -47
  44. package/dist/connectors/linear.js +305 -49
  45. package/dist/connectors/linkedin-ads.js +243 -50
  46. package/dist/connectors/mailchimp-oauth.js +243 -46
  47. package/dist/connectors/mailchimp.js +295 -49
  48. package/dist/connectors/meta-ads-oauth.js +248 -48
  49. package/dist/connectors/meta-ads.js +260 -50
  50. package/dist/connectors/mixpanel.js +313 -47
  51. package/dist/connectors/monday.js +335 -49
  52. package/dist/connectors/mongodb.js +294 -57
  53. package/dist/connectors/notion-oauth.js +206 -5
  54. package/dist/connectors/notion.js +298 -51
  55. package/dist/connectors/openai.js +134 -47
  56. package/dist/connectors/oracle.js +414 -103
  57. package/dist/connectors/outlook-oauth.js +179 -5
  58. package/dist/connectors/powerbi-oauth.js +226 -5
  59. package/dist/connectors/salesforce.js +359 -49
  60. package/dist/connectors/semrush.js +289 -49
  61. package/dist/connectors/sentry.js +264 -50
  62. package/dist/connectors/shopify-oauth.js +162 -5
  63. package/dist/connectors/shopify.js +332 -47
  64. package/dist/connectors/sqlserver.js +390 -102
  65. package/dist/connectors/stripe-api-key.js +244 -46
  66. package/dist/connectors/stripe-oauth.js +177 -5
  67. package/dist/connectors/supabase.js +278 -48
  68. package/dist/connectors/tableau.js +389 -184
  69. package/dist/connectors/tiktok-ads.js +254 -48
  70. package/dist/connectors/wix-store.js +295 -49
  71. package/dist/connectors/zendesk-oauth.js +214 -5
  72. package/dist/connectors/zendesk.js +333 -47
  73. package/dist/index.d.ts +149 -1
  74. package/dist/index.js +13677 -1969
  75. package/dist/main.js +13627 -1927
  76. package/dist/vite-plugin.js +12391 -890
  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,51 @@ 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
+ for (const step of flow.steps) {
311
+ const ans = ctx.answers[answerIdx];
312
+ if (ans && ans.questionSlug === step.slug) {
313
+ state = step.applyAnswer(state, ans.answer);
314
+ answerIdx += 1;
315
+ continue;
316
+ }
317
+ if (step.type === "text") {
318
+ return {
319
+ type: "nextQuestion",
320
+ questionSlug: step.slug,
321
+ question: step.question[ctx.language],
322
+ questionType: "text"
323
+ };
324
+ }
325
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
326
+ if (options.length === 0) {
327
+ continue;
328
+ }
329
+ return {
330
+ type: "nextQuestion",
331
+ questionSlug: step.slug,
332
+ question: step.question[ctx.language],
333
+ questionType: step.type,
334
+ options
335
+ };
336
+ }
337
+ const dataInvestigationResult = await flow.finalize(state, runtime);
338
+ return { type: "fulfilled", dataInvestigationResult };
339
+ }
340
+ async function resolveSetupSelection(params) {
341
+ const { selected, allSentinel, fetchAll, limit } = params;
342
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
343
+ return resolved.slice(0, limit);
344
+ }
345
+
266
346
  // ../connectors/src/auth-types.ts
267
347
  var AUTH_TYPES = {
268
348
  OAUTH: "oauth",
@@ -461,7 +541,105 @@ var googleSheetsOnboarding = new ConnectorOnboarding({
461
541
  }
462
542
  });
463
543
 
544
+ // ../connectors/src/connectors/google-sheets/utils.ts
545
+ async function googleApiFetch(config, url) {
546
+ const res = await config.proxyFetch(url, { method: "GET" });
547
+ if (!res.ok) {
548
+ const text = await res.text().catch(() => res.statusText);
549
+ throw new Error(`Google API ${url} failed: HTTP ${res.status} ${text}`);
550
+ }
551
+ return await res.json();
552
+ }
553
+
554
+ // ../connectors/src/connectors/google-sheets/setup-flow.ts
555
+ var ALL_SPREADSHEETS = "__ALL_SPREADSHEETS__";
556
+ var GOOGLE_SHEETS_SETUP_MAX_SPREADSHEETS = 10;
557
+ var DRIVE_LIST_PAGE_SIZE = 50;
558
+ async function listSpreadsheets(config) {
559
+ const q = encodeURIComponent(
560
+ "mimeType='application/vnd.google-apps.spreadsheet' and trashed=false"
561
+ );
562
+ const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
563
+ const data = await googleApiFetch(config, url);
564
+ return data.files ?? [];
565
+ }
566
+ var googleSheetsSetupFlow = {
567
+ initialState: () => ({}),
568
+ steps: [
569
+ {
570
+ slug: "spreadsheets",
571
+ type: "multiSelect",
572
+ question: {
573
+ 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",
574
+ en: "Select target spreadsheets (multi-select allowed)"
575
+ },
576
+ async fetchOptions(_state, rt) {
577
+ const files = await listSpreadsheets(rt.config);
578
+ const fileOptions = files.map((f) => ({
579
+ value: f.id,
580
+ label: f.name
581
+ }));
582
+ return [
583
+ {
584
+ value: ALL_SPREADSHEETS,
585
+ 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"
586
+ },
587
+ ...fileOptions
588
+ ];
589
+ },
590
+ applyAnswer: (state, answer) => ({ ...state, spreadsheets: answer })
591
+ }
592
+ ],
593
+ async finalize(state, rt) {
594
+ if (!state.spreadsheets) {
595
+ throw new Error("Google Sheets setup: incomplete state on finalize");
596
+ }
597
+ const targetIds = await resolveSetupSelection({
598
+ selected: state.spreadsheets,
599
+ allSentinel: ALL_SPREADSHEETS,
600
+ fetchAll: async () => {
601
+ const files = await listSpreadsheets(rt.config);
602
+ return files.map((f) => f.id);
603
+ },
604
+ limit: GOOGLE_SHEETS_SETUP_MAX_SPREADSHEETS
605
+ });
606
+ const sections = ["## Google Sheets", ""];
607
+ if (targetIds.length === 0) {
608
+ sections.push(
609
+ 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."
610
+ );
611
+ return sections.join("\n");
612
+ }
613
+ for (const id of targetIds) {
614
+ const url = `https://sheets.googleapis.com/v4/spreadsheets/${encodeURIComponent(id)}?fields=spreadsheetId,properties(title),sheets(properties(title,sheetId,gridProperties))`;
615
+ const meta = await googleApiFetch(
616
+ rt.config,
617
+ url
618
+ );
619
+ const title = meta.properties?.title ?? id;
620
+ sections.push(`### Spreadsheet: ${title}`, "", `- ID: ${id}`, "");
621
+ const sheets = meta.sheets ?? [];
622
+ if (sheets.length === 0) {
623
+ sections.push("- (no sheet tabs)", "");
624
+ continue;
625
+ }
626
+ sections.push("| Sheet | Rows | Columns |");
627
+ sections.push("|-------|------|---------|");
628
+ for (const s of sheets) {
629
+ const p = s.properties ?? {};
630
+ const sheetTitle = p.title ?? "(untitled)";
631
+ const rows = p.gridProperties?.rowCount ?? "-";
632
+ const cols = p.gridProperties?.columnCount ?? "-";
633
+ sections.push(`| ${sheetTitle} | ${rows} | ${cols} |`);
634
+ }
635
+ sections.push("");
636
+ }
637
+ return sections.join("\n");
638
+ }
639
+ };
640
+
464
641
  // ../connectors/src/connectors/google-sheets/parameters.ts
642
+ init_parameter_definition();
465
643
  var parameters = {
466
644
  spreadsheetId: new ParameterDefinition({
467
645
  slug: "spreadsheet-id",
@@ -479,6 +657,7 @@ var tools = { request: requestTool };
479
657
  var googleSheetsConnector = new ConnectorPlugin({
480
658
  slug: "google-sheets",
481
659
  authType: AUTH_TYPES.OAUTH,
660
+ skipConnectionCheckOnCreate: true,
482
661
  name: "Google Sheets",
483
662
  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
663
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
@@ -644,7 +823,8 @@ await sheets.batchUpdate(spreadsheetId, [
644
823
  ]);
645
824
  \`\`\``
646
825
  },
647
- tools
826
+ tools,
827
+ setup: (params, ctx, config) => runSetupFlow(googleSheetsSetupFlow, params, ctx, config)
648
828
  });
649
829
 
650
830
  // src/connectors/create-connector-sdk.ts
@@ -673,6 +853,7 @@ function resolveEnvVarOptional(entry, key) {
673
853
  import { getContext } from "hono/context-storage";
674
854
  import { getCookie } from "hono/cookie";
675
855
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
856
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
676
857
  function normalizeHeaders(input) {
677
858
  const out = {};
678
859
  if (!input) return out;
@@ -681,6 +862,11 @@ function normalizeHeaders(input) {
681
862
  });
682
863
  return out;
683
864
  }
865
+ function extractInputUrl(input) {
866
+ if (typeof input === "string") return input;
867
+ if (input instanceof URL) return input.href;
868
+ return input.url;
869
+ }
684
870
  function createSandboxProxyFetch(connectionId) {
685
871
  return async (input, init) => {
686
872
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -690,10 +876,17 @@ function createSandboxProxyFetch(connectionId) {
690
876
  "Connection proxy is not configured. Please check your deployment settings."
691
877
  );
692
878
  }
693
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
879
+ const originalUrl = extractInputUrl(input);
880
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
881
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
882
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
883
+ return fetch(sessionUrl, {
884
+ method: "POST",
885
+ headers: { Authorization: `Bearer ${token}` }
886
+ });
887
+ }
694
888
  const originalMethod = init?.method ?? "GET";
695
889
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
696
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
697
890
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
698
891
  return fetch(proxyUrl, {
699
892
  method: "POST",
@@ -719,10 +912,9 @@ function createDeployedAppProxyFetch(connectionId) {
719
912
  }
720
913
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
721
914
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
915
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
722
916
  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;
917
+ const originalUrl = extractInputUrl(input);
726
918
  const c = getContext();
727
919
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
728
920
  if (!appSession) {
@@ -730,6 +922,14 @@ function createDeployedAppProxyFetch(connectionId) {
730
922
  "No authentication method available for connection proxy."
731
923
  );
732
924
  }
925
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
926
+ return fetch(sessionUrl, {
927
+ method: "POST",
928
+ headers: { Authorization: `Bearer ${appSession}` }
929
+ });
930
+ }
931
+ const originalMethod = init?.method ?? "GET";
932
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
733
933
  return fetch(proxyUrl, {
734
934
  method: "POST",
735
935
  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,51 @@ 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
+ for (const step of flow.steps) {
242
+ const ans = ctx.answers[answerIdx];
243
+ if (ans && ans.questionSlug === step.slug) {
244
+ state = step.applyAnswer(state, ans.answer);
245
+ answerIdx += 1;
246
+ continue;
247
+ }
248
+ if (step.type === "text") {
249
+ return {
250
+ type: "nextQuestion",
251
+ questionSlug: step.slug,
252
+ question: step.question[ctx.language],
253
+ questionType: "text"
254
+ };
255
+ }
256
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
257
+ if (options.length === 0) {
258
+ continue;
259
+ }
260
+ return {
261
+ type: "nextQuestion",
262
+ questionSlug: step.slug,
263
+ question: step.question[ctx.language],
264
+ questionType: step.type,
265
+ options
266
+ };
267
+ }
268
+ const dataInvestigationResult = await flow.finalize(state, runtime);
269
+ return { type: "fulfilled", dataInvestigationResult };
270
+ }
271
+ async function resolveSetupSelection(params) {
272
+ const { selected, allSentinel, fetchAll, limit } = params;
273
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
274
+ return resolved.slice(0, limit);
275
+ }
276
+
208
277
  // ../connectors/src/auth-types.ts
209
278
  var AUTH_TYPES = {
210
279
  OAUTH: "oauth",
@@ -235,6 +304,89 @@ var googleSlidesOnboarding = new ConnectorOnboarding({
235
304
  }
236
305
  });
237
306
 
307
+ // ../connectors/src/connectors/google-slides/utils.ts
308
+ async function googleApiFetch(config, url) {
309
+ const res = await config.proxyFetch(url, { method: "GET" });
310
+ if (!res.ok) {
311
+ const text = await res.text().catch(() => res.statusText);
312
+ throw new Error(`Google Slides ${url} failed: HTTP ${res.status} ${text}`);
313
+ }
314
+ return await res.json();
315
+ }
316
+
317
+ // ../connectors/src/connectors/google-slides/setup-flow.ts
318
+ var ALL_PRESENTATIONS = "__ALL_PRESENTATIONS__";
319
+ var GOOGLE_SLIDES_SETUP_MAX_PRESENTATIONS = 10;
320
+ var DRIVE_LIST_PAGE_SIZE = 50;
321
+ async function listPresentations(config) {
322
+ const q = encodeURIComponent(
323
+ "mimeType='application/vnd.google-apps.presentation' and trashed=false"
324
+ );
325
+ const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
326
+ const data = await googleApiFetch(config, url);
327
+ return data.files ?? [];
328
+ }
329
+ var googleSlidesSetupFlow = {
330
+ initialState: () => ({}),
331
+ steps: [
332
+ {
333
+ slug: "presentations",
334
+ type: "multiSelect",
335
+ question: {
336
+ 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",
337
+ en: "Select target presentations (multi-select allowed)"
338
+ },
339
+ async fetchOptions(_state, rt) {
340
+ const files = await listPresentations(rt.config);
341
+ return [
342
+ {
343
+ value: ALL_PRESENTATIONS,
344
+ 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"
345
+ },
346
+ ...files.map((f) => ({ value: f.id, label: f.name }))
347
+ ];
348
+ },
349
+ applyAnswer: (state, answer) => ({ ...state, presentations: answer })
350
+ }
351
+ ],
352
+ async finalize(state, rt) {
353
+ if (!state.presentations) {
354
+ throw new Error("Google Slides setup: incomplete state on finalize");
355
+ }
356
+ const targetIds = await resolveSetupSelection({
357
+ selected: state.presentations,
358
+ allSentinel: ALL_PRESENTATIONS,
359
+ fetchAll: async () => {
360
+ const files = await listPresentations(rt.config);
361
+ return files.map((f) => f.id);
362
+ },
363
+ limit: GOOGLE_SLIDES_SETUP_MAX_PRESENTATIONS
364
+ });
365
+ const sections = ["## Google Slides", ""];
366
+ if (targetIds.length === 0) {
367
+ sections.push(
368
+ 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."
369
+ );
370
+ return sections.join("\n");
371
+ }
372
+ for (const id of targetIds) {
373
+ const url = `https://slides.googleapis.com/v1/presentations/${encodeURIComponent(id)}?fields=presentationId,title,revisionId,slides(objectId)`;
374
+ const meta = await googleApiFetch(
375
+ rt.config,
376
+ url
377
+ );
378
+ const title = meta.title ?? id;
379
+ const slideCount = (meta.slides ?? []).length;
380
+ sections.push(`### Presentation: ${title}`, "");
381
+ sections.push(`- ID: ${id}`);
382
+ sections.push(`- Slides: ${slideCount}`);
383
+ if (meta.revisionId) sections.push(`- Revision: ${meta.revisionId}`);
384
+ sections.push("");
385
+ }
386
+ return sections.join("\n");
387
+ }
388
+ };
389
+
238
390
  // ../connectors/src/connectors/google-slides/parameters.ts
239
391
  var parameters = {};
240
392
 
@@ -365,6 +517,7 @@ var tools = { request: requestTool };
365
517
  var googleSlidesConnector = new ConnectorPlugin({
366
518
  slug: "google-slides",
367
519
  authType: AUTH_TYPES.OAUTH,
520
+ skipConnectionCheckOnCreate: true,
368
521
  name: "Google Slides",
369
522
  description: "Connect to Google Slides for presentation data access and creation using OAuth.",
370
523
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4oyF4yTRpemMA43X49masx/e1582d25e3b4c9a63ba83df2147c1968/google_slide.png",
@@ -540,7 +693,8 @@ await slides.batchUpdate(presentationId, [
540
693
 
541
694
  \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
695
  },
543
- tools
696
+ tools,
697
+ setup: (params, ctx, config) => runSetupFlow(googleSlidesSetupFlow, params, ctx, config)
544
698
  });
545
699
 
546
700
  // src/connectors/create-connector-sdk.ts
@@ -569,6 +723,7 @@ function resolveEnvVarOptional(entry, key) {
569
723
  import { getContext } from "hono/context-storage";
570
724
  import { getCookie } from "hono/cookie";
571
725
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
726
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
572
727
  function normalizeHeaders(input) {
573
728
  const out = {};
574
729
  if (!input) return out;
@@ -577,6 +732,11 @@ function normalizeHeaders(input) {
577
732
  });
578
733
  return out;
579
734
  }
735
+ function extractInputUrl(input) {
736
+ if (typeof input === "string") return input;
737
+ if (input instanceof URL) return input.href;
738
+ return input.url;
739
+ }
580
740
  function createSandboxProxyFetch(connectionId) {
581
741
  return async (input, init) => {
582
742
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -586,10 +746,17 @@ function createSandboxProxyFetch(connectionId) {
586
746
  "Connection proxy is not configured. Please check your deployment settings."
587
747
  );
588
748
  }
589
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
749
+ const originalUrl = extractInputUrl(input);
750
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
751
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
752
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
753
+ return fetch(sessionUrl, {
754
+ method: "POST",
755
+ headers: { Authorization: `Bearer ${token}` }
756
+ });
757
+ }
590
758
  const originalMethod = init?.method ?? "GET";
591
759
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
592
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
593
760
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
594
761
  return fetch(proxyUrl, {
595
762
  method: "POST",
@@ -615,10 +782,9 @@ function createDeployedAppProxyFetch(connectionId) {
615
782
  }
616
783
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
617
784
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
785
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
618
786
  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;
787
+ const originalUrl = extractInputUrl(input);
622
788
  const c = getContext();
623
789
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
624
790
  if (!appSession) {
@@ -626,6 +792,14 @@ function createDeployedAppProxyFetch(connectionId) {
626
792
  "No authentication method available for connection proxy."
627
793
  );
628
794
  }
795
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
796
+ return fetch(sessionUrl, {
797
+ method: "POST",
798
+ headers: { Authorization: `Bearer ${appSession}` }
799
+ });
800
+ }
801
+ const originalMethod = init?.method ?? "GET";
802
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
629
803
  return fetch(proxyUrl, {
630
804
  method: "POST",
631
805
  headers: {