@squadbase/vite-server 0.1.12-dev.93b8799 → 0.1.17-dev.24af54e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/cli/index.js +12128 -934
  2. package/dist/connectors/airtable-oauth.js +248 -46
  3. package/dist/connectors/airtable.js +285 -51
  4. package/dist/connectors/amplitude.js +288 -47
  5. package/dist/connectors/anthropic.js +126 -47
  6. package/dist/connectors/asana.js +293 -49
  7. package/dist/connectors/attio.js +268 -49
  8. package/dist/connectors/aws-billing.js +253 -46
  9. package/dist/connectors/azure-sql.js +387 -102
  10. package/dist/connectors/backlog-api-key.js +283 -47
  11. package/dist/connectors/clickup.js +304 -49
  12. package/dist/connectors/cosmosdb.js +271 -50
  13. package/dist/connectors/customerio.js +285 -47
  14. package/dist/connectors/dbt.js +306 -47
  15. package/dist/connectors/freshdesk.js +308 -53
  16. package/dist/connectors/freshsales.js +299 -52
  17. package/dist/connectors/freshservice.js +327 -53
  18. package/dist/connectors/gamma.js +293 -52
  19. package/dist/connectors/gemini.js +125 -47
  20. package/dist/connectors/github.js +352 -49
  21. package/dist/connectors/gmail-oauth.js +170 -7
  22. package/dist/connectors/gmail.js +316 -47
  23. package/dist/connectors/google-ads.js +254 -46
  24. package/dist/connectors/google-analytics-oauth.js +276 -46
  25. package/dist/connectors/google-analytics.js +378 -49
  26. package/dist/connectors/google-audit-log.js +404 -47
  27. package/dist/connectors/google-calendar-oauth.js +225 -46
  28. package/dist/connectors/google-calendar.js +325 -47
  29. package/dist/connectors/google-docs.js +186 -6
  30. package/dist/connectors/google-drive.js +228 -5
  31. package/dist/connectors/google-search-console-oauth.js +222 -46
  32. package/dist/connectors/google-sheets.js +238 -47
  33. package/dist/connectors/google-slides.js +171 -6
  34. package/dist/connectors/grafana.js +298 -49
  35. package/dist/connectors/hubspot-oauth.js +174 -5
  36. package/dist/connectors/hubspot.js +272 -49
  37. package/dist/connectors/influxdb.js +382 -51
  38. package/dist/connectors/intercom-oauth.js +176 -5
  39. package/dist/connectors/intercom.js +268 -49
  40. package/dist/connectors/jdbc.js +728 -110
  41. package/dist/connectors/jira-api-key.js +292 -47
  42. package/dist/connectors/kintone-api-token.js +247 -47
  43. package/dist/connectors/kintone.js +294 -47
  44. package/dist/connectors/linear.js +296 -49
  45. package/dist/connectors/linkedin-ads.js +234 -50
  46. package/dist/connectors/mailchimp-oauth.js +234 -46
  47. package/dist/connectors/mailchimp.js +286 -49
  48. package/dist/connectors/meta-ads-oauth.js +239 -48
  49. package/dist/connectors/meta-ads.js +251 -50
  50. package/dist/connectors/mixpanel.js +304 -47
  51. package/dist/connectors/monday.js +326 -49
  52. package/dist/connectors/mongodb.js +285 -57
  53. package/dist/connectors/notion-oauth.js +197 -5
  54. package/dist/connectors/notion.js +289 -51
  55. package/dist/connectors/openai.js +125 -47
  56. package/dist/connectors/oracle.js +405 -103
  57. package/dist/connectors/outlook-oauth.js +170 -5
  58. package/dist/connectors/powerbi-oauth.js +217 -5
  59. package/dist/connectors/salesforce.js +350 -49
  60. package/dist/connectors/semrush.js +280 -49
  61. package/dist/connectors/sentry.js +255 -50
  62. package/dist/connectors/shopify-oauth.js +153 -5
  63. package/dist/connectors/shopify.js +323 -47
  64. package/dist/connectors/sqlserver.js +381 -102
  65. package/dist/connectors/stripe-api-key.js +235 -46
  66. package/dist/connectors/stripe-oauth.js +168 -5
  67. package/dist/connectors/supabase.js +269 -48
  68. package/dist/connectors/tableau.js +337 -206
  69. package/dist/connectors/tiktok-ads.js +245 -48
  70. package/dist/connectors/wix-store.js +286 -49
  71. package/dist/connectors/zendesk-oauth.js +205 -5
  72. package/dist/connectors/zendesk.js +324 -47
  73. package/dist/index.d.ts +149 -1
  74. package/dist/index.js +18297 -6886
  75. package/dist/main.js +12785 -1382
  76. package/dist/vite-plugin.js +12140 -936
  77. package/package.json +1 -1
