@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
@@ -113,6 +113,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
113
113
  tools;
114
114
  query;
115
115
  checkConnection;
116
+ /**
117
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
118
+ * implement this expose a step-by-step exploration flow (database/schema/
119
+ * table/etc. discovery) that the dashboard backend drives via the
120
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
121
+ * `runSetupFlow` from `setup-flow.ts`.
122
+ */
123
+ setup;
124
+ /**
125
+ * Opt-out of the default "verify before save" behavior on connection
126
+ * creation. The backend invokes `checkConnection` synchronously while
127
+ * creating the connection and aborts (no row inserted) if it fails — this
128
+ * flag disables that for connectors where the check cannot succeed pre-save:
129
+ *
130
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
131
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
132
+ * connectionId, which doesn't exist until the row is saved
133
+ *
134
+ * Exceptions are the explicit position; new credential-input connectors get
135
+ * the default verify-on-create behavior without opt-in.
136
+ */
137
+ skipConnectionCheckOnCreate;
116
138
  constructor(config) {
117
139
  this.slug = config.slug;
118
140
  this.authType = config.authType;
@@ -129,6 +151,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
129
151
  this.tools = config.tools;
130
152
  this.query = config.query;
131
153
  this.checkConnection = config.checkConnection;
154
+ this.setup = config.setup;
155
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
132
156
  }
133
157
  get connectorKey() {
134
158
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -193,6 +217,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
193
217
  }
194
218
  };
195
219
 
220
+ // ../connectors/src/setup-flow.ts
221
+ async function runSetupFlow(flow, params, ctx, config) {
222
+ const runtime = {
223
+ params,
224
+ language: ctx.language,
225
+ config
226
+ };
227
+ let state = flow.initialState();
228
+ let answerIdx = 0;
229
+ for (const step of flow.steps) {
230
+ const ans = ctx.answers[answerIdx];
231
+ if (ans && ans.questionSlug === step.slug) {
232
+ state = step.applyAnswer(state, ans.answer);
233
+ answerIdx += 1;
234
+ continue;
235
+ }
236
+ if (step.type === "text") {
237
+ return {
238
+ type: "nextQuestion",
239
+ questionSlug: step.slug,
240
+ question: step.question[ctx.language],
241
+ questionType: "text"
242
+ };
243
+ }
244
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
245
+ if (options.length === 0) {
246
+ continue;
247
+ }
248
+ return {
249
+ type: "nextQuestion",
250
+ questionSlug: step.slug,
251
+ question: step.question[ctx.language],
252
+ questionType: step.type,
253
+ options
254
+ };
255
+ }
256
+ const dataInvestigationResult = await flow.finalize(state, runtime);
257
+ return { type: "fulfilled", dataInvestigationResult };
258
+ }
259
+ async function resolveSetupSelection(params) {
260
+ const { selected, allSentinel, fetchAll, limit } = params;
261
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
262
+ return resolved.slice(0, limit);
263
+ }
264
+
196
265
  // ../connectors/src/auth-types.ts
197
266
  var AUTH_TYPES = {
198
267
  OAUTH: "oauth",
@@ -223,6 +292,104 @@ var googleDocsOnboarding = new ConnectorOnboarding({
223
292
  }
224
293
  });
225
294
 
