@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
@@ -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/sentry/parameters.ts
57
+ init_parameter_definition();
46
58
  var parameters = {
47
59
  organizationSlug: new ParameterDefinition({
48
60
  slug: "organization-slug",
@@ -94,7 +106,7 @@ function createClient(params) {
94
106
  const url = `${BASE_URL}${resolved.startsWith("/") ? "" : "/"}${resolved}`;
95
107
  return authenticatedFetch(url, init);
96
108
  }
97
- async function listProjects() {
109
+ async function listProjects2() {
98
110
  const url = `${BASE_URL}/organizations/${organizationSlug}/projects/`;
99
111
  const response = await authenticatedFetch(url);
100
112
  if (!response.ok) {
@@ -160,7 +172,7 @@ function createClient(params) {
160
172
  }
161
173
  return {
162
174
  request,
163
- listProjects,
175
+ listProjects: listProjects2,
164
176
  listIssues,
165
177
  getIssue,
166
178
  listIssueEvents,
@@ -235,6 +247,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
235
247
  * `runSetupFlow` from `setup-flow.ts`.
236
248
  */
237
249
  setup;
250
+ /**
251
+ * Opt-out of the default "verify before save" behavior on connection
252
+ * creation. The backend invokes `checkConnection` synchronously while
253
+ * creating the connection and aborts (no row inserted) if it fails — this
254
+ * flag disables that for connectors where the check cannot succeed pre-save:
255
+ *
256
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
257
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
258
+ * connectionId, which doesn't exist until the row is saved
259
+ *
260
+ * Exceptions are the explicit position; new credential-input connectors get
261
+ * the default verify-on-create behavior without opt-in.
262
+ */
263
+ skipConnectionCheckOnCreate;
238
264
  constructor(config) {
239
265
  this.slug = config.slug;
240
266
  this.authType = config.authType;
@@ -252,6 +278,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
252
278
  this.query = config.query;
253
279
  this.checkConnection = config.checkConnection;
254
280
  this.setup = config.setup;
281
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
255
282
  }
256
283
  get connectorKey() {
257
284
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -316,6 +343,51 @@ var ConnectorPlugin = class _ConnectorPlugin {
316
343
  }
317
344
  };
318
345
 
346
+ // ../connectors/src/setup-flow.ts
347
+ async function runSetupFlow(flow, params, ctx, config) {
348
+ const runtime = {
349
+ params,
350
+ language: ctx.language,
351
+ config
352
+ };
353
+ let state = flow.initialState();
354
+ let answerIdx = 0;
355
+ for (const step of flow.steps) {
356
+ const ans = ctx.answers[answerIdx];
357
+ if (ans && ans.questionSlug === step.slug) {
358
+ state = step.applyAnswer(state, ans.answer);
359
+ answerIdx += 1;
360
+ continue;
361
+ }
362
+ if (step.type === "text") {
363
+ return {
364
+ type: "nextQuestion",
365
+ questionSlug: step.slug,
366
+ question: step.question[ctx.language],
367
+ questionType: "text"
368
+ };
369
+ }
370
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
371
+ if (options.length === 0) {
372
+ continue;
373
+ }
374
+ return {
375
+ type: "nextQuestion",
376
+ questionSlug: step.slug,
377
+ question: step.question[ctx.language],
378
+ questionType: step.type,
379
+ options
380
+ };
381
+ }
382
+ const dataInvestigationResult = await flow.finalize(state, runtime);
383
+ return { type: "fulfilled", dataInvestigationResult };
384
+ }
385
+ async function resolveSetupSelection(params) {
386
+ const { selected, allSentinel, fetchAll, limit } = params;
387
+ const resolved = selected.includes(allSentinel) ? await fetchAll() : selected.filter((v) => v !== allSentinel);
388
+ return resolved.slice(0, limit);
389
+ }
390
+
319
391
  // ../connectors/src/auth-types.ts
320
392
  var AUTH_TYPES = {
321
393
  OAUTH: "oauth",
@@ -338,9 +410,121 @@ var sentryOnboarding = new ConnectorOnboarding({
338
410
  }
339
411
  });
340
412
 
413
+ // ../connectors/src/connectors/sentry/utils.ts
414
+ var BASE_URL2 = "https://sentry.io/api/0";
415
+ async function apiFetch(params, path2, init) {
416
+ const authToken = params[parameters.authToken.slug];
417
+ if (!authToken) {
418
+ throw new Error("sentry: missing required parameter: auth-token");
419
+ }
420
+ const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
421
+ const headers = new Headers(init?.headers);
422
+ headers.set("Authorization", `Bearer ${authToken}`);
423
+ if (!headers.has("Accept")) headers.set("Accept", "application/json");
424
+ return fetch(url, { ...init, headers });
425
+ }
426
+
427
+ // ../connectors/src/connectors/sentry/setup-flow.ts
428
+ var ALL_PROJECTS = "__ALL_PROJECTS__";
429
+ var SENTRY_SETUP_MAX_PROJECTS = 20;
430
+ async function listOrganizations(params) {
431
+ const res = await apiFetch(params, "/organizations/");
432
+ if (!res.ok) {
433
+ const body = await res.text().catch(() => res.statusText);
434
+ throw new Error(`sentry: listOrganizations failed (${res.status}): ${body}`);
435
+ }
436
+ const data = await res.json();
437
+ return data ?? [];
438
+ }
439
+ async function listProjects(params, orgSlug) {
440
+ const res = await apiFetch(params, `/organizations/${orgSlug}/projects/`);
441
+ if (!res.ok) {
442
+ const body = await res.text().catch(() => res.statusText);
443
+ throw new Error(`sentry: listProjects failed (${res.status}): ${body}`);
444
+ }
445
+ const data = await res.json();
446
+ return data ?? [];
447
+ }
448
+ var sentrySetupFlow = {
449
+ initialState: () => ({}),
450
+ steps: [
451
+ {
452
+ slug: "organization",
453
+ type: "select",
454
+ question: {
455
+ ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u4F7F\u3046\u7D44\u7E54\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
456
+ en: "Select the organization to use for setup"
457
+ },
458
+ async fetchOptions(_state, rt) {
459
+ const orgs = await listOrganizations(rt.params);
460
+ return orgs.filter((o) => o.slug).map((o) => ({ value: o.slug, label: o.name || o.slug }));
461
+ },
462
+ applyAnswer: (state, answer) => ({ ...state, organization: answer[0] })
463
+ },
464
+ {
465
+ slug: "projects",
466
+ type: "multiSelect",
467
+ question: {
468
+ ja: "\u5BFE\u8C61\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
469
+ en: "Select target projects (multi-select allowed)"
470
+ },
471
+ async fetchOptions(state, rt) {
472
+ if (!state.organization) return [];
473
+ const projects = await listProjects(rt.params, state.organization);
474
+ const opts = projects.filter((p) => p.slug).map((p) => ({ value: p.slug, label: p.name || p.slug }));
475
+ if (opts.length === 0) return [];
476
+ return [
477
+ {
478
+ value: ALL_PROJECTS,
479
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8" : "All projects"
480
+ },
481
+ ...opts
482
+ ];
483
+ },
484
+ applyAnswer: (state, answer) => ({ ...state, projects: answer })
485
+ }
486
+ ],
487
+ async finalize(state, rt) {
488
+ if (!state.organization || !state.projects) {
489
+ throw new Error("Sentry setup: incomplete state on finalize");
490
+ }
491
+ const orgSlug = state.organization;
492
+ const projects = await listProjects(rt.params, orgSlug);
493
+ const bySlug = new Map(projects.map((p) => [p.slug, p]));
494
+ const targetSlugs = await resolveSetupSelection({
495
+ selected: state.projects,
496
+ allSentinel: ALL_PROJECTS,
497
+ fetchAll: async () => projects.map((p) => p.slug).filter((s) => s),
498
+ limit: SENTRY_SETUP_MAX_PROJECTS
499
+ });
500
+ const sections = [
501
+ "## Sentry",
502
+ "",
503
+ `### Organization: ${orgSlug}`,
504
+ ""
505
+ ];
506
+ for (const slug of targetSlugs) {
507
+ const project = bySlug.get(slug);
508
+ if (!project) {
509
+ sections.push(`#### Project: ${slug}`, "", "_Not found._", "");
510
+ continue;
511
+ }
512
+ sections.push(`#### Project: ${project.name || project.slug}`, "");
513
+ sections.push("| Field | Value |");
514
+ sections.push("|-------|-------|");
515
+ sections.push(`| Slug | ${project.slug} |`);
516
+ sections.push(`| Platform | ${project.platform ?? "-"} |`);
517
+ sections.push(`| First event | ${project.firstEvent ?? "-"} |`);
518
+ sections.push(`| Created | ${project.dateCreated ?? "-"} |`);
519
+ sections.push("");
520
+ }
521
+ return sections.join("\n");
522
+ }
523
+ };
524
+
341
525
  // ../connectors/src/connectors/sentry/tools/request.ts
342
526
  import { z } from "zod";
343
- var BASE_URL2 = "https://sentry.io/api/0";
527
+ var BASE_URL3 = "https://sentry.io/api/0";
344
528
  var REQUEST_TIMEOUT_MS = 6e4;
345
529
  var inputSchema = z.object({
346
530
  toolUseIntent: z.string().optional().describe(
@@ -390,7 +574,7 @@ Authentication is handled automatically via Bearer token.
390
574
  /\{organizationSlug\}/g,
391
575
  organizationSlug
392
576
  );
393
- const url = `${BASE_URL2}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
577
+ const url = `${BASE_URL3}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
394
578
  const controller = new AbortController();
395
579
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
396
580
  try {
@@ -599,6 +783,7 @@ await sentry.updateIssue("12345", { status: "resolved" });
599
783
  \`\`\``
600
784
  },
601
785
  tools,
786
+ setup: (params, ctx, config) => runSetupFlow(sentrySetupFlow, params, ctx, config),
602
787
  async checkConnection(params) {
603
788
  const authToken = params[parameters.authToken.slug];
604
789
  const organizationSlug = params[parameters.organizationSlug.slug];
@@ -660,6 +845,7 @@ function resolveEnvVarOptional(entry, key) {
660
845
  import { getContext } from "hono/context-storage";
661
846
  import { getCookie } from "hono/cookie";
662
847
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
848
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
663
849
  function normalizeHeaders(input) {
664
850
  const out = {};
665
851
  if (!input) return out;
@@ -668,6 +854,11 @@ function normalizeHeaders(input) {
668
854
  });
669
855
  return out;
670
856
  }
857
+ function extractInputUrl(input) {
858
+ if (typeof input === "string") return input;
859
+ if (input instanceof URL) return input.href;
860
+ return input.url;
861
+ }
671
862
  function createSandboxProxyFetch(connectionId) {
672
863
  return async (input, init) => {
673
864
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -677,10 +868,17 @@ function createSandboxProxyFetch(connectionId) {
677
868
  "Connection proxy is not configured. Please check your deployment settings."
678
869
  );
679
870
  }
680
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
871
+ const originalUrl = extractInputUrl(input);
872
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
873
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
874
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
875
+ return fetch(sessionUrl, {
876
+ method: "POST",
877
+ headers: { Authorization: `Bearer ${token}` }
878
+ });
879
+ }
681
880
  const originalMethod = init?.method ?? "GET";
682
881
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
683
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
684
882
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
685
883
  return fetch(proxyUrl, {
686
884
  method: "POST",
@@ -706,10 +904,9 @@ function createDeployedAppProxyFetch(connectionId) {
706
904
  }
707
905
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
708
906
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
907
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
709
908
  return async (input, init) => {
710
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
711
- const originalMethod = init?.method ?? "GET";
712
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
909
+ const originalUrl = extractInputUrl(input);
713
910
  const c = getContext();
714
911
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
715
912
  if (!appSession) {
@@ -717,6 +914,14 @@ function createDeployedAppProxyFetch(connectionId) {
717
914
  "No authentication method available for connection proxy."
718
915
  );
719
916
  }
917
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
918
+ return fetch(sessionUrl, {
919
+ method: "POST",
920
+ headers: { Authorization: `Bearer ${appSession}` }
921
+ });
922
+ }
923
+ const originalMethod = init?.method ?? "GET";
924
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
720
925
  return fetch(proxyUrl, {
721
926
  method: "POST",
722
927
  headers: {
@@ -73,6 +73,20 @@ var ConnectorPlugin = class _ConnectorPlugin {
73
73
  * `runSetupFlow` from `setup-flow.ts`.
74
74
  */
75
75
  setup;
76
+ /**
77
+ * Opt-out of the default "verify before save" behavior on connection
78
+ * creation. The backend invokes `checkConnection` synchronously while
79
+ * creating the connection and aborts (no row inserted) if it fails — this
80
+ * flag disables that for connectors where the check cannot succeed pre-save:
81
+ *
82
+ * - `squadbase-db` populates `connection-url` only after Neon provisioning
83
+ * - OAuth connectors require an OAuth-aware proxyFetch keyed by the
84
+ * connectionId, which doesn't exist until the row is saved
85
+ *
86
+ * Exceptions are the explicit position; new credential-input connectors get
87
+ * the default verify-on-create behavior without opt-in.
88
+ */
89
+ skipConnectionCheckOnCreate;
76
90
  constructor(config) {
77
91
  this.slug = config.slug;
78
92
  this.authType = config.authType;
@@ -90,6 +104,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
90
104
  this.query = config.query;
91
105
  this.checkConnection = config.checkConnection;
92
106
  this.setup = config.setup;
107
+ this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
93
108
  }
94
109
  get connectorKey() {
95
110
  return _ConnectorPlugin.deriveKey(this.slug, this.authType);
@@ -154,6 +169,46 @@ var ConnectorPlugin = class _ConnectorPlugin {
154
169
  }
155
170
  };
156
171
 
172
+ // ../connectors/src/setup-flow.ts
173
+ async function runSetupFlow(flow, params, ctx, config) {
174
+ const runtime = {
175
+ params,
176
+ language: ctx.language,
177
+ config
178
+ };
179
+ let state = flow.initialState();
180
+ let answerIdx = 0;
181
+ for (const step of flow.steps) {
182
+ const ans = ctx.answers[answerIdx];
183
+ if (ans && ans.questionSlug === step.slug) {
184
+ state = step.applyAnswer(state, ans.answer);
185
+ answerIdx += 1;
186
+ continue;
187
+ }
188
+ if (step.type === "text") {
189
+ return {
190
+ type: "nextQuestion",
191
+ questionSlug: step.slug,
192
+ question: step.question[ctx.language],
193
+ questionType: "text"
194
+ };
195
+ }
196
+ const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
197
+ if (options.length === 0) {
198
+ continue;
199
+ }
200
+ return {
201
+ type: "nextQuestion",
202
+ questionSlug: step.slug,
203
+ question: step.question[ctx.language],
204
+ questionType: step.type,
205
+ options
206
+ };
207
+ }
208
+ const dataInvestigationResult = await flow.finalize(state, runtime);
209
+ return { type: "fulfilled", dataInvestigationResult };
210
+ }
211
+
157
212
  // ../connectors/src/auth-types.ts
158
213
  var AUTH_TYPES = {
159
214
  OAUTH: "oauth",
@@ -316,11 +371,83 @@ var shopifyOauthOnboarding = new ConnectorOnboarding({
316
371
  // ../connectors/src/connectors/shopify-oauth/parameters.ts
317
372
  var parameters = {};
318
373
 
374
+ // ../connectors/src/connectors/shopify-oauth/setup-flow.ts
375
+ var SHOPIFY_API_VERSION = "2024-10";
376
+ var SHOPIFY_OAUTH_SETUP_MAX_ENTITIES = 10;
377
+ var ENTITY_LABELS = {
378
+ products: { en: "Products", ja: "Products (\u5546\u54C1)" },
379
+ orders: { en: "Orders", ja: "Orders (\u6CE8\u6587)" },
380
+ customers: { en: "Customers", ja: "Customers (\u9867\u5BA2)" },
381
+ collections: { en: "Collections", ja: "Collections (\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3)" },
382
+ inventory: { en: "Inventory items", ja: "Inventory items (\u5728\u5EAB)" },
383
+ discounts: { en: "Discounts", ja: "Discounts (\u5272\u5F15)" }
384
+ };
385
+ var ENTITY_VALUES = [
386
+ "products",
387
+ "orders",
388
+ "customers",
389
+ "collections",
390
+ "inventory",
391
+ "discounts"
392
+ ];
393
+ var COUNT_PATHS = {
394
+ products: `/admin/api/${SHOPIFY_API_VERSION}/products/count.json`,
395
+ orders: `/admin/api/${SHOPIFY_API_VERSION}/orders/count.json?status=any`,
396
+ customers: `/admin/api/${SHOPIFY_API_VERSION}/customers/count.json`,
397
+ collections: `/admin/api/${SHOPIFY_API_VERSION}/custom_collections/count.json`,
398
+ inventory: null,
399
+ discounts: `/admin/api/${SHOPIFY_API_VERSION}/price_rules/count.json`
400
+ };
401
+ var shopifyOauthSetupFlow = {
402
+ initialState: () => ({}),
403
+ steps: [
404
+ {
405
+ slug: "entities",
406
+ type: "multiSelect",
407
+ question: {
408
+ ja: "\u5BFE\u8C61\u306E\u30A8\u30F3\u30C6\u30A3\u30C6\u30A3\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
409
+ en: "Select target entities (multi-select allowed)"
410
+ },
411
+ async fetchOptions(_state, rt) {
412
+ return ENTITY_VALUES.map((value) => ({
413
+ value,
414
+ label: ENTITY_LABELS[value][rt.language]
415
+ }));
416
+ },
417
+ applyAnswer: (state, answer) => ({ ...state, entities: answer })
418
+ }
419
+ ],
420
+ async finalize(state, rt) {
421
+ if (!state.entities) {
422
+ throw new Error("Shopify setup: incomplete state on finalize");
423
+ }
424
+ const selected = state.entities.filter(
425
+ (e) => ENTITY_VALUES.includes(e)
426
+ ).slice(0, SHOPIFY_OAUTH_SETUP_MAX_ENTITIES);
427
+ const sections = ["## Shopify", ""];
428
+ for (const entity of selected) {
429
+ const path2 = COUNT_PATHS[entity];
430
+ let count = "available";
431
+ if (path2) {
432
+ const res = await rt.config.proxyFetch(path2, { method: "GET" });
433
+ if (res.ok) {
434
+ const data = await res.json();
435
+ if (typeof data.count === "number") count = String(data.count);
436
+ }
437
+ }
438
+ sections.push(`### ${ENTITY_LABELS[entity].en}`, "");
439
+ sections.push(`Count: ${count}`, "");
440
+ }
441
+ return sections.join("\n");
442
+ }
443
+ };
444
+
319
445
  // ../connectors/src/connectors/shopify-oauth/index.ts
320
446
  var tools = { request: requestTool };
321
447
  var shopifyOauthConnector = new ConnectorPlugin({
322
448
  slug: "shopify",
323
449
  authType: AUTH_TYPES.OAUTH,
450
+ skipConnectionCheckOnCreate: true,
324
451
  name: "Shopify",
325
452
  description: "Connect to Shopify for e-commerce data including products, orders, and customers using OAuth.",
326
453
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/57KEjZCBskKgSxgKyU4Sm0/117d681a410f48dc36f97cdd9c0593c5/shopify-icon.svg",
@@ -433,6 +560,7 @@ const data = await res.json();
433
560
  \`\`\``
434
561
  },
435
562
  tools,
563
+ setup: (params, ctx, config) => runSetupFlow(shopifyOauthSetupFlow, params, ctx, config),
436
564
  async checkConnection(_params, config) {
437
565
  const { proxyFetch } = config;
438
566
  try {
@@ -482,6 +610,7 @@ function resolveEnvVarOptional(entry, key) {
482
610
  import { getContext } from "hono/context-storage";
483
611
  import { getCookie } from "hono/cookie";
484
612
  var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
613
+ var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
485
614
  function normalizeHeaders(input) {
486
615
  const out = {};
487
616
  if (!input) return out;
@@ -490,6 +619,11 @@ function normalizeHeaders(input) {
490
619
  });
491
620
  return out;
492
621
  }
622
+ function extractInputUrl(input) {
623
+ if (typeof input === "string") return input;
624
+ if (input instanceof URL) return input.href;
625
+ return input.url;
626
+ }
493
627
  function createSandboxProxyFetch(connectionId) {
494
628
  return async (input, init) => {
495
629
  const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
@@ -499,10 +633,17 @@ function createSandboxProxyFetch(connectionId) {
499
633
  "Connection proxy is not configured. Please check your deployment settings."
500
634
  );
501
635
  }
502
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
636
+ const originalUrl = extractInputUrl(input);
637
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
638
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
639
+ const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
640
+ return fetch(sessionUrl, {
641
+ method: "POST",
642
+ headers: { Authorization: `Bearer ${token}` }
643
+ });
644
+ }
503
645
  const originalMethod = init?.method ?? "GET";
504
646
  const originalBody = init?.body ? JSON.parse(init.body) : void 0;
505
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
506
647
  const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
507
648
  return fetch(proxyUrl, {
508
649
  method: "POST",
@@ -528,10 +669,9 @@ function createDeployedAppProxyFetch(connectionId) {
528
669
  }
529
670
  const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
530
671
  const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
672
+ const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
531
673
  return async (input, init) => {
532
- const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
533
- const originalMethod = init?.method ?? "GET";
534
- const originalBody = init?.body ? JSON.parse(init.body) : void 0;
674
+ const originalUrl = extractInputUrl(input);
535
675
  const c = getContext();
536
676
  const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
537
677
  if (!appSession) {
@@ -539,6 +679,14 @@ function createDeployedAppProxyFetch(connectionId) {
539
679
  "No authentication method available for connection proxy."
540
680
  );
541
681
  }
682
+ if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
683
+ return fetch(sessionUrl, {
684
+ method: "POST",
685
+ headers: { Authorization: `Bearer ${appSession}` }
686
+ });
687
+ }
688
+ const originalMethod = init?.method ?? "GET";
689
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
542
690
  return fetch(proxyUrl, {
543
691
  method: "POST",
544
692
  headers: {