@@ -121,6 +121,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
121
121
  * `runSetupFlow` from `setup-flow.ts`.
122
122
  */
123
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;
124
138
  constructor(config) {
125
139
  this.slug = config.slug;
126
140
  this.authType = config.authType;
@@ -138,6 +152,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
138
152
  this.query = config.query;
139
153
  this.checkConnection = config.checkConnection;
140
154
  this.setup = config.setup;
155
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
141
156
  }
142
157
  get connectorKey() {
143
158
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -202,6 +217,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
202
217
  }
203
218
  };
204
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
+
205
265
  // ../connectors/src/auth-types.ts
206
266
  var AUTH_TYPES = {
207
267
  OAUTH: "oauth",
@@ -232,6 +292,104 @@ var googleDocsOnboarding = new ConnectorOnboarding({
232
292
  }
233
293
  });
234
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
+
235
393
  // ../connectors/src/connectors/google-docs/parameters.ts
236
394
  var parameters = {};
237
395
 
@@ -364,6 +522,7 @@ var tools = { request: requestTool };
364
522
  var googleDocsConnector = new ConnectorPlugin({
365
523
  slug: "google-docs",
366
524
  authType: AUTH_TYPES.OAUTH,
525
+ skipConnectionCheckOnCreate: true,
367
526
  name: "Google Docs",
368
527
  description: "Connect to Google Docs for document data access and creation using OAuth.",
369
528
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6vvcGJisvXjOumeTvswjzf/e9bb39e453cc0b71a20f26019b23b0d2/google_docs.png",
@@ -519,7 +678,8 @@ await docs.batchUpdate(documentId, [
519
678
  ]);
520
679
  \`\`\``
521
680
  },
522
- tools
681
+ tools,
682
+ setup: (params, ctx, config) => runSetupFlow(googleDocsSetupFlow, params, ctx, config)
523
683
  });
524
684
 
525
685
  // src/connectors/create-connector-sdk.ts
@@ -548,6 +708,7 @@ function resolveEnvVarOptional(entry, key) {
548
708
  import { getContext } from "hono/context-storage";
549
709
  import { getCookie } from "hono/cookie";
550
710
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
711
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
551
712
  function normalizeHeaders(input) {
552
713
  const out = {};
553
714
  if (!input) return out;
@@ -556,6 +717,11 @@ function normalizeHeaders(input) {
556
717
  });
557
718
  return out;
558
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
+ }
559
725
  function createSandboxProxyFetch(connectionId) {
560
726
  return async (input, init) => {
561
727
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -565,10 +731,17 @@ function createSandboxProxyFetch(connectionId) {
565
731
  "Connection proxy is not configured. Please check your deployment settings."
566
732
  );
567
733
  }
568
- 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
+ }
569
743
  const originalMethod = init?.method ?? "GET";