295
+ // ../connectors/src/connectors/google-docs/utils.ts
296
+ async function googleApiFetch(config, url) {
297
+ const res = await config.proxyFetch(url, { method: "GET" });
298
+ if (!res.ok) {
299
+ const text = await res.text().catch(() => res.statusText);
300
+ throw new Error(`Google Docs ${url} failed: HTTP ${res.status} ${text}`);
301
+ }
302
+ return await res.json();
303
+ }
304
+
305
+ // ../connectors/src/connectors/google-docs/setup-flow.ts
306
+ var ALL_DOCUMENTS = "__ALL_DOCUMENTS__";
307
+ var GOOGLE_DOCS_SETUP_MAX_DOCUMENTS = 10;
308
+ var DRIVE_LIST_PAGE_SIZE = 50;
309
+ async function listDocuments(config) {
310
+ const q = encodeURIComponent(
311
+ "mimeType='application/vnd.google-apps.document' and trashed=false"
312
+ );
313
+ const url = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=${DRIVE_LIST_PAGE_SIZE}&orderBy=modifiedTime%20desc&fields=files(id,name,modifiedTime)`;
314
+ const data = await googleApiFetch(config, url);
315
+ return data.files ?? [];
316
+ }
317
+ function extractHeadings(meta, max) {
318
+ const out = [];
319
+ for (const c of meta.body?.content ?? []) {
320
+ const p = c.paragraph;
321
+ if (!p) continue;
322
+ const style = p.paragraphStyle?.namedStyleType ?? "";
323
+ if (!style.startsWith("HEADING_")) continue;
324
+ const text = (p.elements ?? []).map((el) => el.textRun?.content ?? "").join("").trim();
325
+ if (text) out.push(`${style}: ${text}`);
326
+ if (out.length >= max) break;
327
+ }
328
+ return out;
329
+ }
330
+ var googleDocsSetupFlow = {
331
+ initialState: () => ({}),
332
+ steps: [
333
+ {
334
+ slug: "documents",
335
+ type: "multiSelect",
336
+ question: {
337
+ ja: "\u5BFE\u8C61\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
338
+ en: "Select target documents (multi-select allowed)"
339
+ },
340
+ async fetchOptions(_state, rt) {
341
+ const files = await listDocuments(rt.config);
342
+ return [
343
+ {
344
+ value: ALL_DOCUMENTS,
345
+ label: rt.language === "ja" ? "\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u3059\u3079\u3066\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8" : "All accessible documents"
346
+ },
347
+ ...files.map((f) => ({ value: f.id, label: f.name }))
348
+ ];
349
+ },
350
+ applyAnswer: (state, answer) => ({ ...state, documents: answer })
351
+ }
352
+ ],
353
+ async finalize(state, rt) {
354
+ if (!state.documents) {
355
+ throw new Error("Google Docs setup: incomplete state on finalize");
356
+ }
357
+ const targetIds = await resolveSetupSelection({
358
+ selected: state.documents,
359
+ allSentinel: ALL_DOCUMENTS,
360
+ fetchAll: async () => {
361
+ const files = await listDocuments(rt.config);
362
+ return files.map((f) => f.id);
363
+ },
364
+ limit: GOOGLE_DOCS_SETUP_MAX_DOCUMENTS
365
+ });
366
+ const sections = ["## Google Docs", ""];
367
+ if (targetIds.length === 0) {
368
+ sections.push(
369
+ rt.language === "ja" ? "\u5BFE\u8C61\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002" : "No documents selected."
370
+ );
371
+ return sections.join("\n");
372
+ }
373
+ for (const id of targetIds) {
374
+ const url = `https://docs.googleapis.com/v1/documents/${encodeURIComponent(
375
+ id
376
+ )}`;
377
+ const meta = await googleApiFetch(rt.config, url);
378
+ const title = meta.title ?? id;
379
+ sections.push(`### Document: ${title}`, "");
380
+ sections.push(`- ID: ${id}`);
381
+ if (meta.revisionId) sections.push(`- Revision: ${meta.revisionId}`);
382
+ const headings = extractHeadings(meta, 5);
383
+ if (headings.length > 0) {
384
+ sections.push("- Outline:");
385
+ for (const h of headings) sections.push(` - ${h}`);
386
+ }
387
+ sections.push("");
388
+ }
389
+ return sections.join("\n");
390
+ }
391
+ };
392
+
226
393
  // ../connectors/src/connectors/google-docs/parameters.ts
227
394
  var parameters = {};
228
395
 
@@ -355,6 +522,7 @@ var tools = { request: requestTool };
355
522
  var googleDocsConnector = new ConnectorPlugin({
356
523
  slug: "google-docs",
357
524
  authType: AUTH_TYPES.OAUTH,
525
+ skipConnectionCheckOnCreate: true,
358
526
  name: "Google Docs",
359
527
  description: "Connect to Google Docs for document data access and creation using OAuth.",
360
528
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6vvcGJisvXjOumeTvswjzf/e9bb39e453cc0b71a20f26019b23b0d2/google_docs.png",
@@ -510,7 +678,8 @@ await docs.batchUpdate(documentId, [
510
678
  ]);
511
679
  \`\`\``
512
680
  },
513
- tools
681
+ tools,
682
+ setup: (params, ctx, config) => runSetupFlow(googleDocsSetupFlow, params, ctx, config)
514
683
  });
