@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,48 +1,60 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
1
6
  // ../connectors/src/parameter-definition.ts
2
- var ParameterDefinition = class {
3
- slug;
4
- name;
5
- description;
6
- envVarBaseKey;
7
- type;
8
- secret;
9
- required;
10
- constructor(config) {
11
- this.slug = config.slug;
12
- this.name = config.name;
13
- this.description = config.description;
14
- this.envVarBaseKey = config.envVarBaseKey;
15
- this.type = config.type;
16
- this.secret = config.secret;
17
- this.required = config.required;
18
- }
19
- /**
20
- * Get the parameter value from a ConnectorConnectionObject.
21
- */
22
- getValue(connection2) {
23
- const param = connection2.parameters.find(
24
- (p) => p.parameterSlug === this.slug
25
- );
26
- if (!param || param.value == null) {
27
- throw new Error(
28
- `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
29
- );
30
- }
31
- return param.value;
32
- }
33
- /**
34
- * Try to get the parameter value. Returns undefined if not found (for optional params).
35
- */
36
- tryGetValue(connection2) {
37
- const param = connection2.parameters.find(
38
- (p) => p.parameterSlug === this.slug
39
- );
40
- if (!param || param.value == null) return void 0;
41
- return param.value;
7
+ var ParameterDefinition;
8
+ var init_parameter_definition = __esm({
9
+ "../connectors/src/parameter-definition.ts"() {
10
+ "use strict";
11
+ ParameterDefinition = class {
12
+ slug;
13
+ name;
14
+ description;
15
+ envVarBaseKey;
16
+ type;
17
+ secret;
18
+ required;
19
+ constructor(config) {
20
+ this.slug = config.slug;
21
+ this.name = config.name;
22
+ this.description = config.description;
23
+ this.envVarBaseKey = config.envVarBaseKey;
24
+ this.type = config.type;
25
+ this.secret = config.secret;
26
+ this.required = config.required;
27
+ }
28
+ /**
29
+ * Get the parameter value from a ConnectorConnectionObject.
30
+ */
31
+ getValue(connection2) {
32
+ const param = connection2.parameters.find(
33
+ (p) => p.parameterSlug === this.slug
34
+ );
35
+ if (!param || param.value == null) {
36
+ throw new Error(
37
+ `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
38
+ );
39
+ }
40
+ return param.value;
41
+ }
42
+ /**
43
+ * Try to get the parameter value. Returns undefined if not found (for optional params).
44
+ */
45
+ tryGetValue(connection2) {
46
+ const param = connection2.parameters.find(
47
+ (p) => p.parameterSlug === this.slug
48
+ );
49
+ if (!param || param.value == null) return void 0;
50
+ return param.value;
51
+ }
52
+ };
42
53
  }
43
- };
54
+ });
44
55
 
45
56
  // ../connectors/src/connectors/notion/parameters.ts