570
744
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
571
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
572
745
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
573
746
  return fetch(proxyUrl, {
574
747
  method: "POST",
@@ -594,10 +767,9 @@ function createDeployedAppProxyFetch(connectionId) {
594
767
  }
595
768
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
596
769
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
770
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
597
771
  return async (input, init) => {
598
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
599
- const originalMethod = init?.method ?? "GET";
600
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
772
+ const originalUrl = extractInputUrl(input);
601
773
  const c = getContext();
602
774
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
603
775
  if (!appSession) {
@@ -605,6 +777,14 @@ function createDeployedAppProxyFetch(connectionId) {
605
777
  "No authentication method available for connection proxy."
606
778
  );
607
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;
608
788
  return fetch(proxyUrl, {
609
789
  method: "POST",
610
790
  headers: {
@@ -210,6 +210,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
210
210
  * `runSetupFlow` from `setup-flow.ts`.
211
211
  */
212
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;
213
227
  constructor(config) {
214
228
  this.slug = config.slug;
215
229
  this.authType = config.authType;
@@ -227,6 +241,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
227
241
  this.query = config.query;
228
242
  this.checkConnection = config.checkConnection;
229
243
  this.setup = config.setup;
244
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
230
245
  }
231
246
  get connectorKey() {
232
247
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -291,6 +306,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
291
306
  }
292
307
  };
293
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
+
294
354
  // ../connectors/src/auth-types.ts
295
355
  var AUTH_TYPES = {
296
356
  OAUTH: "oauth",
@@ -321,6 +381,147 @@ var googleDriveOnboarding = new ConnectorOnboarding({
321
381
  }
322
382
  });
323
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
+
324
525
  // ../connectors/src/connectors/google-drive/parameters.ts
325
526
  var parameters = {};
326
527
 
@@ -448,6 +649,7 @@ var tools = { request: requestTool };
448
649
  var googleDriveConnector = new ConnectorPlugin({
449
650
  slug: "google-drive",
450
651
  authType: AUTH_TYPES.OAUTH,
652
+ skipConnectionCheckOnCreate: true,
451
653
  name: "Google Drive",
452
654
  description: "Connect to Google Drive for file management, sharing, and collaboration using OAuth.",
453
655
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4GJX5yQTogUgar1buWxXbv/4b43a65353319c508111489f834d22c4/google_drive.png",
@@ -739,6 +941,7 @@ await drive.updateFile("fileId123", {}, "newFolderId", "oldFolderId");
739
941
  \`\`\``
740
942
  },
741
943
  tools,
944
+ setup: (params, ctx, config) => runSetupFlow(googleDriveSetupFlow, params, ctx, config),
742
945
  async checkConnection(_params, config) {
743
946
  const { proxyFetch } = config;
744
947
  const url = "https://www.googleapis.com/drive/v3/about?fields=user";
@@ -787,6 +990,7 @@ function resolveEnvVarOptional(entry, key) {
787
990
  import { getContext } from "hono/context-storage";
788
991
  import { getCookie } from "hono/cookie";
789
992
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
993
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
790
994
  function normalizeHeaders(input) {
791
995
  const out = {};
792
996
  if (!input) return out;
@@ -795,6 +999,11 @@ function normalizeHeaders(input) {
795
999
  });
796
1000
  return out;
797
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
+ }
798
1007
  function createSandboxProxyFetch(connectionId) {
799
1008
  return async (input, init) => {
800
1009
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -804,10 +1013,17 @@ function createSandboxProxyFetch(connectionId) {
804
1013
  "Connection proxy is not configured. Please check your deployment settings."
805
1014
  );
806
1015
  }
807
- 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
+ }
808
1025
  const originalMethod = init?.method ?? "GET";
809
1026
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
810
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
811
1027
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
812
1028
  return fetch(proxyUrl, {
813
1029
  method: "POST",
@@ -833,10 +1049,9 @@ function createDeployedAppProxyFetch(connectionId) {
833
1049
  }
834
1050
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
835
1051
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
1052
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
836
1053
  return async (input, init) => {
837
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
838
- const originalMethod = init?.method ?? "GET";
839
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
1054
+ const originalUrl = extractInputUrl(input);
840
1055
  const c = getContext();
841
1056
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
842
1057
  if (!appSession) {
@@ -844,6 +1059,14 @@ function createDeployedAppProxyFetch(connectionId) {
844
1059
  "No authentication method available for connection proxy."
845
1060
  );
846
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;
847
1070
  return fetch(proxyUrl, {
848
1071
  method: "POST",
849
1072
  headers: {