515
684
 
516
685
  // src/connectors/create-connector-sdk.ts
@@ -539,6 +708,7 @@ function resolveEnvVarOptional(entry, key) {
539
708
  import { getContext } from "hono/context-storage";
540
709
  import { getCookie } from "hono/cookie";
541
710
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
711
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
542
712
  function normalizeHeaders(input) {
543
713
  const out = {};
544
714
  if (!input) return out;
@@ -547,6 +717,11 @@ function normalizeHeaders(input) {
547
717
  });
548
718
  return out;
549
719
  }
720
+ function extractInputUrl(input) {
721
+ if (typeof input === "string") return input;
722
+ if (input instanceof URL) return input.href;
723
+ return input.url;
724
+ }
550
725
  function createSandboxProxyFetch(connectionId) {
551
726
  return async (input, init) => {
552
727
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -556,10 +731,17 @@ function createSandboxProxyFetch(connectionId) {
556
731
  "Connection proxy is not configured. Please check your deployment settings."
557
732
  );
558
733
  }
559
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
734
+ const originalUrl = extractInputUrl(input);
735
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
736
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
737
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
738
+ return fetch(sessionUrl, {
739
+ method: "POST",
740
+ headers: { Authorization: `Bearer ${token}` }
741
+ });
742
+ }
560
743
  const originalMethod = init?.method ?? "GET";