57
+ init_parameter_definition();
46
58
  var parameters = {
47
59
  apiKey: new ParameterDefinition({
48
60
  slug: "api-key",
@@ -223,6 +235,28 @@ var ConnectorPlugin = class _ConnectorPlugin {
223
235
  tools;
224
236
  query;
225
237
  checkConnection;
238
+ /**
239
+ * SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
240
+ * implement this expose a step-by-step exploration flow (database/schema/
241
+ * table/etc. discovery) that the dashboard backend drives via the
242
+ * `/connections/:connectionId/setup` endpoint. Implement by delegating to
243
+ * `runSetupFlow` from `setup-flow.ts`.
244
+ */
245
+ setup;
246
+ /**
247
+ * Opt-out of the default "verify before save" behavior on connection
248
+ * creation. The backend invokes `checkConnection` synchronously while
249
+ * creating the connection and aborts (no row inserted) if it fails — this
250
+ * flag disables that for connectors where the check cannot succeed pre-save:
251
+ *
252
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
253
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
254
+ * connectionId, which doesn't exist until the row is saved
255
+ *
256
+ * Exceptions are the explicit position; new credential-input connectors get
257
+ * the default verify-on-create behavior without opt-in.
258
+ */
259
+ skipConnectionCheckOnCreate;
226
260
  constructor(config) {
227
261
  this.slug = config.slug;
228
262
  this.authType = config.authType;
@@ -239,6 +273,8 @@ var ConnectorPlugin = class _ConnectorPlugin {
239
273
  this.tools = config.tools;
240
274
  this.query = config.query;
241
275
  this.checkConnection = config.checkConnection;
276
+ this.setup = config.setup;
277
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
242
278
  }
243
279
  get connectorKey() {
244
280
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -303,6 +339,76 @@ var ConnectorPlugin = class _ConnectorPlugin {
303
339
  }
304
340
  };
305
341
 
342
+ // ../connectors/src/setup-flow.ts
343
+ async function runSetupFlow(flow, params, ctx, config) {
344
+ const runtime = {
345
+ params,
346
+ language: ctx.language,
347
+ config
348
+ };
349
+ let state = flow.initialState();
350
+ let answerIdx = 0;
351
+ const pendingParameterUpdates = [];
352
+ for (const step of flow.steps) {
353
+ const ans = ctx.answers[answerIdx];
354
+ if (ans && ans.questionSlug === step.slug) {
355
+ state = step.applyAnswer(state, ans.answer);
356
+ if (step.toParameterUpdates) {
357
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
358
+ }
359
+ answerIdx += 1;
360
+ continue;
361
+ }
362
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
363
+ if (step.type === "text") {
364
+ if (step.fetchOptions) {
365
+ const options2 = await step.fetchOptions(state, runtime);
366
+ if (options2.length === 0) {
367
+ continue;
368
+ }
369
+ }
370
+ return {
371
+ type: "nextQuestion",
372
+ questionSlug: step.slug,
373
+ question: step.question[ctx.language],
374
+ questionType: "text",
375
+ allowFreeText: resolvedAllowFreeText,
376
+ ...pendingParameterUpdates.length > 0 && {
377
+ parameterUpdates: pendingParameterUpdates
378
+ }
379
+ };
380
+ }
381
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
382
+ if (options.length === 0) {
383
+ continue;
384
+ }
385
+ return {
386
+ type: "nextQuestion",
387
+ questionSlug: step.slug,
388
+ question: step.question[ctx.language],
389
+ questionType: step.type,
390
+ options,
391
+ allowFreeText: resolvedAllowFreeText,
392
+ ...pendingParameterUpdates.length > 0 && {
393
+ parameterUpdates: pendingParameterUpdates
394
+ }
395
+ };
396
+ }
397
+ const dataInvestigationResult = await flow.finalize(state, runtime);
398
+ return {
399
+ type: "fulfilled",
400
+ dataInvestigationResult,
401
+ ...pendingParameterUpdates.length > 0 && {
402
+ parameterUpdates: pendingParameterUpdates
403
+ }
404
+ };
405
+ }
406
+ async function resolveSetupSelection(params) {
407
+ const { selected, allSentinel, fetchAll, limit } = params;
408
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
409
+ return resolved.slice(0, limit);
410
+ }
411
+
306
412
  // ../connectors/src/auth-types.ts
307
413
  var AUTH_TYPES = {
308
414
  OAUTH: "oauth",
@@ -327,10 +433,123 @@ var notionOnboarding = new ConnectorOnboarding({
327
433
  }
328
434
  });
329
435
 
330
- // ../connectors/src/connectors/notion/tools/request.ts
331
- import { z } from "zod";
436
+ // ../connectors/src/connectors/notion/utils.ts
332
437
  var BASE_URL2 = "https://api.notion.com/v1";
333
438
  var NOTION_VERSION2 = "2022-06-28";
439
+ async function apiFetch(params, path2, init) {
440
+ const apiKey = params[parameters.apiKey.slug];
441
+ if (!apiKey) {
442
+ throw new Error("notion: missing required parameter: api-key");
443
+ }
444
+ const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
445
+ const headers = new Headers(init?.headers);
446
+ headers.set("Authorization", `Bearer ${apiKey}`);
447
+ headers.set("Notion-Version", NOTION_VERSION2);
448
+ if (init?.body && !headers.has("Content-Type")) {
449
+ headers.set("Content-Type", "application/json");
450
+ }
451
+ return fetch(url, { ...init, headers });
452
+ }
453
+
454
+ // ../connectors/src/connectors/notion/setup-flow.ts
455
+ var ALL_DATABASES = "__ALL_DATABASES__";
456
+ var NOTION_SETUP_MAX_DATABASES = 20;
457
+ function databaseTitle(db) {
458
+ const parts = (db.title ?? []).map((t) => t.plain_text ?? "").filter((s) => s);
459
+ return parts.join("").trim() || "(Untitled)";
460
+ }
461
+ async function searchDatabases(params) {
462
+ const results = [];
463
+ let startCursor;
464
+ for (let i = 0; i < 20; i++) {
465
+ const body = {
466
+ filter: { property: "object", value: "database" },
467
+ page_size: 100
468
+ };
469
+ if (startCursor) body.start_cursor = startCursor;
470
+ const res = await apiFetch(params, "/search", {
471
+ method: "POST",
472
+ body: JSON.stringify(body)
473
+ });
474
+ if (!res.ok) {
475
+ const text = await res.text().catch(() => res.statusText);
476
+ throw new Error(`notion: search failed (${res.status}): ${text}`);
477
+ }
478
+ const data = await res.json();
479
+ for (const r of data.results ?? []) results.push(r);
480
+ if (!data.has_more || !data.next_cursor) break;
481
+ startCursor = data.next_cursor;
482
+ }
483
+ return results;
484
+ }
485
+ async function getDatabase(params, databaseId) {
486
+ const res = await apiFetch(params, `/databases/${databaseId}`);
487
+ if (!res.ok) {
488
+ const text = await res.text().catch(() => res.statusText);
489
+ throw new Error(
490
+ `notion: getDatabase ${databaseId} failed (${res.status}): ${text}`
491
+ );
492
+ }
493
+ return await res.json();
494
+ }
495
+ var notionSetupFlow = {
496
+ initialState: () => ({}),
497
+ steps: [
498
+ {
499
+ slug: "databases",
500
+ type: "multiSelect",
501
+ question: {
502
+ ja: "\u5BFE\u8C61\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
503
+ en: "Select target databases (multi-select allowed)"
504
+ },
505
+ async fetchOptions(_state, rt) {
506
+ const dbs = await searchDatabases(rt.params);
507
+ const dbOptions = dbs.filter((db) => db.id).map((db) => ({ value: db.id, label: databaseTitle(db) }));
508
+ return [
509
+ {
510
+ value: ALL_DATABASES,
511
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9" : "All databases"
512
+ },
513
+ ...dbOptions
514
+ ];
515
+ },
516
+ applyAnswer: (state, answer) => ({ ...state, databases: answer })
517
+ }
518
+ ],
519
+ async finalize(state, rt) {
520
+ if (!state.databases) {
521
+ throw new Error("Notion setup: incomplete state on finalize");
522
+ }
523
+ const targetIds = await resolveSetupSelection({
524
+ selected: state.databases,
525
+ allSentinel: ALL_DATABASES,
526
+ fetchAll: async () => {
527
+ const dbs = await searchDatabases(rt.params);
528
+ return dbs.map((db) => db.id).filter((id) => id);
529
+ },
530
+ limit: NOTION_SETUP_MAX_DATABASES
531
+ });
532
+ const sections = ["## Notion", ""];
533
+ for (const dbId of targetIds) {
534
+ const db = await getDatabase(rt.params, dbId);
535
+ const title = databaseTitle(db);
536
+ sections.push(`### Database: ${title}`, "", `- id: \`${db.id}\``, "");
537
+ sections.push("| Property | Type |");
538
+ sections.push("|----------|------|");
539
+ for (const [name, def] of Object.entries(db.properties ?? {})) {
540
+ const escapedName = name.replace(/\|/g, "\\|");
541
+ sections.push(`| ${escapedName} | ${def?.type ?? "-"} |`);
542
+ }
543
+ sections.push("");
544
+ }
545
+ return sections.join("\n");
546
+ }
547
+ };
548
+
549
+ // ../connectors/src/connectors/notion/tools/request.ts
550
+ import { z } from "zod";
551
+ var BASE_URL3 = "https://api.notion.com/v1";
552
+ var NOTION_VERSION3 = "2022-06-28";
334
553
  var REQUEST_TIMEOUT_MS = 6e4;
335
554
  var inputSchema = z.object({
336
555
  toolUseIntent: z.string().optional().describe(
@@ -377,7 +596,7 @@ Pagination uses cursor-based start_cursor and page_size (max 100).`,
377
596
  );
378
597
  try {
379
598
  const apiKey = parameters.apiKey.getValue(connection2);
380
- const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
599
+ const url = `${BASE_URL3}${path2.startsWith("/") ? "" : "/"}${path2}`;
381
600
  const controller = new AbortController();
382
601
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
383
602
  try {
@@ -385,7 +604,7 @@ Pagination uses cursor-based start_cursor and page_size (max 100).`,
385
604
  method,
386
605
  headers: {
387
606
  Authorization: `Bearer ${apiKey}`,
388
- "Notion-Version": NOTION_VERSION2,
607
+ "Notion-Version": NOTION_VERSION3,
389
608
  "Content-Type": "application/json"
390
609
  },
391
610
  body: body ? JSON.stringify(body) : void 0,
@@ -561,7 +780,40 @@ export default async function handler(c: Context) {
561
780
  - \u30D6\u30ED\u30C3\u30AF\u306E\u5B50\u306F\u6700\u521D\u306E\u30EC\u30D9\u30EB\u306E\u307F\u3067\u3059\u3002\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30B3\u30F3\u30C6\u30F3\u30C4\u306B\u306F\u518D\u5E30\u304C\u5FC5\u8981\u3067\u3059
562
781
  - 25\u4EF6\u4EE5\u4E0A\u306E\u30A2\u30A4\u30C6\u30E0\u3092\u6301\u3064\u30D7\u30ED\u30D1\u30C6\u30A3\uFF08people\u3001relation\u306A\u3069\uFF09\u306F\u5B8C\u5168\u306A\u30C7\u30FC\u30BF\u53D6\u5F97\u306B\u30D7\u30ED\u30D1\u30C6\u30A3\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u304C\u5FC5\u8981\u3067\u3059`
563
782
  },
564
- tools
783
+ tools,
784
+ setup: (params, ctx, config) => runSetupFlow(notionSetupFlow, params, ctx, config),
785
+ async checkConnection(params, _config) {
786
+ const apiKey = params[parameters.apiKey.slug];
787
+ if (!apiKey) {
788
+ return {
789
+ success: false,
790
+ error: `Missing required parameter: ${parameters.apiKey.slug}`
791
+ };
792
+ }
793
+ try {
794
+ const res = await fetch("https://api.notion.com/v1/users/me", {
795
+ method: "GET",
796
+ headers: {
797
+ Authorization: `Bearer ${apiKey}`,
798
+ "Notion-Version": "2022-06-28",
799
+ Accept: "application/json"
800
+ }
801
+ });
802
+ if (!res.ok) {
803
+ const errorText = await res.text().catch(() => res.statusText);
804
+ return {
805
+ success: false,
806
+ error: `Notion API failed: HTTP ${res.status} ${errorText}`
807
+ };
808
+ }
809
+ return { success: true };
810
+ } catch (error) {
811
+ return {
812
+ success: false,
813
+ error: error instanceof Error ? error.message : String(error)
814
+ };
815
+ }
816
+ }
565
817
  });
566
818
 
567
819
  // src/connectors/create-connector-sdk.ts
@@ -590,6 +842,7 @@ function resolveEnvVarOptional(entry, key) {
590
842
  import { getContext } from "hono/context-storage";
591
843
  import { getCookie } from "hono/cookie";
592
844
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
845
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
593
846
  function normalizeHeaders(input) {
594
847
  const out = {};
595
848
  if (!input) return out;
@@ -598,6 +851,11 @@ function normalizeHeaders(input) {
598
851
  });
599
852
  return out;
600
853
  }
854
+ function extractInputUrl(input) {
855
+ if (typeof input === "string") return input;
856
+ if (input instanceof URL) return input.href;
857
+ return input.url;
858
+ }
601
859
  function createSandboxProxyFetch(connectionId) {
602
860
  return async (input, init) => {
603
861
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -607,10 +865,17 @@ function createSandboxProxyFetch(connectionId) {
607
865
  "Connection proxy is not configured. Please check your deployment settings."
608
866
  );
609
867
  }
610
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
868
+ const originalUrl = extractInputUrl(input);
869
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
870
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
871
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
872
+ return fetch(sessionUrl, {
873
+ method: "POST",
874
+ headers: { Authorization: `Bearer ${token}` }
875
+ });
876
+ }
611
877
  const originalMethod = init?.method ?? "GET";
612
878
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
613
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
614
879
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
615
880
  return fetch(proxyUrl, {
616
881
  method: "POST",
@@ -636,10 +901,9 @@ function createDeployedAppProxyFetch(connectionId) {
636
901
  }
637
902
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
638
903
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
904
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
639
905
  return async (input, init) => {
640
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
641
- const originalMethod = init?.method ?? "GET";
642
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
906
+ const originalUrl = extractInputUrl(input);
643
907
  const c = getContext();
644
908
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
645
909
  if (!appSession) {
@@ -647,6 +911,14 @@ function createDeployedAppProxyFetch(connectionId) {
647
911
  "No authentication method available for connection proxy."
648
912
  );
649
913
  }
914
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
915
+ return fetch(sessionUrl, {
916
+ method: "POST",
917
+ headers: { Authorization: `Bearer ${appSession}` }
918
+ });
919
+ }
920
+ const originalMethod = init?.method ?? "GET";
921
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
650
922
  return fetch(proxyUrl, {
651
923
  method: "POST",
652
924
  headers: {