561
744
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
562
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
563
745
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
564
746
  return fetch(proxyUrl, {
565
747
  method: "POST",
@@ -585,10 +767,9 @@ function createDeployedAppProxyFetch(connectionId) {
585
767
  }
586
768
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
587
769
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
770
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
588
771
  return async (input, init) => {
589
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
590
- const originalMethod = init?.method ?? "GET";
591
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
772
+ const originalUrl = extractInputUrl(input);
592
773
  const c = getContext();
593
774
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
594
775
  if (!appSession) {
@@ -596,6 +777,14 @@ function createDeployedAppProxyFetch(connectionId) {
596
777
  "No authentication method available for connection proxy."
597
778
  );
598
779
  }
780
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
781
+ return fetch(sessionUrl, {
782
+ method: "POST",
783
+ headers: { Authorization: `Bearer ${appSession}` }
784
+ });
785
+ }
786
+ const originalMethod = init?.method ?? "GET";
787
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
599
788
  return fetch(proxyUrl, {
600
789
  method: "POST",
601
790
  headers: {
@@ -202,6 +202,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
202
202
  tools;
203
203
  query;
204
204
  checkConnection;
205
+ /**
206
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
207
+ * implement this expose a step-by-step exploration flow (database/schema/
208
+ * table/etc. discovery) that the dashboard backend drives via the
209
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
210
+ * `runSetupFlow` from `setup-flow.ts`.
211
+ */
212
+ setup;
213
+ /**
214
+ * Opt-out of the default "verify before save" behavior on connection
215
+ * creation. The backend invokes `checkConnection` synchronously while
216
+ * creating the connection and aborts (no row inserted) if it fails — this
217
+ * flag disables that for connectors where the check cannot succeed pre-save:
218
+ *
219
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
220
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
221
+ * connectionId, which doesn't exist until the row is saved
222
+ *
223
+ * Exceptions are the explicit position; new credential-input connectors get
224
+ * the default verify-on-create behavior without opt-in.
225
+ */
226
+ skipConnectionCheckOnCreate;
205
227
  constructor(config) {
206
228
  this.slug = config.slug;
207
229
  this.authType = config.authType;
@@ -218,6 +240,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
218
240
  this.tools = config.tools;
219
241
  this.query = config.query;
220
242
  this.checkConnection = config.checkConnection;
243
+ this.setup = config.setup;
244
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
221
245
  }
222
246
  get connectorKey() {
223
247
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -282,6 +306,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
282
306
  }
283
307
  };
284
308
 
309
+ // ../connectors/src/setup-flow.ts
310
+ async function runSetupFlow(flow, params, ctx, config) {
311
+ const runtime = {
312
+ params,
313
+ language: ctx.language,
314
+ config
315
+ };
316
+ let state = flow.initialState();
317
+ let answerIdx = 0;
318
+ for (const step of flow.steps) {
319
+ const ans = ctx.answers[answerIdx];
320
+ if (ans && ans.questionSlug === step.slug) {
321
+ state = step.applyAnswer(state, ans.answer);
322
+ answerIdx += 1;
323
+ continue;
324
+ }
325
+ if (step.type === "text") {
326
+ return {
327
+ type: "nextQuestion",
328
+ questionSlug: step.slug,
329
+ question: step.question[ctx.language],
330
+ questionType: "text"
331
+ };
332
+ }
333
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
334
+ if (options.length === 0) {
335
+ continue;
336
+ }
337
+ return {
338
+ type: "nextQuestion",
339
+ questionSlug: step.slug,
340
+ question: step.question[ctx.language],
341
+ questionType: step.type,
342
+ options
343
+ };
344
+ }
345
+ const dataInvestigationResult = await flow.finalize(state, runtime);
346
+ return { type: "fulfilled", dataInvestigationResult };
347
+ }
348
+ async function resolveSetupSelection(params) {
349
+ const { selected, allSentinel, fetchAll, limit } = params;
350
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
351
+ return resolved.slice(0, limit);
352
+ }
353
+
285
354
  // ../connectors/src/auth-types.ts
286
355
  var AUTH_TYPES = {
287
356
  OAUTH: "oauth",
@@ -312,6 +381,147 @@ var googleDriveOnboarding = new ConnectorOnboarding({
312
381
  }
313
382
  });
314
383
 
384
+ // ../connectors/src/connectors/google-drive/utils.ts
385
+ async function googleApiFetch(config, url) {
386
+ const res = await config.proxyFetch(url, { method: "GET" });
387
+ if (!res.ok) {
388
+ const text = await res.text().catch(() => res.statusText);
389
+ throw new Error(`Google Drive ${url} failed: HTTP ${res.status} ${text}`);
390
+ }
391
+ return await res.json();
392
+ }
393
+
394
+ // ../connectors/src/connectors/google-drive/setup-flow.ts
395
+ var MY_DRIVE = "__MY_DRIVE__";
396
+ var ALL_ITEMS = "__ALL_ITEMS__";
397
+ var GOOGLE_DRIVE_SETUP_MAX_ITEMS = 25;
398
+ var PAGE_SIZE = 50;
399
+ var FOLDER_MIME = "application/vnd.google-apps.folder";
400
+ async function listSharedDrives(config) {
401
+ const url = `https://www.googleapis.com/drive/v3/drives?pageSize=100&fields=drives(id,name)`;
402
+ try {
403
+ const data = await googleApiFetch(config, url);
404
+ return data.drives ?? [];
405
+ } catch {
406
+ return [];
407
+ }
408
+ }
409
+ function listItemsUrl(driveId) {
410
+ const params = new URLSearchParams({
411
+ pageSize: String(PAGE_SIZE),
412
+ fields: "files(id,name,mimeType,modifiedTime)",
413
+ orderBy: "modifiedTime desc"
414
+ });
415
+ if (driveId) {
416
+ params.set("corpora", "drive");
417
+ params.set("driveId", driveId);
418
+ params.set("includeItemsFromAllDrives", "true");
419
+ params.set("supportsAllDrives", "true");
420
+ params.set("q", `'${driveId}' in parents and trashed=false`);
421
+ } else {
422
+ params.set("q", `'root' in parents and trashed=false`);
423
+ }
424
+ return `https://www.googleapis.com/drive/v3/files?${params.toString()}`;
425
+ }
426
+ async function listItems(config, driveId) {
427
+ const data = await googleApiFetch(
428
+ config,
429
+ listItemsUrl(driveId)
430
+ );
431
+ return data.files ?? [];
432
+ }
433
+ var googleDriveSetupFlow = {
434
+ initialState: () => ({}),
435
+ steps: [
436
+ {
437
+ slug: "drive",
438
+ type: "select",
439
+ question: {
440
+ ja: "\u5BFE\u8C61\u306E\u30C9\u30E9\u30A4\u30D6\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
441
+ en: "Select the drive to use"
442
+ },
443
+ async fetchOptions(_state, rt) {
444
+ const shared = await listSharedDrives(rt.config);
445
+ const myDriveLabel = rt.language === "ja" ? "\u30DE\u30A4\u30C9\u30E9\u30A4\u30D6" : "My Drive";
446
+ return [
447
+ { value: MY_DRIVE, label: myDriveLabel },
448
+ ...shared.filter((d) => d.id).map((d) => ({ value: d.id, label: d.name ?? d.id }))
449
+ ];
450
+ },
451
+ applyAnswer: (state, answer) => ({ ...state, drive: answer[0] })
452
+ },
453
+ {
454
+ slug: "items",
455
+ type: "multiSelect",
456
+ question: {
457
+ ja: "\u5BFE\u8C61\u306E\u30D5\u30A9\u30EB\u30C0\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
458
+ en: "Select target folders or files (multi-select allowed)"
459
+ },
460
+ async fetchOptions(state, rt) {
461
+ if (!state.drive) return [];
462
+ const driveId = state.drive === MY_DRIVE ? null : state.drive;
463
+ const files = await listItems(rt.config, driveId);
464
+ const fileOptions = files.map((f) => {
465
+ const isFolder = f.mimeType === FOLDER_MIME;
466
+ const prefix = isFolder ? "[folder] " : "";
467
+ return { value: f.id, label: `${prefix}${f.name}` };
468
+ });
469
+ return [
470
+ {
471
+ value: ALL_ITEMS,
472
+ label: rt.language === "ja" ? "\u3053\u306E\u30C9\u30E9\u30A4\u30D6\u306E\u3059\u3079\u3066\u306E\u30A2\u30A4\u30C6\u30E0" : "All items in this drive"
473
+ },
474
+ ...fileOptions
475
+ ];
476
+ },
477
+ applyAnswer: (state, answer) => ({ ...state, items: answer })
478
+ }
479
+ ],
480
+ async finalize(state, rt) {
481
+ if (!state.drive || !state.items) {
482
+ throw new Error("Google Drive setup: incomplete state on finalize");
483
+ }
484
+ const driveId = state.drive === MY_DRIVE ? null : state.drive;
485
+ const allFiles = await listItems(rt.config, driveId);
486
+ const filesById = new Map(allFiles.map((f) => [f.id, f]));
487
+ const targetIds = await resolveSetupSelection({
488
+ selected: state.items,
489
+ allSentinel: ALL_ITEMS,
490
+ fetchAll: async () => allFiles.map((f) => f.id),
491
+ limit: GOOGLE_DRIVE_SETUP_MAX_ITEMS
492
+ });
493
+ const driveLabel = state.drive === MY_DRIVE ? rt.language === "ja" ? "\u30DE\u30A4\u30C9\u30E9\u30A4\u30D6" : "My Drive" : state.drive;
494
+ const sections = [
495
+ "## Google Drive",
496
+ "",
497
+ `### Drive: ${driveLabel}`,
498
+ ""
499
+ ];
500
+ if (targetIds.length === 0) {
501
+ sections.push(
502
+ rt.language === "ja" ? "- \u9078\u629E\u3055\u308C\u305F\u30A2\u30A4\u30C6\u30E0\u306F\u3042\u308A\u307E\u305B\u3093\u3002" : "- No items selected."
503
+ );
504
+ return sections.join("\n");
505
+ }
506
+ sections.push("| Name | Type | Modified |");
507
+ sections.push("|------|------|----------|");
508
+ for (const id of targetIds) {
509
+ const f = filesById.get(id);
510
+ if (!f) {
511
+ sections.push(`| ${id} | (unknown) | - |`);
512
+ continue;
513
+ }
514
+ const isFolder = f.mimeType === FOLDER_MIME;
515
+ const typeLabel = isFolder ? "folder" : f.mimeType ?? "file";
516
+ sections.push(
517
+ `| ${f.name} | ${typeLabel} | ${f.modifiedTime ?? "-"} |`
518
+ );
519
+ }
520
+ sections.push("");
521
+ return sections.join("\n");
522
+ }
523
+ };
524
+
315
525
  // ../connectors/src/connectors/google-drive/parameters.ts
316
526
  var parameters = {};
317
527
 
@@ -439,6 +649,7 @@ var tools = { request: requestTool };
439
649
  var googleDriveConnector = new ConnectorPlugin({
440
650
  slug: "google-drive",
441
651
  authType: AUTH_TYPES.OAUTH,
652
+ skipConnectionCheckOnCreate: true,
442
653
  name: "Google Drive",
443
654
  description: "Connect to Google Drive for file management, sharing, and collaboration using OAuth.",
444
655
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4GJX5yQTogUgar1buWxXbv/4b43a65353319c508111489f834d22c4/google_drive.png",
@@ -730,6 +941,7 @@ await drive.updateFile("fileId123", {}, "newFolderId", "oldFolderId");
730
941
  \`\`\``
731
942
  },
732
943
  tools,
944
+ setup: (params, ctx, config) => runSetupFlow(googleDriveSetupFlow, params, ctx, config),
733
945
  async checkConnection(_params, config) {
734
946
  const { proxyFetch } = config;
735
947
  const url = "https://www.googleapis.com/drive/v3/about?fields=user";
@@ -778,6 +990,7 @@ function resolveEnvVarOptional(entry, key) {
778
990
  import { getContext } from "hono/context-storage";
779
991
  import { getCookie } from "hono/cookie";
780
992
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
993
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
781
994
  function normalizeHeaders(input) {
782
995
  const out = {};
783
996
  if (!input) return out;
@@ -786,6 +999,11 @@ function normalizeHeaders(input) {
786
999
  });
787
1000
  return out;
788
1001
  }
1002
+ function extractInputUrl(input) {
1003
+ if (typeof input === "string") return input;
1004
+ if (input instanceof URL) return input.href;
1005
+ return input.url;
1006
+ }
789
1007
  function createSandboxProxyFetch(connectionId) {
790
1008
  return async (input, init) => {
791
1009
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -795,10 +1013,17 @@ function createSandboxProxyFetch(connectionId) {
795
1013
  "Connection proxy is not configured. Please check your deployment settings."
796
1014
  );
797
1015
  }
798
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1016
+ const originalUrl = extractInputUrl(input);
1017
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
1018
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
1019
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
1020
+ return fetch(sessionUrl, {
1021
+ method: "POST",
1022
+ headers: { Authorization: `Bearer ${token}` }
1023
+ });
1024
+ }
799
1025
  const originalMethod = init?.method ?? "GET";
800
1026
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
801
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
802
1027
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
803
1028
  return fetch(proxyUrl, {
804
1029
  method: "POST",
@@ -824,10 +1049,9 @@ function createDeployedAppProxyFetch(connectionId) {
824
1049
  }
825
1050
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
826
1051
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
1052
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
827
1053
  return async (input, init) => {
828
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
829
- const originalMethod = init?.method ?? "GET";
830
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
1054
+ const originalUrl = extractInputUrl(input);
831
1055
  const c = getContext();
832
1056
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
833
1057
  if (!appSession) {
@@ -835,6 +1059,14 @@ function createDeployedAppProxyFetch(connectionId) {
835
1059
  "No authentication method available for connection proxy."
836
1060
  );
837
1061
  }
1062
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
1063
+ return fetch(sessionUrl, {
1064
+ method: "POST",
1065
+ headers: { Authorization: `Bearer ${appSession}` }
1066
+ });
1067
+ }
1068
+ const originalMethod = init?.method ?? "GET";
1069
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
838
1070
  return fetch(proxyUrl, {
839
1071
  method: "POST",
840
1072
  headers: {