@squadbase/vite-server 0.1.17-dev.24af54e → 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 (73) hide show
  1. package/dist/cli/index.js +1681 -449
  2. package/dist/connectors/airtable-oauth.js +28 -3
  3. package/dist/connectors/airtable.js +28 -3
  4. package/dist/connectors/amplitude.js +28 -3
  5. package/dist/connectors/asana.js +28 -3
  6. package/dist/connectors/attio.js +28 -3
  7. package/dist/connectors/aws-billing.js +28 -3
  8. package/dist/connectors/azure-sql.js +31 -6
  9. package/dist/connectors/backlog-api-key.js +28 -3
  10. package/dist/connectors/clickup.js +28 -3
  11. package/dist/connectors/cosmosdb.js +28 -3
  12. package/dist/connectors/customerio.js +29 -4
  13. package/dist/connectors/dbt.js +28 -3
  14. package/dist/connectors/freshdesk.js +28 -3
  15. package/dist/connectors/freshsales.js +28 -3
  16. package/dist/connectors/freshservice.js +28 -3
  17. package/dist/connectors/gamma.js +30 -5
  18. package/dist/connectors/github.js +28 -3
  19. package/dist/connectors/gmail-oauth.js +28 -3
  20. package/dist/connectors/gmail.js +28 -3
  21. package/dist/connectors/google-ads.js +28 -3
  22. package/dist/connectors/google-analytics-oauth.js +28 -3
  23. package/dist/connectors/google-analytics.js +227 -105
  24. package/dist/connectors/google-audit-log.js +28 -3
  25. package/dist/connectors/google-calendar-oauth.js +28 -3
  26. package/dist/connectors/google-calendar.js +28 -3
  27. package/dist/connectors/google-docs.js +28 -3
  28. package/dist/connectors/google-drive.js +28 -3
  29. package/dist/connectors/google-search-console-oauth.js +28 -3
  30. package/dist/connectors/google-sheets.js +28 -3
  31. package/dist/connectors/google-slides.js +28 -3
  32. package/dist/connectors/grafana.js +28 -3
  33. package/dist/connectors/hubspot-oauth.js +28 -3
  34. package/dist/connectors/hubspot.js +28 -3
  35. package/dist/connectors/influxdb.js +28 -3
  36. package/dist/connectors/intercom-oauth.js +28 -3
  37. package/dist/connectors/intercom.js +28 -3
  38. package/dist/connectors/jdbc.js +28 -3
  39. package/dist/connectors/jira-api-key.js +28 -3
  40. package/dist/connectors/kintone-api-token.js +28 -3
  41. package/dist/connectors/kintone.js +28 -3
  42. package/dist/connectors/linear.js +28 -3
  43. package/dist/connectors/linkedin-ads.js +28 -3
  44. package/dist/connectors/mailchimp-oauth.js +28 -3
  45. package/dist/connectors/mailchimp.js +28 -3
  46. package/dist/connectors/meta-ads-oauth.js +28 -3
  47. package/dist/connectors/meta-ads.js +28 -3
  48. package/dist/connectors/mixpanel.js +28 -3
  49. package/dist/connectors/monday.js +28 -3
  50. package/dist/connectors/mongodb.js +28 -3
  51. package/dist/connectors/notion-oauth.js +28 -3
  52. package/dist/connectors/notion.js +28 -3
  53. package/dist/connectors/oracle.js +54 -14
  54. package/dist/connectors/outlook-oauth.js +28 -3
  55. package/dist/connectors/powerbi-oauth.js +309 -37
  56. package/dist/connectors/salesforce.js +28 -3
  57. package/dist/connectors/semrush.js +366 -46
  58. package/dist/connectors/sentry.js +28 -3
  59. package/dist/connectors/shopify-oauth.js +28 -3
  60. package/dist/connectors/shopify.js +28 -3
  61. package/dist/connectors/sqlserver.js +31 -6
  62. package/dist/connectors/stripe-api-key.js +28 -3
  63. package/dist/connectors/stripe-oauth.js +28 -3
  64. package/dist/connectors/supabase.js +31 -6
  65. package/dist/connectors/tableau.js +246 -78
  66. package/dist/connectors/tiktok-ads.js +28 -3
  67. package/dist/connectors/wix-store.js +28 -3
  68. package/dist/connectors/zendesk-oauth.js +28 -3
  69. package/dist/connectors/zendesk.js +28 -3
  70. package/dist/index.js +1681 -449
  71. package/dist/main.js +1681 -449
  72. package/dist/vite-plugin.js +1681 -449
  73. package/package.json +1 -1
@@ -792,19 +792,34 @@ async function runSetupFlow(flow, params, ctx, config) {
792
792
  };
793
793
  let state = flow.initialState();
794
794
  let answerIdx = 0;
795
+ const pendingParameterUpdates = [];
795
796
  for (const step of flow.steps) {
796
797
  const ans = ctx.answers[answerIdx];
797
798
  if (ans && ans.questionSlug === step.slug) {
798
799
  state = step.applyAnswer(state, ans.answer);
800
+ if (step.toParameterUpdates) {
801
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
802
+ }
799
803
  answerIdx += 1;
800
804
  continue;
801
805
  }
806
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
802
807
  if (step.type === "text") {
808
+ if (step.fetchOptions) {
809
+ const options2 = await step.fetchOptions(state, runtime);
810
+ if (options2.length === 0) {
811
+ continue;
812
+ }
813
+ }
803
814
  return {
804
815
  type: "nextQuestion",
805
816
  questionSlug: step.slug,
806
817
  question: step.question[ctx.language],
807
- questionType: "text"
818
+ questionType: "text",
819
+ allowFreeText: resolvedAllowFreeText,
820
+ ...pendingParameterUpdates.length > 0 && {
821
+ parameterUpdates: pendingParameterUpdates
822
+ }
808
823
  };
809
824
  }
810
825
  const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
@@ -816,11 +831,21 @@ async function runSetupFlow(flow, params, ctx, config) {
816
831
  questionSlug: step.slug,
817
832
  question: step.question[ctx.language],
818
833
  questionType: step.type,
819
- options
834
+ options,
835
+ allowFreeText: resolvedAllowFreeText,
836
+ ...pendingParameterUpdates.length > 0 && {
837
+ parameterUpdates: pendingParameterUpdates
838
+ }
820
839
  };
821
840
  }
822
841
  const dataInvestigationResult = await flow.finalize(state, runtime);
823
- return { type: "fulfilled", dataInvestigationResult };
842
+ return {
843
+ type: "fulfilled",
844
+ dataInvestigationResult,
845
+ ...pendingParameterUpdates.length > 0 && {
846
+ parameterUpdates: pendingParameterUpdates
847
+ }
848
+ };
824
849
  }
825
850
  async function resolveSetupSelection(params) {
826
851
  const { selected, allSentinel, fetchAll, limit } = params;
@@ -999,7 +1024,46 @@ var INTERNAL_SCHEMAS = /* @__PURE__ */ new Set([
999
1024
  "READER_ACCOUNT_USAGE",
1000
1025
  "DATA_SHARING_USAGE"
1001
1026
  ]);
1027
+ var OBJECT_TYPE_LABELS = {
1028
+ table: { ja: "\u30C6\u30FC\u30D6\u30EB", en: "Table" },
1029
+ view: { ja: "\u30D3\u30E5\u30FC", en: "View" },
1030
+ stream: { ja: "\u30B9\u30C8\u30EA\u30FC\u30E0", en: "Stream" },
1031
+ dynamic_table: { ja: "\u30C0\u30A4\u30CA\u30DF\u30C3\u30AF\u30C6\u30FC\u30D6\u30EB", en: "Dynamic Table" },
1032
+ pipe: { ja: "\u30D1\u30A4\u30D7", en: "Pipe" },
1033
+ task: { ja: "\u30BF\u30B9\u30AF", en: "Task" }
1034
+ };
1035
+ var HEADING_LABELS = {
1036
+ table: "Table",
1037
+ view: "View",
1038
+ stream: "Stream",
1039
+ dynamic_table: "Dynamic Table",
1040
+ pipe: "Pipe",
1041
+ task: "Task"
1042
+ };
1002
1043
  function createSnowflakeSetupFlow(runQuery11) {
1044
+ const objectTypes = /* @__PURE__ */ new Map();
1045
+ async function fetchAllObjects(params, db, schema) {
1046
+ objectTypes.clear();
1047
+ const typeQueries = [
1048
+ ["table", `SHOW TABLES IN SCHEMA "${db}"."${schema}"`],
1049
+ ["view", `SHOW VIEWS IN SCHEMA "${db}"."${schema}"`],
1050
+ ["stream", `SHOW STREAMS IN SCHEMA "${db}"."${schema}"`],
1051
+ ["dynamic_table", `SHOW DYNAMIC TABLES IN SCHEMA "${db}"."${schema}"`],
1052
+ ["pipe", `SHOW PIPES IN SCHEMA "${db}"."${schema}"`],
1053
+ ["task", `SHOW TASKS IN SCHEMA "${db}"."${schema}"`]
1054
+ ];
1055
+ const results = await Promise.all(
1056
+ typeQueries.map(([, sql]) => runQuery11(params, sql).catch(() => []))
1057
+ );
1058
+ for (let i = 0; i < results.length; i++) {
1059
+ const type = typeQueries[i][0];
1060
+ for (const r of results[i]) {
1061
+ const name = String(r["name"] ?? "");
1062
+ if (name) objectTypes.set(name, type);
1063
+ }
1064
+ }
1065
+ return Array.from(objectTypes.keys());
1066
+ }
1003
1067
  return {
1004
1068
  initialState: () => ({}),
1005
1069
  steps: [
@@ -1039,22 +1103,27 @@ function createSnowflakeSetupFlow(runQuery11) {
1039
1103
  slug: "tables",
1040
1104
  type: "multiSelect",
1041
1105
  question: {
1042
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
1043
- en: "Select target tables (multi-select allowed)"
1106
+ ja: "\u5BFE\u8C61\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u30FB\u30B9\u30C8\u30EA\u30FC\u30E0\u7B49\u3001\u8907\u6570\u9078\u629E\u53EF\uFF09",
1107
+ en: "Select target objects (tables, views, streams, etc. \u2014 multi-select allowed)"
1044
1108
  },
1045
1109
  async fetchOptions(state, rt) {
1046
1110
  if (!state.database || !state.schema) return [];
1047
- const rows = await runQuery11(
1111
+ const allNames = await fetchAllObjects(
1048
1112
  rt.params,
1049
- `SHOW TABLES IN SCHEMA "${state.database}"."${state.schema}"`
1113
+ state.database,
1114
+ state.schema
1050
1115
  );
1051
- const tableOptions = rows.map((r) => String(r["name"] ?? "")).filter((name) => name).map((value) => ({ value }));
1116
+ const options = allNames.map((name) => {
1117
+ const type = objectTypes.get(name) ?? "table";
1118
+ const typeLabel = OBJECT_TYPE_LABELS[type][rt.language];
1119
+ return { value: name, label: `${name} (${typeLabel})` };
1120
+ });
1052
1121
  return [
1053
1122
  {
1054
1123
  value: ALL_TABLES,
1055
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
1124
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8" : "All objects"
1056
1125
  },
1057
- ...tableOptions
1126
+ ...options
1058
1127
  ];
1059
1128
  },
1060
1129
  applyAnswer: (state, answer) => ({ ...state, tables: answer })
@@ -1066,16 +1135,10 @@ function createSnowflakeSetupFlow(runQuery11) {
1066
1135
  }
1067
1136
  const db = state.database;
1068
1137
  const schema = state.schema;
1069
- const targetTables = await resolveSetupSelection({
1138
+ const targetObjects = await resolveSetupSelection({
1070
1139
  selected: state.tables,
1071
1140
  allSentinel: ALL_TABLES,
1072
- fetchAll: async () => {
1073
- const rows = await runQuery11(
1074
- rt.params,
1075
- `SHOW TABLES IN SCHEMA "${db}"."${schema}"`
1076
- );
1077
- return rows.map((r) => String(r["name"] ?? "")).filter((name) => name);
1078
- },
1141
+ fetchAll: () => fetchAllObjects(rt.params, db, schema),
1079
1142
  limit: SNOWFLAKE_SETUP_MAX_TABLES
1080
1143
  });
1081
1144
  const sections = [
@@ -1086,24 +1149,66 @@ function createSnowflakeSetupFlow(runQuery11) {
1086
1149
  `#### Schema: ${schema}`,
1087
1150
  ""
1088
1151
  ];
1089
- for (const table of targetTables) {
1090
- const cols = await runQuery11(
1091
- rt.params,
1092
- `DESCRIBE TABLE "${db}"."${schema}"."${table}"`
1093
- );
1094
- sections.push(`##### Table: ${table}`, "");
1095
- sections.push("| Column | Type | Nullable | Default |");
1096
- sections.push("|--------|------|----------|---------|");
1097
- for (const c of cols) {
1098
- const name = String(c["name"] ?? "");
1099
- const type = String(c["type"] ?? "");
1100
- const nullable = String(c["null?"] ?? "");
1101
- const defaultValue = c["default"] == null ? "-" : String(c["default"]);
1102
- sections.push(
1103
- `| ${name} | ${type} | ${nullable} | ${defaultValue} |`
1104
- );
1152
+ for (const name of targetObjects) {
1153
+ const type = objectTypes.get(name) ?? "table";
1154
+ const heading = HEADING_LABELS[type];
1155
+ switch (type) {
1156
+ case "table":
1157
+ case "view":
1158
+ case "dynamic_table":
1159
+ case "stream": {
1160
+ const cols = await runQuery11(
1161
+ rt.params,
1162
+ `DESCRIBE TABLE "${db}"."${schema}"."${name}"`
1163
+ ).catch(() => []);
1164
+ sections.push(`##### ${heading}: ${name}`, "");
1165
+ if (cols.length > 0) {
1166
+ sections.push("| Column | Type | Nullable | Default |");
1167
+ sections.push("|--------|------|----------|---------|");
1168
+ for (const c of cols) {
1169
+ const colName = String(c["name"] ?? "");
1170
+ const colType = String(c["type"] ?? "");
1171
+ const nullable = String(c["null?"] ?? "");
1172
+ const defaultValue = c["default"] == null ? "-" : String(c["default"]);
1173
+ sections.push(
1174
+ `| ${colName} | ${colType} | ${nullable} | ${defaultValue} |`
1175
+ );
1176
+ }
1177
+ }
1178
+ sections.push("");
1179
+ break;
1180
+ }
1181
+ case "pipe": {
1182
+ const rows = await runQuery11(
1183
+ rt.params,
1184
+ `SHOW PIPES LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
1185
+ ).catch(() => []);
1186
+ sections.push(`##### Pipe: ${name}`, "");
1187
+ if (rows.length > 0) {
1188
+ const definition = String(rows[0]["definition"] ?? "-");
1189
+ sections.push(`Definition: \`${definition}\``, "");
1190
+ }
1191
+ sections.push("");
1192
+ break;
1193
+ }
1194
+ case "task": {
1195
+ const rows = await runQuery11(
1196
+ rt.params,
1197
+ `SHOW TASKS LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
1198
+ ).catch(() => []);
1199
+ sections.push(`##### Task: ${name}`, "");
1200
+ if (rows.length > 0) {
1201
+ const schedule = String(rows[0]["schedule"] ?? "-");
1202
+ const taskState = String(rows[0]["state"] ?? "-");
1203
+ const definition = String(rows[0]["definition"] ?? "-");
1204
+ sections.push(`Schedule: ${schedule}`, "");
1205
+ sections.push(`State: ${taskState}`, "");
1206
+ sections.push(`Definition: \`${definition}\``, "");
1207
+ }
1208
+ sections.push("");
1209
+ break;
1210
+ }
1105
1211
  }
1106
- sections.push("");
1107
1212
  }
1108
1213
  return sections.join("\n");
1109
1214
  }
@@ -1916,8 +2021,8 @@ var postgresqlSetupFlow = {
1916
2021
  slug: "tables",
1917
2022
  type: "multiSelect",
1918
2023
  question: {
1919
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
1920
- en: "Select target tables (multi-select allowed)"
2024
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
2025
+ en: "Select target tables and views (multi-select allowed)"
1921
2026
  },
1922
2027
  async fetchOptions(state, rt) {
1923
2028
  if (!state.schema) return [];
@@ -1926,7 +2031,7 @@ var postgresqlSetupFlow = {
1926
2031
  return [
1927
2032
  {
1928
2033
  value: ALL_TABLES2,
1929
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
2034
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
1930
2035
  },
1931
2036
  ...tableOptions
1932
2037
  ];
@@ -2263,8 +2368,8 @@ var mysqlSetupFlow = {
2263
2368
  slug: "tables",
2264
2369
  type: "multiSelect",
2265
2370
  question: {
2266
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
2267
- en: "Select target tables (multi-select allowed)"
2371
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
2372
+ en: "Select target tables and views (multi-select allowed)"
2268
2373
  },
2269
2374
  async fetchOptions(state, rt) {
2270
2375
  if (!state.database) return [];
@@ -2273,7 +2378,7 @@ var mysqlSetupFlow = {
2273
2378
  return [
2274
2379
  {
2275
2380
  value: ALL_TABLES3,
2276
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
2381
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
2277
2382
  },
2278
2383
  ...tableOptions
2279
2384
  ];
@@ -2724,6 +2829,72 @@ var bigqueryOnboarding = new ConnectorOnboarding({
2724
2829
  }
2725
2830
  });
2726
2831
 
2832
+ // ../connectors/src/table-grouping.ts
2833
+ var SHARD_GROUP_PREFIX = "__SHARD__";
2834
+ var DEFAULT_MIN_SHARD_GROUP_SIZE = 3;
2835
+ function extractDateShardSuffix(name) {
2836
+ const m = name.match(/^(.+)_(\d{8})$/);
2837
+ if (!m) return null;
2838
+ const [, prefix, suffix] = m;
2839
+ const y = +suffix.slice(0, 4);
2840
+ const mo = +suffix.slice(4, 6);
2841
+ const d = +suffix.slice(6, 8);
2842
+ if (y < 2e3 || y > 2099 || mo < 1 || mo > 12 || d < 1 || d > 31) {
2843
+ return null;
2844
+ }
2845
+ return { prefix, suffix };
2846
+ }
2847
+ function detectDateShardCandidates(tableNames, minCount = DEFAULT_MIN_SHARD_GROUP_SIZE) {
2848
+ const prefixMap = /* @__PURE__ */ new Map();
2849
+ const nonSharded = [];
2850
+ for (const name of tableNames) {
2851
+ const parsed = extractDateShardSuffix(name);
2852
+ if (parsed) {
2853
+ const existing = prefixMap.get(parsed.prefix);
2854
+ if (existing) {
2855
+ existing.push(name);
2856
+ } else {
2857
+ prefixMap.set(parsed.prefix, [name]);
2858
+ }
2859
+ } else {
2860
+ nonSharded.push(name);
2861
+ }
2862
+ }
2863
+ const candidates = [];
2864
+ const singles = [...nonSharded];
2865
+ for (const [prefix, members] of prefixMap) {
2866
+ if (members.length >= minCount) {
2867
+ candidates.push({ prefix, count: members.length, members });
2868
+ } else {
2869
+ singles.push(...members);
2870
+ }
2871
+ }
2872
+ return { singles, candidates };
2873
+ }
2874
+ function schemasMatch(columnsA, columnsB) {
2875
+ if (columnsA.length !== columnsB.length) return false;
2876
+ return columnsA.every(
2877
+ (a, i) => String(a["column_name"] ?? "") === String(columnsB[i]["column_name"] ?? "") && String(a["data_type"] ?? "") === String(columnsB[i]["data_type"] ?? "")
2878
+ );
2879
+ }
2880
+ function isShardGroupValue(value) {
2881
+ return value.startsWith(SHARD_GROUP_PREFIX);
2882
+ }
2883
+ function getShardGroupPrefix(value) {
2884
+ return value.slice(SHARD_GROUP_PREFIX.length);
2885
+ }
2886
+ function shardGroupValue(prefix) {
2887
+ return `${SHARD_GROUP_PREFIX}${prefix}`;
2888
+ }
2889
+ function buildGroupedTableOptions(singles, confirmedGroups, language) {
2890
+ const groupOptions = confirmedGroups.sort((a, b) => a.prefix.localeCompare(b.prefix)).map((g) => ({
2891
+ value: shardGroupValue(g.prefix),
2892
+ label: language === "ja" ? `${g.prefix}_* (\u65E5\u4ED8\u30B7\u30E3\u30FC\u30C9: ${g.count} \u30C6\u30FC\u30D6\u30EB)` : `${g.prefix}_* (date-sharded: ${g.count} tables)`
2893
+ }));
2894
+ const singleOptions = singles.sort().map((name) => ({ value: name }));
2895
+ return [...groupOptions, ...singleOptions];
2896
+ }
2897
+
2727
2898
  // ../connectors/src/connectors/bigquery/utils.ts
2728
2899
  async function runQuery5(params, sql) {
2729
2900
  const { BigQuery } = await import("@google-cloud/bigquery");
@@ -2754,13 +2925,23 @@ async function listProjects(params) {
2754
2925
  scopes: ["https://www.googleapis.com/auth/bigquery"]
2755
2926
  });
2756
2927
  const client = await auth.getClient();
2757
- const res = await client.request({
2758
- url: "https://bigquery.googleapis.com/bigquery/v2/projects"
2759
- });
2760
- return (res.data.projects ?? []).map((p) => ({
2761
- projectId: p.projectReference?.projectId ?? "",
2762
- friendlyName: p.friendlyName ?? p.projectReference?.projectId ?? ""
2763
- })).filter((p) => p.projectId !== "");
2928
+ const projects = [];
2929
+ let pageToken;
2930
+ do {
2931
+ const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
2932
+ const res = await client.request({ url });
2933
+ for (const p of res.data.projects ?? []) {
2934
+ const id = p.projectReference?.projectId ?? "";
2935
+ if (id) {
2936
+ projects.push({
2937
+ projectId: id,
2938
+ friendlyName: p.friendlyName ?? id
2939
+ });
2940
+ }
2941
+ }
2942
+ pageToken = res.data.nextPageToken;
2943
+ } while (pageToken);
2944
+ return projects;
2764
2945
  }
2765
2946
  async function listDatasets(params, projectId2) {
2766
2947
  const { BigQuery } = await import("@google-cloud/bigquery");
@@ -2798,23 +2979,25 @@ var PUBLIC_DATASETS = [
2798
2979
  labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
2799
2980
  }
2800
2981
  ];
2982
+ var SAME_AS_BILLING = "__SAME_AS_BILLING__";
2801
2983
  function resolveDatasetRef(state) {
2802
2984
  const dataset = state.dataset ?? "";
2803
2985
  if (dataset.includes(".")) {
2804
2986
  const [datasetProject, ...rest] = dataset.split(".");
2805
2987
  return { datasetProject, datasetId: rest.join(".") };
2806
2988
  }
2807
- return { datasetProject: state.project ?? "", datasetId: dataset };
2989
+ return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
2808
2990
  }
2809
2991
  var bigquerySetupFlow = {
2810
2992
  initialState: () => ({}),
2811
2993
  steps: [
2812
2994
  {
2813
- slug: "project",
2995
+ slug: "billingProject",
2814
2996
  type: "select",
2997
+ allowFreeText: false,
2815
2998
  question: {
2816
- ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u4F7F\u3046 GCP \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u30D1\u30D6\u30EA\u30C3\u30AF\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u4F7F\u3046\u5834\u5408\u3082\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u3057\u3066\u5FC5\u8981\u3067\u3059\uFF09",
2817
- en: "Select the GCP project to use for setup (also required as the billing project when querying public datasets)"
2999
+ ja: "BigQuery \u3092\u5B9F\u884C\u3059\u308B Google Cloud \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08BigQuery \u306E\u8AB2\u91D1\u306B\u7D10\u3065\u304F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067\u3059\uFF09",
3000
+ en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
2818
3001
  },
2819
3002
  async fetchOptions(_state, rt) {
2820
3003
  const projects = await listProjects(rt.params);
@@ -2823,7 +3006,40 @@ var bigquerySetupFlow = {
2823
3006
  label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
2824
3007
  }));
2825
3008
  },
2826
- applyAnswer: (state, answer) => ({ ...state, project: answer[0] })
3009
+ applyAnswer: (state, answer) => ({
3010
+ ...state,
3011
+ billingProject: answer[0]
3012
+ }),
3013
+ toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
3014
+ },
3015
+ {
3016
+ slug: "databaseProject",
3017
+ type: "select",
3018
+ question: {
3019
+ ja: "\u30C7\u30FC\u30BF\u304C\u683C\u7D0D\u3055\u308C\u3066\u3044\u308B GCP \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
3020
+ en: "Select the GCP project where your data resides"
3021
+ },
3022
+ async fetchOptions(state, rt) {
3023
+ if (!state.billingProject) return [];
3024
+ const sameAsBillingOption = {
3025
+ value: SAME_AS_BILLING,
3026
+ label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
3027
+ };
3028
+ const projects = await listProjects(rt.params);
3029
+ const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
3030
+ value: p.projectId,
3031
+ label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
3032
+ }));
3033
+ const publicProjectOption = {
3034
+ value: "bigquery-public-data",
3035
+ label: rt.language === "ja" ? "bigquery-public-data (Google \u30D1\u30D6\u30EA\u30C3\u30AF\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8)" : "bigquery-public-data (Google public datasets)"
3036
+ };
3037
+ return [sameAsBillingOption, ...projectOptions, publicProjectOption];
3038
+ },
3039
+ applyAnswer: (state, answer) => ({
3040
+ ...state,
3041
+ databaseProject: answer[0] === SAME_AS_BILLING ? state.billingProject : answer[0]
3042
+ })
2827
3043
  },
2828
3044
  {
2829
3045
  slug: "dataset",
@@ -2833,8 +3049,8 @@ var bigquerySetupFlow = {
2833
3049
  en: "Select the dataset to use for setup"
2834
3050
  },
2835
3051
  async fetchOptions(state, rt) {
2836
- if (!state.project) return [];
2837
- const datasets = await listDatasets(rt.params, state.project);
3052
+ if (!state.databaseProject) return [];
3053
+ const datasets = await listDatasets(rt.params, state.databaseProject);
2838
3054
  const projectDatasetOptions = datasets.map((d) => ({
2839
3055
  value: d.datasetId,
2840
3056
  label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
@@ -2851,66 +3067,140 @@ var bigquerySetupFlow = {
2851
3067
  slug: "tables",
2852
3068
  type: "multiSelect",
2853
3069
  question: {
2854
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
2855
- en: "Select target tables (multi-select allowed)"
3070
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
3071
+ en: "Select target tables and views (multi-select allowed)"
2856
3072
  },
2857
3073
  async fetchOptions(state, rt) {
2858
- if (!state.project || !state.dataset) return [];
3074
+ if (!state.billingProject || !state.dataset) return [];
2859
3075
  const { datasetProject, datasetId } = resolveDatasetRef(state);
2860
3076
  const rows = await runQuery5(
2861
3077
  rt.params,
2862
3078
  `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
2863
3079
  );
2864
- const tableOptions = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name).map((value) => ({ value }));
3080
+ const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3081
+ const { singles, candidates } = detectDateShardCandidates(tableNames);
3082
+ const confirmedGroups = [];
3083
+ const rejectedSingles = [];
3084
+ for (const candidate of candidates) {
3085
+ const [first, second] = candidate.members;
3086
+ const colRows = await runQuery5(
3087
+ rt.params,
3088
+ `SELECT table_name, column_name, data_type FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name IN ('${first.replaceAll("'", "''")}', '${second.replaceAll("'", "''")}') ORDER BY table_name, ordinal_position`
3089
+ );
3090
+ const colsA = colRows.filter(
3091
+ (r) => String(r["table_name"]) === first
3092
+ );
3093
+ const colsB = colRows.filter(
3094
+ (r) => String(r["table_name"]) === second
3095
+ );
3096
+ if (schemasMatch(colsA, colsB)) {
3097
+ confirmedGroups.push(candidate);
3098
+ } else {
3099
+ rejectedSingles.push(...candidate.members);
3100
+ }
3101
+ }
3102
+ const allSingles = [...singles, ...rejectedSingles];
2865
3103
  return [
2866
3104
  {
2867
3105
  value: ALL_TABLES4,
2868
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
3106
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
2869
3107
  },
2870
- ...tableOptions
3108
+ ...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
2871
3109
  ];
2872
3110
  },
2873
3111
  applyAnswer: (state, answer) => ({ ...state, tables: answer })
2874
3112
  }
2875
3113
  ],
2876
3114
  async finalize(state, rt) {
2877
- if (!state.project || !state.dataset || !state.tables) {
3115
+ if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
2878
3116
  throw new Error("BigQuery setup: incomplete state on finalize");
2879
3117
  }
2880
3118
  const { datasetProject, datasetId } = resolveDatasetRef(state);
2881
- const targetTables = await resolveSetupSelection({
2882
- selected: state.tables,
2883
- allSentinel: ALL_TABLES4,
2884
- fetchAll: async () => {
2885
- const rows = await runQuery5(
2886
- rt.params,
2887
- `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
2888
- );
2889
- return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
2890
- },
2891
- limit: BIGQUERY_SETUP_MAX_TABLES
2892
- });
3119
+ const fetchAllTableNames = async () => {
3120
+ const rows = await runQuery5(
3121
+ rt.params,
3122
+ `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3123
+ );
3124
+ return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3125
+ };
3126
+ let entries;
3127
+ if (state.tables.includes(ALL_TABLES4)) {
3128
+ const allNames = await fetchAllTableNames();
3129
+ const { singles, candidates } = detectDateShardCandidates(allNames);
3130
+ entries = [
3131
+ ...candidates.map(
3132
+ (g) => ({
3133
+ type: "shardGroup",
3134
+ prefix: g.prefix,
3135
+ count: g.count,
3136
+ representative: g.members[0]
3137
+ })
3138
+ ),
3139
+ ...singles.map((name) => ({ type: "table", name }))
3140
+ ];
3141
+ } else {
3142
+ const shardSelections = state.tables.filter(isShardGroupValue);
3143
+ const tableSelections = state.tables.filter(
3144
+ (v) => !isShardGroupValue(v)
3145
+ );
3146
+ entries = tableSelections.map(
3147
+ (name) => ({ type: "table", name })
3148
+ );
3149
+ if (shardSelections.length > 0) {
3150
+ const allNames = await fetchAllTableNames();
3151
+ for (const value of shardSelections) {
3152
+ const prefix = getShardGroupPrefix(value);
3153
+ const members = allNames.filter((n) => {
3154
+ const parsed = extractDateShardSuffix(n);
3155
+ return parsed != null && parsed.prefix === prefix;
3156
+ });
3157
+ if (members.length > 0) {
3158
+ entries.push({
3159
+ type: "shardGroup",
3160
+ prefix,
3161
+ count: members.length,
3162
+ representative: members[0]
3163
+ });
3164
+ }
3165
+ }
3166
+ }
3167
+ }
3168
+ entries = entries.slice(0, BIGQUERY_SETUP_MAX_TABLES);
3169
+ const queryColumns = async (tableName) => runQuery5(
3170
+ rt.params,
3171
+ `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
3172
+ );
2893
3173
  const sections = [
2894
3174
  "## BigQuery",
2895
3175
  "",
2896
- `### Billing project: ${state.project}`,
3176
+ `### Billing project: ${state.billingProject}`,
3177
+ "",
3178
+ `### Database project: ${state.databaseProject}`,
2897
3179
  "",
2898
3180
  `#### Dataset: ${datasetProject}.${datasetId}`,
2899
3181
  ""
2900
3182
  ];
2901
- for (const table of targetTables) {
2902
- const cols = await runQuery5(
2903
- rt.params,
2904
- `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${table.replaceAll("'", "''")}' ORDER BY ordinal_position`
2905
- );
2906
- sections.push(`##### Table: ${table}`, "");
3183
+ for (const entry of entries) {
3184
+ const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
3185
+ const cols = await queryColumns(tableName);
3186
+ if (entry.type === "shardGroup") {
3187
+ sections.push(
3188
+ `##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
3189
+ ""
3190
+ );
3191
+ sections.push(
3192
+ `_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
3193
+ ""
3194
+ );
3195
+ } else {
3196
+ sections.push(`##### Table: ${entry.name}`, "");
3197
+ }
2907
3198
  sections.push("| Column | Type | Nullable |");
2908
3199
  sections.push("|--------|------|----------|");
2909
3200
  for (const c of cols) {
2910
- const name = String(c["column_name"] ?? "");
2911
- const type = String(c["data_type"] ?? "");
2912
- const nullable = String(c["is_nullable"] ?? "");
2913
- sections.push(`| ${name} | ${type} | ${nullable} |`);
3201
+ sections.push(
3202
+ `| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
3203
+ );
2914
3204
  }
2915
3205
  sections.push("");
2916
3206
  }
@@ -3408,21 +3698,30 @@ async function runQuery6(proxyFetch, projectId2, sql) {
3408
3698
  return parseQueryResponse(data);
3409
3699
  }
3410
3700
  async function listProjects2(proxyFetch) {
3411
- const res = await proxyFetch(
3412
- "https://bigquery.googleapis.com/bigquery/v2/projects",
3413
- { method: "GET" }
3414
- );
3415
- if (!res.ok) {
3416
- const errorText = await res.text().catch(() => res.statusText);
3417
- throw new Error(
3418
- `BigQuery listProjects failed: HTTP ${res.status} ${errorText}`
3419
- );
3420
- }
3421
- const data = await res.json();
3422
- return (data.projects ?? []).map((p) => ({
3423
- projectId: p.projectReference?.projectId ?? "",
3424
- friendlyName: p.friendlyName ?? p.projectReference?.projectId ?? ""
3425
- })).filter((p) => p.projectId !== "");
3701
+ const projects = [];
3702
+ let pageToken;
3703
+ do {
3704
+ const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
3705
+ const res = await proxyFetch(url, { method: "GET" });
3706
+ if (!res.ok) {
3707
+ const errorText = await res.text().catch(() => res.statusText);
3708
+ throw new Error(
3709
+ `BigQuery listProjects failed: HTTP ${res.status} ${errorText}`
3710
+ );
3711
+ }
3712
+ const data = await res.json();
3713
+ for (const p of data.projects ?? []) {
3714
+ const id = p.projectReference?.projectId ?? "";
3715
+ if (id) {
3716
+ projects.push({
3717
+ projectId: id,
3718
+ friendlyName: p.friendlyName ?? id
3719
+ });
3720
+ }
3721
+ }
3722
+ pageToken = data.nextPageToken;
3723
+ } while (pageToken);
3724
+ return projects;
3426
3725
  }
3427
3726
  async function listDatasets2(proxyFetch, projectId2) {
3428
3727
  const res = await proxyFetch(
@@ -3462,23 +3761,25 @@ var PUBLIC_DATASETS2 = [
3462
3761
  labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
3463
3762
  }
3464
3763
  ];
3764
+ var SAME_AS_BILLING2 = "__SAME_AS_BILLING__";
3465
3765
  function resolveDatasetRef2(state) {
3466
3766
  const dataset = state.dataset ?? "";
3467
3767
  if (dataset.includes(".")) {
3468
3768
  const [datasetProject, ...rest] = dataset.split(".");
3469
3769
  return { datasetProject, datasetId: rest.join(".") };
3470
3770
  }
3471
- return { datasetProject: state.project ?? "", datasetId: dataset };
3771
+ return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
3472
3772
  }
3473
3773
  var bigqueryOauthSetupFlow = {
3474
3774
  initialState: () => ({}),
3475
3775
  steps: [
3476
3776
  {
3477
- slug: "project",
3777
+ slug: "billingProject",
3478
3778
  type: "select",
3779
+ allowFreeText: false,
3479
3780
  question: {
3480
- ja: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u4F7F\u3046 GCP \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u30D1\u30D6\u30EA\u30C3\u30AF\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u4F7F\u3046\u5834\u5408\u3082\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u3057\u3066\u5FC5\u8981\u3067\u3059\uFF09",
3481
- en: "Select the GCP project to use for setup (also required as the billing project when querying public datasets)"
3781
+ ja: "BigQuery \u3092\u5B9F\u884C\u3059\u308B Google Cloud \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08BigQuery \u306E\u8AB2\u91D1\u306B\u7D10\u3065\u304F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067\u3059\uFF09",
3782
+ en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
3482
3783
  },
3483
3784
  async fetchOptions(_state, rt) {
3484
3785
  const projects = await listProjects2(rt.config.proxyFetch);
@@ -3487,7 +3788,40 @@ var bigqueryOauthSetupFlow = {
3487
3788
  label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
3488
3789
  }));
3489
3790
  },
3490
- applyAnswer: (state, answer) => ({ ...state, project: answer[0] })
3791
+ applyAnswer: (state, answer) => ({
3792
+ ...state,
3793
+ billingProject: answer[0]
3794
+ }),
3795
+ toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
3796
+ },
3797
+ {
3798
+ slug: "databaseProject",
3799
+ type: "select",
3800
+ question: {
3801
+ ja: "\u30C7\u30FC\u30BF\u304C\u683C\u7D0D\u3055\u308C\u3066\u3044\u308B GCP \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
3802
+ en: "Select the GCP project where your data resides"
3803
+ },
3804
+ async fetchOptions(state, rt) {
3805
+ if (!state.billingProject) return [];
3806
+ const sameAsBillingOption = {
3807
+ value: SAME_AS_BILLING2,
3808
+ label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
3809
+ };
3810
+ const projects = await listProjects2(rt.config.proxyFetch);
3811
+ const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
3812
+ value: p.projectId,
3813
+ label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
3814
+ }));
3815
+ const publicProjectOption = {
3816
+ value: "bigquery-public-data",
3817
+ label: rt.language === "ja" ? "bigquery-public-data (Google \u30D1\u30D6\u30EA\u30C3\u30AF\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8)" : "bigquery-public-data (Google public datasets)"
3818
+ };
3819
+ return [sameAsBillingOption, ...projectOptions, publicProjectOption];
3820
+ },
3821
+ applyAnswer: (state, answer) => ({
3822
+ ...state,
3823
+ databaseProject: answer[0] === SAME_AS_BILLING2 ? state.billingProject : answer[0]
3824
+ })
3491
3825
  },
3492
3826
  {
3493
3827
  slug: "dataset",
@@ -3497,8 +3831,11 @@ var bigqueryOauthSetupFlow = {
3497
3831
  en: "Select the dataset to use for setup"
3498
3832
  },
3499
3833
  async fetchOptions(state, rt) {
3500
- if (!state.project) return [];
3501
- const datasets = await listDatasets2(rt.config.proxyFetch, state.project);
3834
+ if (!state.databaseProject) return [];
3835
+ const datasets = await listDatasets2(
3836
+ rt.config.proxyFetch,
3837
+ state.databaseProject
3838
+ );
3502
3839
  const projectDatasetOptions = datasets.map((d) => ({
3503
3840
  value: d.datasetId,
3504
3841
  label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
@@ -3515,70 +3852,145 @@ var bigqueryOauthSetupFlow = {
3515
3852
  slug: "tables",
3516
3853
  type: "multiSelect",
3517
3854
  question: {
3518
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
3519
- en: "Select target tables (multi-select allowed)"
3855
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
3856
+ en: "Select target tables and views (multi-select allowed)"
3520
3857
  },
3521
3858
  async fetchOptions(state, rt) {
3522
- if (!state.project || !state.dataset) return [];
3859
+ if (!state.billingProject || !state.dataset) return [];
3523
3860
  const { datasetProject, datasetId } = resolveDatasetRef2(state);
3524
3861
  const rows = await runQuery6(
3525
3862
  rt.config.proxyFetch,
3526
- state.project,
3863
+ state.billingProject,
3527
3864
  `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3528
3865
  );
3529
- const tableOptions = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name).map((value) => ({ value }));
3866
+ const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3867
+ const { singles, candidates } = detectDateShardCandidates(tableNames);
3868
+ const confirmedGroups = [];
3869
+ const rejectedSingles = [];
3870
+ for (const candidate of candidates) {
3871
+ const [first, second] = candidate.members;
3872
+ const colRows = await runQuery6(
3873
+ rt.config.proxyFetch,
3874
+ state.billingProject,
3875
+ `SELECT table_name, column_name, data_type FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name IN ('${first.replaceAll("'", "''")}', '${second.replaceAll("'", "''")}') ORDER BY table_name, ordinal_position`
3876
+ );
3877
+ const colsA = colRows.filter(
3878
+ (r) => String(r["table_name"]) === first
3879
+ );
3880
+ const colsB = colRows.filter(
3881
+ (r) => String(r["table_name"]) === second
3882
+ );
3883
+ if (schemasMatch(colsA, colsB)) {
3884
+ confirmedGroups.push(candidate);
3885
+ } else {
3886
+ rejectedSingles.push(...candidate.members);
3887
+ }
3888
+ }
3889
+ const allSingles = [...singles, ...rejectedSingles];
3530
3890
  return [
3531
3891
  {
3532
3892
  value: ALL_TABLES5,
3533
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
3893
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
3534
3894
  },
3535
- ...tableOptions
3895
+ ...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
3536
3896
  ];
3537
3897
  },
3538
3898
  applyAnswer: (state, answer) => ({ ...state, tables: answer })
3539
3899
  }
3540
3900
  ],
3541
3901
  async finalize(state, rt) {
3542
- if (!state.project || !state.dataset || !state.tables) {
3902
+ if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
3543
3903
  throw new Error("BigQuery OAuth setup: incomplete state on finalize");
3544
3904
  }
3545
- const billingProject = state.project;
3905
+ const billingProject = state.billingProject;
3546
3906
  const { datasetProject, datasetId } = resolveDatasetRef2(state);
3547
- const targetTables = await resolveSetupSelection({
3548
- selected: state.tables,
3549
- allSentinel: ALL_TABLES5,
3550
- fetchAll: async () => {
3551
- const rows = await runQuery6(
3552
- rt.config.proxyFetch,
3553
- billingProject,
3554
- `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3555
- );
3556
- return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3557
- },
3558
- limit: BIGQUERY_OAUTH_SETUP_MAX_TABLES
3559
- });
3907
+ const fetchAllTableNames = async () => {
3908
+ const rows = await runQuery6(
3909
+ rt.config.proxyFetch,
3910
+ billingProject,
3911
+ `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3912
+ );
3913
+ return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3914
+ };
3915
+ let entries;
3916
+ if (state.tables.includes(ALL_TABLES5)) {
3917
+ const allNames = await fetchAllTableNames();
3918
+ const { singles, candidates } = detectDateShardCandidates(allNames);
3919
+ entries = [
3920
+ ...candidates.map(
3921
+ (g) => ({
3922
+ type: "shardGroup",
3923
+ prefix: g.prefix,
3924
+ count: g.count,
3925
+ representative: g.members[0]
3926
+ })
3927
+ ),
3928
+ ...singles.map((name) => ({ type: "table", name }))
3929
+ ];
3930
+ } else {
3931
+ const shardSelections = state.tables.filter(isShardGroupValue);
3932
+ const tableSelections = state.tables.filter(
3933
+ (v) => !isShardGroupValue(v)
3934
+ );
3935
+ entries = tableSelections.map(
3936
+ (name) => ({ type: "table", name })
3937
+ );
3938
+ if (shardSelections.length > 0) {
3939
+ const allNames = await fetchAllTableNames();
3940
+ for (const value of shardSelections) {
3941
+ const prefix = getShardGroupPrefix(value);
3942
+ const members = allNames.filter((n) => {
3943
+ const parsed = extractDateShardSuffix(n);
3944
+ return parsed != null && parsed.prefix === prefix;
3945
+ });
3946
+ if (members.length > 0) {
3947
+ entries.push({
3948
+ type: "shardGroup",
3949
+ prefix,
3950
+ count: members.length,
3951
+ representative: members[0]
3952
+ });
3953
+ }
3954
+ }
3955
+ }
3956
+ }
3957
+ entries = entries.slice(0, BIGQUERY_OAUTH_SETUP_MAX_TABLES);
3958
+ const queryColumns = async (tableName) => runQuery6(
3959
+ rt.config.proxyFetch,
3960
+ billingProject,
3961
+ `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
3962
+ );
3560
3963
  const sections = [
3561
3964
  "## BigQuery (OAuth)",
3562
3965
  "",
3563
3966
  `### Billing project: ${billingProject}`,
3564
3967
  "",
3968
+ `### Database project: ${state.databaseProject}`,
3969
+ "",
3565
3970
  `#### Dataset: ${datasetProject}.${datasetId}`,
3566
3971
  ""
3567
3972
  ];
3568
- for (const table of targetTables) {
3569
- const cols = await runQuery6(
3570
- rt.config.proxyFetch,
3571
- billingProject,
3572
- `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${table.replaceAll("'", "''")}' ORDER BY ordinal_position`
3573
- );
3574
- sections.push(`##### Table: ${table}`, "");
3973
+ for (const entry of entries) {
3974
+ const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
3975
+ const cols = await queryColumns(tableName);
3976
+ if (entry.type === "shardGroup") {
3977
+ sections.push(
3978
+ `##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
3979
+ ""
3980
+ );
3981
+ sections.push(
3982
+ `_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
3983
+ ""
3984
+ );
3985
+ } else {
3986
+ sections.push(`##### Table: ${entry.name}`, "");
3987
+ }
3575
3988
  sections.push("| Column | Type | Nullable |");
3576
3989
  sections.push("|--------|------|----------|");
3577
3990
  for (const c of cols) {
3578
- const name = String(c["column_name"] ?? "");
3579
- const type = String(c["data_type"] ?? "");
3580
- const nullable = String(c["is_nullable"] ?? "");
3581
- sections.push(`| ${name} | ${type} | ${nullable} |`);
3991
+ sections.push(
3992
+ `| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
3993
+ );
3582
3994
  }
3583
3995
  sections.push("");
3584
3996
  }
@@ -5287,14 +5699,15 @@ function isInternalSchema2(name) {
5287
5699
  function quoteLiteral(value) {
5288
5700
  return "'" + value.replace(/'/g, "''") + "'";
5289
5701
  }
5290
- async function fetchTableNames3(params, schema) {
5702
+ async function fetchTableAndViewNames(params, schema) {
5291
5703
  const rows = await runQuery7(
5292
5704
  params,
5293
- `SELECT tablename FROM pg_tables
5294
- WHERE schemaname = ${quoteLiteral(schema)}
5295
- ORDER BY tablename`
5705
+ `SELECT table_name FROM information_schema.tables
5706
+ WHERE table_schema = ${quoteLiteral(schema)}
5707
+ AND table_type IN ('BASE TABLE', 'VIEW')
5708
+ ORDER BY table_name`
5296
5709
  );
5297
- return rows.map((r) => String(r["tablename"] ?? "")).filter((name) => name);
5710
+ return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
5298
5711
  }
5299
5712
  var redshiftSetupFlow = {
5300
5713
  initialState: () => ({}),
@@ -5309,9 +5722,11 @@ var redshiftSetupFlow = {
5309
5722
  async fetchOptions(_state, rt) {
5310
5723
  const rows = await runQuery7(
5311
5724
  rt.params,
5312
- `SELECT DISTINCT schemaname FROM pg_tables ORDER BY schemaname`
5725
+ `SELECT DISTINCT table_schema FROM information_schema.tables
5726
+ WHERE table_type IN ('BASE TABLE', 'VIEW')
5727
+ ORDER BY table_schema`
5313
5728
  );
5314
- return rows.map((r) => String(r["schemaname"] ?? "")).filter((name) => name && !isInternalSchema2(name)).map((value) => ({ value }));
5729
+ return rows.map((r) => String(r["table_schema"] ?? "")).filter((name) => name && !isInternalSchema2(name)).map((value) => ({ value }));
5315
5730
  },
5316
5731
  applyAnswer: (state, answer) => ({ ...state, schema: answer[0] })
5317
5732
  },
@@ -5319,17 +5734,17 @@ var redshiftSetupFlow = {
5319
5734
  slug: "tables",
5320
5735
  type: "multiSelect",
5321
5736
  question: {
5322
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
5323
- en: "Select target tables (multi-select allowed)"
5737
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
5738
+ en: "Select target tables and views (multi-select allowed)"
5324
5739
  },
5325
5740
  async fetchOptions(state, rt) {
5326
5741
  if (!state.schema) return [];
5327
- const names = await fetchTableNames3(rt.params, state.schema);
5742
+ const names = await fetchTableAndViewNames(rt.params, state.schema);
5328
5743
  const tableOptions = names.map((value) => ({ value }));
5329
5744
  return [
5330
5745
  {
5331
5746
  value: ALL_TABLES7,
5332
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
5747
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
5333
5748
  },
5334
5749
  ...tableOptions
5335
5750
  ];
@@ -5345,9 +5760,21 @@ var redshiftSetupFlow = {
5345
5760
  const targetTables = await resolveSetupSelection({
5346
5761
  selected: state.tables,
5347
5762
  allSentinel: ALL_TABLES7,
5348
- fetchAll: () => fetchTableNames3(rt.params, schema),
5763
+ fetchAll: () => fetchTableAndViewNames(rt.params, schema),
5349
5764
  limit: REDSHIFT_SETUP_MAX_TABLES
5350
5765
  });
5766
+ const typeRows = targetTables.length > 0 ? await runQuery7(
5767
+ rt.params,
5768
+ `SELECT table_name, table_type FROM information_schema.tables
5769
+ WHERE table_schema = ${quoteLiteral(schema)}
5770
+ AND table_name IN (${targetTables.map(quoteLiteral).join(", ")})`
5771
+ ) : [];
5772
+ const typeMap = new Map(
5773
+ typeRows.map((r) => [
5774
+ String(r["table_name"] ?? ""),
5775
+ String(r["table_type"] ?? "BASE TABLE")
5776
+ ])
5777
+ );
5351
5778
  const sections = [
5352
5779
  "## Redshift",
5353
5780
  "",
@@ -5355,6 +5782,7 @@ var redshiftSetupFlow = {
5355
5782
  ""
5356
5783
  ];
5357
5784
  for (const table of targetTables) {
5785
+ const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
5358
5786
  const cols = await runQuery7(
5359
5787
  rt.params,
5360
5788
  `SELECT column_name, data_type, is_nullable, column_default
@@ -5363,7 +5791,7 @@ var redshiftSetupFlow = {
5363
5791
  AND table_name = ${quoteLiteral(table)}
5364
5792
  ORDER BY ordinal_position`
5365
5793
  );
5366
- sections.push(`#### Table: ${table}`, "");
5794
+ sections.push(`#### ${heading}: ${table}`, "");
5367
5795
  sections.push("| Column | Type | Nullable | Default |");
5368
5796
  sections.push("|--------|------|----------|---------|");
5369
5797
  for (const c of cols) {
@@ -5791,8 +6219,8 @@ var databricksSetupFlow = {
5791
6219
  slug: "tables",
5792
6220
  type: "multiSelect",
5793
6221
  question: {
5794
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
5795
- en: "Select target tables (multi-select allowed)"
6222
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
6223
+ en: "Select target tables and views (multi-select allowed)"
5796
6224
  },
5797
6225
  async fetchOptions(state, rt) {
5798
6226
  if (!state.catalog || !state.schema) return [];
@@ -5804,7 +6232,7 @@ var databricksSetupFlow = {
5804
6232
  return [
5805
6233
  {
5806
6234
  value: ALL_TABLES8,
5807
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
6235
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
5808
6236
  },
5809
6237
  ...tableOptions
5810
6238
  ];
@@ -7180,15 +7608,6 @@ var parameters13 = {
7180
7608
  type: "base64EncodedJson",
7181
7609
  secret: true,
7182
7610
  required: true
7183
- }),
7184
- propertyId: new ParameterDefinition({
7185
- slug: "property-id",
7186
- name: "Google Analytics Property ID",
7187
- description: "The Google Analytics 4 property ID (e.g., 123456789).",
7188
- envVarBaseKey: "GA_PROPERTY_ID",
7189
- type: "text",
7190
- secret: false,
7191
- required: true
7192
7611
  })
7193
7612
  };
7194
7613
 
@@ -7196,6 +7615,7 @@ var parameters13 = {
7196
7615
  import * as crypto2 from "crypto";
7197
7616
  var TOKEN_URL = "https://oauth2.googleapis.com/token";
7198
7617
  var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta";
7618
+ var DATA_BASE_URL = "https://analyticsdata.googleapis.com/v1beta";
7199
7619
  var SCOPE = "https://www.googleapis.com/auth/analytics.readonly";
7200
7620
  function base64url(input) {
7201
7621
  const buf = typeof input === "string" ? Buffer.from(input) : input;
@@ -7277,10 +7697,25 @@ async function adminFetch(params, path4, init) {
7277
7697
  headers.set("Authorization", `Bearer ${accessToken}`);
7278
7698
  return fetch(url, { ...init, headers });
7279
7699
  }
7700
+ async function dataFetch(params, path4, init) {
7701
+ const keyJsonBase64 = params[parameters13.serviceAccountKeyJsonBase64.slug];
7702
+ if (!keyJsonBase64) {
7703
+ throw new Error(
7704
+ "google-analytics: missing required parameter: service-account-key-json-base64"
7705
+ );
7706
+ }
7707
+ const serviceAccountKey = decodeServiceAccount(keyJsonBase64);
7708
+ const accessToken = await getAccessToken(serviceAccountKey);
7709
+ const url = `${DATA_BASE_URL}${path4.startsWith("/") ? "" : "/"}${path4}`;
7710
+ const headers = new Headers(init?.headers);
7711
+ headers.set("Authorization", `Bearer ${accessToken}`);
7712
+ return fetch(url, { ...init, headers });
7713
+ }
7280
7714
 
7281
7715
  // ../connectors/src/connectors/google-analytics/setup-flow.ts
7282
7716
  var ALL_PROPERTIES = "__ALL_PROPERTIES__";
7283
7717
  var GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES = 20;
7718
+ var METADATA_DISPLAY_LIMIT = 30;
7284
7719
  async function listAccountSummaries(params) {
7285
7720
  const summaries = [];
7286
7721
  let pageToken;
@@ -7307,6 +7742,48 @@ async function getProperty(params, propertyId) {
7307
7742
  if (!res.ok) return null;
7308
7743
  return await res.json();
7309
7744
  }
7745
+ async function getMetadata(params, propertyId) {
7746
+ try {
7747
+ const res = await dataFetch(
7748
+ params,
7749
+ `/properties/${propertyId}/metadata`
7750
+ );
7751
+ if (!res.ok) return { dimensions: [], metrics: [] };
7752
+ const data = await res.json();
7753
+ return {
7754
+ dimensions: data.dimensions ?? [],
7755
+ metrics: data.metrics ?? []
7756
+ };
7757
+ } catch {
7758
+ return { dimensions: [], metrics: [] };
7759
+ }
7760
+ }
7761
+ function appendMetadataSection(sections, dimensions, metrics) {
7762
+ if (dimensions.length > 0) {
7763
+ sections.push(`#### Dimensions (${dimensions.length})`, "");
7764
+ for (const d of dimensions.slice(0, METADATA_DISPLAY_LIMIT)) {
7765
+ sections.push(`- ${d.apiName ?? d.uiName ?? "(unknown)"}`);
7766
+ }
7767
+ if (dimensions.length > METADATA_DISPLAY_LIMIT) {
7768
+ sections.push(
7769
+ `- \u2026and ${dimensions.length - METADATA_DISPLAY_LIMIT} more`
7770
+ );
7771
+ }
7772
+ sections.push("");
7773
+ }
7774
+ if (metrics.length > 0) {
7775
+ sections.push(`#### Metrics (${metrics.length})`, "");
7776
+ for (const m of metrics.slice(0, METADATA_DISPLAY_LIMIT)) {
7777
+ sections.push(`- ${m.apiName ?? m.uiName ?? "(unknown)"}`);
7778
+ }
7779
+ if (metrics.length > METADATA_DISPLAY_LIMIT) {
7780
+ sections.push(
7781
+ `- \u2026and ${metrics.length - METADATA_DISPLAY_LIMIT} more`
7782
+ );
7783
+ }
7784
+ sections.push("");
7785
+ }
7786
+ }
7310
7787
  var googleAnalyticsSetupFlow = {
7311
7788
  initialState: () => ({}),
7312
7789
  steps: [
@@ -7318,15 +7795,19 @@ var googleAnalyticsSetupFlow = {
7318
7795
  en: "Select a Google Analytics account"
7319
7796
  },
7320
7797
  async fetchOptions(_state, rt) {
7321
- const summaries = await listAccountSummaries(rt.params);
7322
- return summaries.map((s) => {
7323
- const accountResource = s.account ?? s.name ?? "";
7324
- if (!accountResource) return null;
7325
- return {
7326
- value: accountResource,
7327
- label: s.displayName ?? accountResource
7328
- };
7329
- }).filter((v) => v != null);
7798
+ try {
7799
+ const summaries = await listAccountSummaries(rt.params);
7800
+ return summaries.map((s) => {
7801
+ const accountResource = s.account ?? s.name ?? "";
7802
+ if (!accountResource) return null;
7803
+ return {
7804
+ value: accountResource,
7805
+ label: s.displayName ?? accountResource
7806
+ };
7807
+ }).filter((v) => v != null);
7808
+ } catch {
7809
+ return [];
7810
+ }
7330
7811
  },
7331
7812
  applyAnswer: (state, answer) => ({ ...state, account: answer[0] })
7332
7813
  },
@@ -7339,68 +7820,117 @@ var googleAnalyticsSetupFlow = {
7339
7820
  },
7340
7821
  async fetchOptions(state, rt) {
7341
7822
  if (!state.account) return [];
7342
- const summaries = await listAccountSummaries(rt.params);
7343
- const account = summaries.find(
7344
- (s) => (s.account ?? s.name) === state.account
7345
- );
7346
- const props = (account?.propertySummaries ?? []).map((p) => {
7347
- const id = propertyIdFromResource(p.property);
7348
- if (!id) return null;
7349
- return {
7350
- value: id,
7351
- label: p.displayName ? `${p.displayName} (${id})` : id
7352
- };
7353
- }).filter((v) => v != null);
7354
- if (props.length === 0) return [];
7355
- return [
7356
- {
7357
- value: ALL_PROPERTIES,
7358
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
7359
- },
7360
- ...props
7361
- ];
7823
+ try {
7824
+ const summaries = await listAccountSummaries(rt.params);
7825
+ const account = summaries.find(
7826
+ (s) => (s.account ?? s.name) === state.account
7827
+ );
7828
+ const props = (account?.propertySummaries ?? []).map((p) => {
7829
+ const id = propertyIdFromResource(p.property);
7830
+ if (!id) return null;
7831
+ return {
7832
+ value: id,
7833
+ label: p.displayName ? `${p.displayName} (${id})` : id
7834
+ };
7835
+ }).filter((v) => v != null);
7836
+ if (props.length === 0) return [];
7837
+ return [
7838
+ {
7839
+ value: ALL_PROPERTIES,
7840
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
7841
+ },
7842
+ ...props
7843
+ ];
7844
+ } catch {
7845
+ return [];
7846
+ }
7362
7847
  },
7363
7848
  applyAnswer: (state, answer) => ({ ...state, properties: answer })
7849
+ },
7850
+ {
7851
+ slug: "manualPropertyId",
7852
+ type: "text",
7853
+ question: {
7854
+ ja: "GA4 \u30D7\u30ED\u30D1\u30C6\u30A3 ID \u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: 123456789\uFF09\u3002GA4 \u7BA1\u7406\u753B\u9762 > \u30D7\u30ED\u30D1\u30C6\u30A3\u8A2D\u5B9A\u3067\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002",
7855
+ en: "Enter your GA4 Property ID (e.g., 123456789). Found in GA4 Admin > Property Settings."
7856
+ },
7857
+ async fetchOptions(state) {
7858
+ if (state.properties?.length) return [];
7859
+ return [{ value: "_show", label: "" }];
7860
+ },
7861
+ applyAnswer: (state, answer) => ({
7862
+ ...state,
7863
+ manualPropertyId: answer[0]
7864
+ })
7364
7865
  }
7365
7866
  ],
7366
7867
  async finalize(state, rt) {
7367
- if (!state.account || !state.properties) {
7368
- throw new Error("Google Analytics setup: incomplete state on finalize");
7369
- }
7370
- const summaries = await listAccountSummaries(rt.params);
7371
- const account = summaries.find(
7372
- (s) => (s.account ?? s.name) === state.account
7373
- );
7374
- const accountLabel2 = account?.displayName ?? state.account.replace(/^accounts\//, "");
7375
- const targetPropertyIds = await resolveSetupSelection({
7376
- selected: state.properties,
7377
- allSentinel: ALL_PROPERTIES,
7378
- fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
7379
- limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
7380
- });
7381
- const sections = [
7382
- "## Google Analytics",
7383
- "",
7384
- `### Account: ${accountLabel2}`,
7385
- ""
7386
- ];
7387
- if (targetPropertyIds.length === 0) {
7388
- sections.push("_No properties selected._", "");
7868
+ const sections = ["## Google Analytics", ""];
7869
+ if (state.account && state.properties) {
7870
+ let summaries = [];
7871
+ try {
7872
+ summaries = await listAccountSummaries(rt.params);
7873
+ } catch {
7874
+ }
7875
+ const account = summaries.find(
7876
+ (s) => (s.account ?? s.name) === state.account
7877
+ );
7878
+ const accountLabel2 = account?.displayName ?? state.account.replace(/^accounts\//, "");
7879
+ const targetPropertyIds = await resolveSetupSelection({
7880
+ selected: state.properties,
7881
+ allSentinel: ALL_PROPERTIES,
7882
+ fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
7883
+ limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
7884
+ });
7885
+ sections.push(`### Account: ${accountLabel2}`, "");
7886
+ if (targetPropertyIds.length === 0) {
7887
+ sections.push("_No properties selected._", "");
7888
+ return sections.join("\n");
7889
+ }
7890
+ sections.push(
7891
+ "| Property ID | Display Name | Time Zone | Currency | Industry |"
7892
+ );
7893
+ sections.push(
7894
+ "|-------------|--------------|-----------|----------|----------|"
7895
+ );
7896
+ for (const pid of targetPropertyIds) {
7897
+ const prop = await getProperty(rt.params, pid).catch(() => null);
7898
+ const displayName3 = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
7899
+ const timeZone = prop?.timeZone ?? "-";
7900
+ const currency = prop?.currencyCode ?? "-";
7901
+ const industry = (prop?.industryCategory ?? "-").replace(
7902
+ /\|/g,
7903
+ "\\|"
7904
+ );
7905
+ sections.push(
7906
+ `| ${pid} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
7907
+ );
7908
+ }
7909
+ sections.push("");
7910
+ const firstPropertyId = targetPropertyIds[0];
7911
+ if (firstPropertyId) {
7912
+ const { dimensions, metrics } = await getMetadata(
7913
+ rt.params,
7914
+ firstPropertyId
7915
+ );
7916
+ appendMetadataSection(sections, dimensions, metrics);
7917
+ }
7389
7918
  return sections.join("\n");
7390
7919
  }
7391
- sections.push("| Property ID | Display Name | Time Zone | Currency | Industry |");
7392
- sections.push("|-------------|--------------|-----------|----------|----------|");
7393
- for (const propertyId of targetPropertyIds) {
7394
- const prop = await getProperty(rt.params, propertyId);
7395
- const displayName3 = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
7396
- const timeZone = prop?.timeZone ?? "-";
7397
- const currency = prop?.currencyCode ?? "-";
7398
- const industry = (prop?.industryCategory ?? "-").replace(/\|/g, "\\|");
7399
- sections.push(
7400
- `| ${propertyId} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
7920
+ const propertyId = state.manualPropertyId;
7921
+ if (propertyId) {
7922
+ sections.push(`### Property: ${propertyId}`, "");
7923
+ const { dimensions, metrics } = await getMetadata(
7924
+ rt.params,
7925
+ propertyId
7401
7926
  );
7927
+ appendMetadataSection(sections, dimensions, metrics);
7928
+ return sections.join("\n");
7402
7929
  }
7403
- sections.push("");
7930
+ sections.push(
7931
+ "_Could not list GA4 accounts. Please enable the Google Analytics Admin API in your GCP project. Property ID can be specified per request at runtime._",
7932
+ ""
7933
+ );
7404
7934
  return sections.join("\n");
7405
7935
  }
7406
7936
  };
@@ -7412,8 +7942,9 @@ var REQUEST_TIMEOUT_MS10 = 6e4;
7412
7942
  var inputSchema20 = z20.object({
7413
7943
  toolUseIntent: z20.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
7414
7944
  connectionId: z20.string().describe("ID of the Google Analytics connection to use"),
7945
+ propertyId: z20.string().describe("GA4 property ID (e.g., '123456789')"),
7415
7946
  method: z20.enum(["GET", "POST"]).describe("HTTP method"),
7416
- path: z20.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."),
7947
+ path: z20.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is replaced with the propertyId parameter."),
7417
7948
  body: z20.record(z20.string(), z20.unknown()).optional().describe("POST request body (JSON)")
7418
7949
  });
7419
7950
  var outputSchema20 = z20.discriminatedUnion("success", [
@@ -7431,10 +7962,10 @@ var requestTool3 = new ConnectorTool({
7431
7962
  name: "request",
7432
7963
  description: `Send authenticated requests to the Google Analytics Data API.
7433
7964
  Authentication is handled automatically using a service account.
7434
- {propertyId} in the path is automatically replaced with the connection's property-id.`,
7965
+ {propertyId} in the path is automatically replaced with the propertyId parameter.`,
7435
7966
  inputSchema: inputSchema20,
7436
7967
  outputSchema: outputSchema20,
7437
- async execute({ connectionId, method, path: path4, body }, connections) {
7968
+ async execute({ connectionId, propertyId, method, path: path4, body }, connections) {
7438
7969
  const connection = connections.find((c) => c.id === connectionId);
7439
7970
  if (!connection) {
7440
7971
  return { success: false, error: `Connection ${connectionId} not found` };
@@ -7443,7 +7974,6 @@ Authentication is handled automatically using a service account.
7443
7974
  try {
7444
7975
  const { GoogleAuth } = await import("google-auth-library");
7445
7976
  const keyJsonBase64 = parameters13.serviceAccountKeyJsonBase64.getValue(connection);
7446
- const propertyId = parameters13.propertyId.getValue(connection);
7447
7977
  const credentials = JSON.parse(
7448
7978
  Buffer.from(keyJsonBase64, "base64").toString("utf-8")
7449
7979
  );
@@ -7503,16 +8033,16 @@ var googleAnalyticsConnector = new ConnectorPlugin({
7503
8033
  systemPrompt: {
7504
8034
  en: `### Tools
7505
8035
 
7506
- - \`google-analytics-service-account_request\`: The only way to call the GA4 Data API. Use it to fetch metadata, run reports, or run realtime reports. See the GA4 Data API Reference below for available endpoints and request bodies.
8036
+ - \`google-analytics-service-account_request\`: The only way to call the GA4 Data API. Use it to fetch metadata, run reports, or run realtime reports. Requires a \`propertyId\` parameter. See the GA4 Data API Reference below for available endpoints and request bodies.
7507
8037
 
7508
8038
  ### Business Logic
7509
8039
 
7510
8040
  The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
7511
8041
 
7512
8042
  SDK methods (client created via \`connection(connectionId)\`):
7513
- - \`client.runReport(request)\` \u2014 run a GA4 report
7514
- - \`client.runRealtimeReport(request)\` \u2014 run a realtime report
7515
- - \`client.getMetadata()\` \u2014 fetch available dimensions/metrics
8043
+ - \`client.runReport(propertyId, request)\` \u2014 run a GA4 report
8044
+ - \`client.runRealtimeReport(propertyId, request)\` \u2014 run a realtime report
8045
+ - \`client.getMetadata(propertyId)\` \u2014 fetch available dimensions/metrics
7516
8046
  - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
7517
8047
 
7518
8048
  \`\`\`ts
@@ -7522,12 +8052,13 @@ import { connection } from "@squadbase/vite-server/connectors/google-analytics";
7522
8052
  const ga = connection("<connectionId>");
7523
8053
 
7524
8054
  export default async function handler(c: Context) {
7525
- const { startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8055
+ const { propertyId, startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8056
+ propertyId: string;
7526
8057
  startDate?: string;
7527
8058
  endDate?: string;
7528
8059
  }>();
7529
8060
 
7530
- const { rows } = await ga.runReport({
8061
+ const { rows } = await ga.runReport(propertyId, {
7531
8062
  dateRanges: [{ startDate, endDate }],
7532
8063
  dimensions: [{ name: "date" }],
7533
8064
  metrics: [{ name: "activeUsers" }, { name: "sessions" }],
@@ -7571,16 +8102,16 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
7571
8102
  - Relative: \`"today"\`, \`"yesterday"\`, \`"7daysAgo"\`, \`"30daysAgo"\``,
7572
8103
  ja: `### \u30C4\u30FC\u30EB
7573
8104
 
7574
- - \`google-analytics-service-account_request\`: GA4 Data API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30E1\u30BF\u30C7\u30FC\u30BF\u306E\u53D6\u5F97\u3001\u30EC\u30DD\u30FC\u30C8\u306E\u5B9F\u884C\u3001\u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u306E\u5B9F\u884C\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3068\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u306F\u4E0B\u90E8\u306E\u300CGA4 Data API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
8105
+ - \`google-analytics-service-account_request\`: GA4 Data API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30E1\u30BF\u30C7\u30FC\u30BF\u306E\u53D6\u5F97\u3001\u30EC\u30DD\u30FC\u30C8\u306E\u5B9F\u884C\u3001\u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u306E\u5B9F\u884C\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\`propertyId\` \u30D1\u30E9\u30E1\u30FC\u30BF\u30FC\u304C\u5FC5\u8981\u3067\u3059\u3002\u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3068\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u306F\u4E0B\u90E8\u306E\u300CGA4 Data API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
7575
8106
 
7576
8107
  ### Business Logic
7577
8108
 
7578
8109
  \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
7579
8110
 
7580
8111
  SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
7581
- - \`client.runReport(request)\` \u2014 GA4\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
7582
- - \`client.runRealtimeReport(request)\` \u2014 \u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
7583
- - \`client.getMetadata()\` \u2014 \u5229\u7528\u53EF\u80FD\u306A\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3/\u30E1\u30C8\u30EA\u30AF\u30B9\u3092\u53D6\u5F97
8112
+ - \`client.runReport(propertyId, request)\` \u2014 GA4\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
8113
+ - \`client.runRealtimeReport(propertyId, request)\` \u2014 \u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
8114
+ - \`client.getMetadata(propertyId)\` \u2014 \u5229\u7528\u53EF\u80FD\u306A\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3/\u30E1\u30C8\u30EA\u30AF\u30B9\u3092\u53D6\u5F97
7584
8115
  - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
7585
8116
 
7586
8117
  \`\`\`ts
@@ -7590,12 +8121,13 @@ import { connection } from "@squadbase/vite-server/connectors/google-analytics";
7590
8121
  const ga = connection("<connectionId>");
7591
8122
 
7592
8123
  export default async function handler(c: Context) {
7593
- const { startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8124
+ const { propertyId, startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8125
+ propertyId: string;
7594
8126
  startDate?: string;
7595
8127
  endDate?: string;
7596
8128
  }>();
7597
8129
 
7598
- const { rows } = await ga.runReport({
8130
+ const { rows } = await ga.runReport(propertyId, {
7599
8131
  dateRanges: [{ startDate, endDate }],
7600
8132
  dimensions: [{ name: "date" }],
7601
8133
  metrics: [{ name: "activeUsers" }, { name: "sessions" }],
@@ -7649,12 +8181,12 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
7649
8181
  };
7650
8182
  }
7651
8183
  try {
7652
- const res = await adminFetch(params, "/accountSummaries?pageSize=1");
8184
+ const res = await dataFetch(params, `/metadata`);
7653
8185
  if (!res.ok) {
7654
8186
  const body = await res.text().catch(() => res.statusText);
7655
8187
  return {
7656
8188
  success: false,
7657
- error: `google-analytics: accountSummaries failed (${res.status}): ${body}`
8189
+ error: `Google Analytics API failed: HTTP ${res.status} ${body}`
7658
8190
  };
7659
8191
  }
7660
8192
  return { success: true };
@@ -19294,7 +19826,7 @@ function escapeIdentifier(name) {
19294
19826
  function quoteLiteral2(value) {
19295
19827
  return "'" + value.replace(/'/g, "''") + "'";
19296
19828
  }
19297
- async function fetchTableNames4(params, database) {
19829
+ async function fetchTableNames3(params, database) {
19298
19830
  const rows = await runQuery9(
19299
19831
  params,
19300
19832
  `SELECT name FROM system.tables
@@ -19323,17 +19855,17 @@ var clickhouseSetupFlow = {
19323
19855
  slug: "tables",
19324
19856
  type: "multiSelect",
19325
19857
  question: {
19326
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
19327
- en: "Select target tables (multi-select allowed)"
19858
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
19859
+ en: "Select target tables and views (multi-select allowed)"
19328
19860
  },
19329
19861
  async fetchOptions(state, rt) {
19330
19862
  if (!state.database) return [];
19331
- const names = await fetchTableNames4(rt.params, state.database);
19863
+ const names = await fetchTableNames3(rt.params, state.database);
19332
19864
  const tableOptions = names.map((value) => ({ value }));
19333
19865
  return [
19334
19866
  {
19335
19867
  value: ALL_TABLES11,
19336
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
19868
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
19337
19869
  },
19338
19870
  ...tableOptions
19339
19871
  ];
@@ -19349,7 +19881,7 @@ var clickhouseSetupFlow = {
19349
19881
  const targetTables = await resolveSetupSelection({
19350
19882
  selected: state.tables,
19351
19883
  allSentinel: ALL_TABLES11,
19352
- fetchAll: () => fetchTableNames4(rt.params, database),
19884
+ fetchAll: () => fetchTableNames3(rt.params, database),
19353
19885
  limit: CLICKHOUSE_SETUP_MAX_TABLES
19354
19886
  });
19355
19887
  const sections = [
@@ -23948,7 +24480,7 @@ export default async function handler(c: Context) {
23948
24480
  const region = params[parameters50.region.slug];
23949
24481
  const baseUrl = region === "eu" ? "https://api-eu.customer.io" : "https://api.customer.io";
23950
24482
  try {
23951
- const res = await fetch(`${baseUrl}/v1/accounts/region`, {
24483
+ const res = await fetch(`${baseUrl}/v1/segments`, {
23952
24484
  method: "GET",
23953
24485
  headers: {
23954
24486
  Authorization: `Bearer ${appApiKey}`,
@@ -29504,7 +30036,7 @@ function apiFetch27(params, path4, init) {
29504
30036
  // ../connectors/src/connectors/gamma/setup-flow.ts
29505
30037
  var ALL_FOLDERS = "__ALL_FOLDERS__";
29506
30038
  var GAMMA_SETUP_MAX_FOLDERS = 20;
29507
- var FOLDERS_PAGE_LIMIT = 100;
30039
+ var FOLDERS_PAGE_LIMIT = 50;
29508
30040
  async function listAllFolders(params) {
29509
30041
  const results = [];
29510
30042
  let after;
@@ -29525,7 +30057,7 @@ async function listAllFolders(params) {
29525
30057
  return results;
29526
30058
  }
29527
30059
  async function listThemes(params) {
29528
- const res = await apiFetch27(params, "/themes?limit=100");
30060
+ const res = await apiFetch27(params, "/themes?limit=50");
29529
30061
  if (!res.ok) {
29530
30062
  return [];
29531
30063
  }
@@ -33362,7 +33894,8 @@ var semrushOnboarding = new ConnectorOnboarding({
33362
33894
  });
33363
33895
 
33364
33896
  // ../connectors/src/connectors/semrush/utils.ts
33365
- var PROJECTS_BASE_URL = "https://api.semrush.com/management/v1";
33897
+ var BASE_URL59 = "https://api.semrush.com";
33898
+ var PROJECTS_BASE_URL = `${BASE_URL59}/management/v1`;
33366
33899
  function projectsApiFetch(params, path4, init) {
33367
33900
  const apiKey = params[parameters68.apiKey.slug];
33368
33901
  if (!apiKey) {
@@ -33379,10 +33912,103 @@ function projectsApiFetch(params, path4, init) {
33379
33912
  if (!headers.has("Accept")) headers.set("Accept", "application/json");
33380
33913
  return fetch(url.toString(), { ...init, headers });
33381
33914
  }
33915
+ async function reportFetch(params, query) {
33916
+ const apiKey = params[parameters68.apiKey.slug];
33917
+ if (!apiKey) {
33918
+ throw new Error(
33919
+ `semrush: missing required parameter: ${parameters68.apiKey.slug}`
33920
+ );
33921
+ }
33922
+ const url = new URL(`${BASE_URL59}/`);
33923
+ for (const [k, v] of Object.entries(query)) {
33924
+ url.searchParams.set(k, v);
33925
+ }
33926
+ url.searchParams.set("key", apiKey);
33927
+ const res = await fetch(url.toString());
33928
+ const text = await res.text();
33929
+ if (text.startsWith("ERROR ")) throw new Error(text.trim());
33930
+ return parseSemicolonCsv(text);
33931
+ }
33932
+ async function backlinksFetch(params, query) {
33933
+ const apiKey = params[parameters68.apiKey.slug];
33934
+ if (!apiKey) {
33935
+ throw new Error(
33936
+ `semrush: missing required parameter: ${parameters68.apiKey.slug}`
33937
+ );
33938
+ }
33939
+ const url = new URL(`${BASE_URL59}/analytics/v1/`);
33940
+ for (const [k, v] of Object.entries(query)) {
33941
+ url.searchParams.set(k, v);
33942
+ }
33943
+ url.searchParams.set("key", apiKey);
33944
+ const res = await fetch(url.toString());
33945
+ const text = await res.text();
33946
+ if (text.startsWith("ERROR ")) throw new Error(text.trim());
33947
+ return parseSemicolonCsv(text);
33948
+ }
33949
+ function parseSemicolonCsv(raw) {
33950
+ const lines = raw.trim().split("\n").filter(Boolean);
33951
+ if (lines.length === 0) return { columns: [], rows: [] };
33952
+ const columns = lines[0].split(";");
33953
+ const rows = lines.slice(1).map((line) => {
33954
+ const values = line.split(";");
33955
+ const row = {};
33956
+ for (let i = 0; i < columns.length; i++) {
33957
+ row[columns[i]] = values[i] ?? "";
33958
+ }
33959
+ return row;
33960
+ });
33961
+ return { columns, rows };
33962
+ }
33382
33963
 
33383
33964
  // ../connectors/src/connectors/semrush/setup-flow.ts
33384
33965
  var ALL_PROJECTS6 = "__ALL_PROJECTS__";
33385
33966
  var SEMRUSH_SETUP_MAX_PROJECTS = 10;
33967
+ var SEMRUSH_DATABASES = [
33968
+ { value: "us", label: "United States" },
33969
+ { value: "uk", label: "United Kingdom" },
33970
+ { value: "ca", label: "Canada" },
33971
+ { value: "au", label: "Australia" },
33972
+ { value: "de", label: "Germany" },
33973
+ { value: "fr", label: "France" },
33974
+ { value: "es", label: "Spain" },
33975
+ { value: "it", label: "Italy" },
33976
+ { value: "br", label: "Brazil" },
33977
+ { value: "jp", label: "Japan" },
33978
+ { value: "in", label: "India" },
33979
+ { value: "ru", label: "Russia" },
33980
+ { value: "nl", label: "Netherlands" },
33981
+ { value: "se", label: "Sweden" },
33982
+ { value: "mx", label: "Mexico" },
33983
+ { value: "kr", label: "South Korea" },
33984
+ { value: "sg", label: "Singapore" },
33985
+ { value: "hk", label: "Hong Kong" },
33986
+ { value: "tw", label: "Taiwan" }
33987
+ ];
33988
+ var REPORT_TYPE_LABELS = {
33989
+ domain_overview: {
33990
+ en: "Domain Overview (rank, traffic, keyword count)",
33991
+ ja: "Domain Overview (\u30E9\u30F3\u30AF\u30FB\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u30FB\u30AD\u30FC\u30EF\u30FC\u30C9\u6570)"
33992
+ },
33993
+ organic_search: {
33994
+ en: "Organic Search (top organic keywords)",
33995
+ ja: "Organic Search (\u4E0A\u4F4D\u30AA\u30FC\u30AC\u30CB\u30C3\u30AF\u30AD\u30FC\u30EF\u30FC\u30C9)"
33996
+ },
33997
+ paid_search: {
33998
+ en: "Paid Search (top paid keywords)",
33999
+ ja: "Paid Search (\u4E0A\u4F4D\u6709\u6599\u30AD\u30FC\u30EF\u30FC\u30C9)"
34000
+ },
34001
+ backlinks: {
34002
+ en: "Backlinks (referring domains, backlink count)",
34003
+ ja: "Backlinks (\u53C2\u7167\u30C9\u30E1\u30A4\u30F3\u30FB\u88AB\u30EA\u30F3\u30AF\u6570)"
34004
+ }
34005
+ };
34006
+ var REPORT_TYPE_VALUES = [
34007
+ "domain_overview",
34008
+ "organic_search",
34009
+ "paid_search",
34010
+ "backlinks"
34011
+ ];
33386
34012
  function projectId(p) {
33387
34013
  const raw = p.project_id ?? p.id;
33388
34014
  return raw == null ? "" : String(raw);
@@ -33391,7 +34017,7 @@ function projectName(p) {
33391
34017
  return p.project_name ?? p.name ?? p.domain ?? p.url ?? projectId(p);
33392
34018
  }
33393
34019
  function projectDomain(p) {
33394
- return p.domain ?? p.url ?? "";
34020
+ return p.domain ?? p.domain_unicode ?? p.url ?? "";
33395
34021
  }
33396
34022
  function projectCreatedAt(p) {
33397
34023
  return p.created_at ?? p.date_created ?? "";
@@ -33399,13 +34025,19 @@ function projectCreatedAt(p) {
33399
34025
  async function fetchProjects(params) {
33400
34026
  let res;
33401
34027
  try {
33402
- res = await projectsApiFetch(params, "/projects/");
34028
+ res = await projectsApiFetch(params, "/projects");
33403
34029
  } catch (err) {
33404
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
34030
+ return {
34031
+ ok: false,
34032
+ error: err instanceof Error ? err.message : String(err)
34033
+ };
33405
34034
  }
33406
34035
  if (!res.ok) {
33407
34036
  const body2 = await res.text().catch(() => res.statusText);
33408
- return { ok: false, error: `HTTP ${res.status} ${body2 || res.statusText}` };
34037
+ return {
34038
+ ok: false,
34039
+ error: `HTTP ${res.status} ${body2 || res.statusText}`
34040
+ };
33409
34041
  }
33410
34042
  let body;
33411
34043
  try {
@@ -33419,9 +34051,171 @@ async function fetchProjects(params) {
33419
34051
  const projects = Array.isArray(body) ? body : Array.isArray(body?.projects) ? body.projects : Array.isArray(body?.data) ? body.data : [];
33420
34052
  return { ok: true, projects };
33421
34053
  }
34054
+ function formatNumber(n) {
34055
+ return n.toLocaleString("en-US");
34056
+ }
34057
+ async function fetchDomainOverview(params, domain, database) {
34058
+ const sections = [];
34059
+ try {
34060
+ const report = await reportFetch(params, {
34061
+ type: "domain_ranks",
34062
+ domain,
34063
+ database
34064
+ });
34065
+ if (report.rows.length === 0) {
34066
+ sections.push("_No data found for this domain._", "");
34067
+ return sections;
34068
+ }
34069
+ const row = report.rows[0];
34070
+ sections.push("| Metric | Value |");
34071
+ sections.push("|--------|-------|");
34072
+ sections.push(
34073
+ `| Rank | ${row["Rank"] ?? "-"} |`,
34074
+ `| Organic Keywords | ${formatNumber(Number(row["Organic Keywords"]) || 0)} |`,
34075
+ `| Organic Traffic | ${formatNumber(Number(row["Organic Traffic"]) || 0)} |`,
34076
+ `| Organic Cost | $${formatNumber(Number(row["Organic Cost"]) || 0)} |`,
34077
+ `| Adwords Keywords | ${formatNumber(Number(row["Adwords Keywords"]) || 0)} |`,
34078
+ `| Adwords Traffic | ${formatNumber(Number(row["Adwords Traffic"]) || 0)} |`,
34079
+ `| Adwords Cost | $${formatNumber(Number(row["Adwords Cost"]) || 0)} |`
34080
+ );
34081
+ sections.push("");
34082
+ } catch (err) {
34083
+ sections.push(
34084
+ `_Error: ${err instanceof Error ? err.message : String(err)}_`,
34085
+ ""
34086
+ );
34087
+ }
34088
+ return sections;
34089
+ }
34090
+ async function fetchOrganicSearch(params, domain, database) {
34091
+ return fetchKeywordReport(params, "domain_organic", domain, database);
34092
+ }
34093
+ async function fetchPaidSearch(params, domain, database) {
34094
+ return fetchKeywordReport(params, "domain_adwords", domain, database);
34095
+ }
34096
+ async function fetchKeywordReport(params, type, domain, database) {
34097
+ const sections = [];
34098
+ try {
34099
+ const report = await reportFetch(params, {
34100
+ type,
34101
+ domain,
34102
+ database,
34103
+ display_limit: "5"
34104
+ });
34105
+ if (report.rows.length === 0) {
34106
+ sections.push("_No data found._", "");
34107
+ return sections;
34108
+ }
34109
+ sections.push(...renderCsvTable(report, 5));
34110
+ sections.push("");
34111
+ } catch (err) {
34112
+ sections.push(
34113
+ `_Error: ${err instanceof Error ? err.message : String(err)}_`,
34114
+ ""
34115
+ );
34116
+ }
34117
+ return sections;
34118
+ }
34119
+ async function fetchBacklinks(params, domain) {
34120
+ const sections = [];
34121
+ try {
34122
+ const report = await backlinksFetch(params, {
34123
+ type: "backlinks_overview",
34124
+ target: domain,
34125
+ target_type: "root_domain"
34126
+ });
34127
+ if (report.rows.length === 0) {
34128
+ sections.push("_No backlink data found._", "");
34129
+ return sections;
34130
+ }
34131
+ const row = report.rows[0];
34132
+ sections.push("| Metric | Value |");
34133
+ sections.push("|--------|-------|");
34134
+ for (const col of report.columns) {
34135
+ sections.push(`| ${col} | ${formatNumber(Number(row[col]) || 0)} |`);
34136
+ }
34137
+ sections.push("");
34138
+ } catch (err) {
34139
+ sections.push(
34140
+ `_Error: ${err instanceof Error ? err.message : String(err)}_`,
34141
+ ""
34142
+ );
34143
+ }
34144
+ return sections;
34145
+ }
34146
+ function renderCsvTable(report, maxRows) {
34147
+ const cols = report.columns;
34148
+ const rows = report.rows.slice(0, maxRows);
34149
+ const lines = [];
34150
+ lines.push(`| ${cols.join(" | ")} |`);
34151
+ lines.push(`|${cols.map(() => "---").join("|")}|`);
34152
+ for (const row of rows) {
34153
+ const cells = cols.map((c) => (row[c] ?? "").replace(/\|/g, "\\|"));
34154
+ lines.push(`| ${cells.join(" | ")} |`);
34155
+ }
34156
+ return lines;
34157
+ }
33422
34158
  var semrushSetupFlow = {
33423
34159
  initialState: () => ({}),
33424
34160
  steps: [
34161
+ {
34162
+ slug: "domain",
34163
+ type: "select",
34164
+ allowFreeText: true,
34165
+ question: {
34166
+ ja: "\u5206\u6790\u5BFE\u8C61\u306E\u30C9\u30E1\u30A4\u30F3\u3092\u9078\u629E\u307E\u305F\u306F\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044",
34167
+ en: "Select or enter the domain to analyze"
34168
+ },
34169
+ async fetchOptions(_state, rt) {
34170
+ const result = await fetchProjects(rt.params);
34171
+ if (!result.ok || result.projects.length === 0) return [];
34172
+ const seen = /* @__PURE__ */ new Set();
34173
+ const options = [];
34174
+ for (const p of result.projects) {
34175
+ const d = projectDomain(p);
34176
+ if (d && !seen.has(d)) {
34177
+ seen.add(d);
34178
+ options.push({
34179
+ value: d,
34180
+ label: `${d} (${projectName(p)})`
34181
+ });
34182
+ }
34183
+ }
34184
+ return options;
34185
+ },
34186
+ applyAnswer: (state, answer) => ({ ...state, domain: answer[0] })
34187
+ },
34188
+ {
34189
+ slug: "database",
34190
+ type: "select",
34191
+ allowFreeText: false,
34192
+ question: {
34193
+ ja: "\u30EA\u30FC\u30B8\u30E7\u30F3\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5BFE\u8C61\u30C9\u30E1\u30A4\u30F3\u306E\u4E3B\u8981\u5E02\u5834\uFF09",
34194
+ en: "Select the region (primary market for the target domain)"
34195
+ },
34196
+ async fetchOptions() {
34197
+ return SEMRUSH_DATABASES.map((db) => ({
34198
+ value: db.value,
34199
+ label: `${db.label} (${db.value})`
34200
+ }));
34201
+ },
34202
+ applyAnswer: (state, answer) => ({ ...state, database: answer[0] })
34203
+ },
34204
+ {
34205
+ slug: "reportTypes",
34206
+ type: "multiSelect",
34207
+ question: {
34208
+ ja: "\u63A2\u7D22\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u7A2E\u5225\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
34209
+ en: "Select report types to explore (multi-select allowed)"
34210
+ },
34211
+ async fetchOptions(_state, rt) {
34212
+ return REPORT_TYPE_VALUES.map((value) => ({
34213
+ value,
34214
+ label: REPORT_TYPE_LABELS[value][rt.language]
34215
+ }));
34216
+ },
34217
+ applyAnswer: (state, answer) => ({ ...state, reportTypes: answer })
34218
+ },
33425
34219
  {
33426
34220
  slug: "projects",
33427
34221
  type: "multiSelect",
@@ -33438,7 +34232,9 @@ var semrushSetupFlow = {
33438
34232
  const id = projectId(p);
33439
34233
  if (!id) return null;
33440
34234
  return { value: id, label: projectName(p) };
33441
- }).filter((opt) => opt !== null);
34235
+ }).filter(
34236
+ (opt) => opt !== null
34237
+ );
33442
34238
  if (options.length === 0) return [];
33443
34239
  return [
33444
34240
  {
@@ -33452,49 +34248,80 @@ var semrushSetupFlow = {
33452
34248
  }
33453
34249
  ],
33454
34250
  async finalize(state, rt) {
33455
- const sections = ["## Semrush", ""];
33456
- if (!state.projects?.length) {
34251
+ if (!state.domain || !state.database || !state.reportTypes) {
34252
+ throw new Error("Semrush setup: incomplete state on finalize");
34253
+ }
34254
+ const domain = state.domain;
34255
+ const database = state.database;
34256
+ const selected = state.reportTypes.filter(
34257
+ (r) => REPORT_TYPE_VALUES.includes(r)
34258
+ );
34259
+ const sections = [
34260
+ "## Semrush",
34261
+ "",
34262
+ `**Domain:** ${domain}`,
34263
+ `**Region:** ${database}`,
34264
+ ""
34265
+ ];
34266
+ for (const reportType of selected) {
33457
34267
  sections.push(
33458
- "_No Semrush Projects API access detected; Standard Analytics reports run by domain/keyword and don't require pre-selection._",
34268
+ `### ${REPORT_TYPE_LABELS[reportType].en}`,
33459
34269
  ""
33460
34270
  );
33461
- return sections.join("\n");
33462
- }
33463
- const result = await fetchProjects(rt.params);
33464
- if (!result.ok) {
33465
- throw new Error(
33466
- `semrush: listProjects failed on finalize: ${result.error}`
33467
- );
33468
- }
33469
- const projectByIdMap = /* @__PURE__ */ new Map();
33470
- for (const p of result.projects) {
33471
- const id = projectId(p);
33472
- if (id) projectByIdMap.set(id, p);
33473
- }
33474
- const targetIds = await resolveSetupSelection({
33475
- selected: state.projects,
33476
- allSentinel: ALL_PROJECTS6,
33477
- fetchAll: async () => result.projects.map((p) => projectId(p)).filter((id) => id),
33478
- limit: SEMRUSH_SETUP_MAX_PROJECTS
33479
- });
33480
- if (!targetIds.length) {
33481
- sections.push("_No projects selected._", "");
33482
- return sections.join("\n");
34271
+ switch (reportType) {
34272
+ case "domain_overview":
34273
+ sections.push(
34274
+ ...await fetchDomainOverview(rt.params, domain, database)
34275
+ );
34276
+ break;
34277
+ case "organic_search":
34278
+ sections.push(
34279
+ ...await fetchOrganicSearch(rt.params, domain, database)
34280
+ );
34281
+ break;
34282
+ case "paid_search":
34283
+ sections.push(
34284
+ ...await fetchPaidSearch(rt.params, domain, database)
34285
+ );
34286
+ break;
34287
+ case "backlinks":
34288
+ sections.push(...await fetchBacklinks(rt.params, domain));
34289
+ break;
34290
+ }
33483
34291
  }
33484
- sections.push("| Project | Domain | Created |");
33485
- sections.push("|---------|--------|---------|");
33486
- for (const id of targetIds) {
33487
- const p = projectByIdMap.get(id);
33488
- if (!p) {
33489
- sections.push(`| ${id} | - | - |`);
33490
- continue;
34292
+ if (state.projects?.length) {
34293
+ const result = await fetchProjects(rt.params);
34294
+ if (result.ok) {
34295
+ const projectByIdMap = /* @__PURE__ */ new Map();
34296
+ for (const p of result.projects) {
34297
+ const id = projectId(p);
34298
+ if (id) projectByIdMap.set(id, p);
34299
+ }
34300
+ const targetIds = await resolveSetupSelection({
34301
+ selected: state.projects,
34302
+ allSentinel: ALL_PROJECTS6,
34303
+ fetchAll: async () => result.projects.map((p) => projectId(p)).filter((id) => id),
34304
+ limit: SEMRUSH_SETUP_MAX_PROJECTS
34305
+ });
34306
+ if (targetIds.length > 0) {
34307
+ sections.push("### Projects", "");
34308
+ sections.push("| Project | Domain | Created |");
34309
+ sections.push("|---------|--------|---------|");
34310
+ for (const id of targetIds) {
34311
+ const p = projectByIdMap.get(id);
34312
+ if (!p) {
34313
+ sections.push(`| ${id} | - | - |`);
34314
+ continue;
34315
+ }
34316
+ const name = projectName(p).replace(/\|/g, "\\|");
34317
+ const dom = projectDomain(p).replace(/\|/g, "\\|") || "-";
34318
+ const created = projectCreatedAt(p) || "-";
34319
+ sections.push(`| ${name} | ${dom} | ${created} |`);
34320
+ }
34321
+ sections.push("");
34322
+ }
33491
34323
  }
33492
- const name = projectName(p).replace(/\|/g, "\\|");
33493
- const domain = projectDomain(p).replace(/\|/g, "\\|") || "-";
33494
- const created = projectCreatedAt(p) || "-";
33495
- sections.push(`| ${name} | ${domain} | ${created} |`);
33496
34324
  }
33497
- sections.push("");
33498
34325
  return sections.join("\n");
33499
34326
  }
33500
34327
  };
@@ -33755,7 +34582,7 @@ API \u30E6\u30CB\u30C3\u30C8\u6B8B\u91CF\u306E\u78BA\u8A8D\uFF08\u7121\u6599\u30
33755
34582
 
33756
34583
  // ../connectors/src/connectors/google-search-console-oauth/tools/list-sites.ts
33757
34584
  import { z as z84 } from "zod";
33758
- var BASE_URL59 = "https://searchconsole.googleapis.com/webmasters/v3";
34585
+ var BASE_URL60 = "https://searchconsole.googleapis.com/webmasters/v3";
33759
34586
  var REQUEST_TIMEOUT_MS67 = 6e4;
33760
34587
  var cachedToken30 = null;
33761
34588
  async function getProxyToken30(config) {
@@ -33826,7 +34653,7 @@ var listSitesTool = new ConnectorTool({
33826
34653
  `[connector-request] google-search-console-oauth/${connection.name}: listSites`
33827
34654
  );
33828
34655
  try {
33829
- const url = `${BASE_URL59}/sites`;
34656
+ const url = `${BASE_URL60}/sites`;
33830
34657
  const token = await getProxyToken30(config.oauthProxy);
33831
34658
  const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
33832
34659
  const controller = new AbortController();
@@ -34008,7 +34835,7 @@ var googleSearchConsoleOauthSetupFlow = {
34008
34835
  import { z as z85 } from "zod";
34009
34836
  var BASE_HOST10 = "https://searchconsole.googleapis.com";
34010
34837
  var BASE_PATH_SEGMENT10 = "/webmasters/v3";
34011
- var BASE_URL60 = `${BASE_HOST10}${BASE_PATH_SEGMENT10}`;
34838
+ var BASE_URL61 = `${BASE_HOST10}${BASE_PATH_SEGMENT10}`;
34012
34839
  var REQUEST_TIMEOUT_MS68 = 6e4;
34013
34840
  var cachedToken31 = null;
34014
34841
  async function getProxyToken31(config) {
@@ -34093,7 +34920,7 @@ For URL Inspection API requests, use the absolute path '/v1/urlInspection/index:
34093
34920
  resolvedPath,
34094
34921
  BASE_PATH_SEGMENT10
34095
34922
  );
34096
- let url = `${BASE_URL60}${normalizedPath}`;
34923
+ let url = `${BASE_URL61}${normalizedPath}`;
34097
34924
  if (queryParams) {
34098
34925
  const searchParams = new URLSearchParams(queryParams);
34099
34926
  url += `?${searchParams.toString()}`;
@@ -34419,7 +35246,7 @@ function isInternalSchema3(name) {
34419
35246
  if (lower.startsWith("pg_toast_")) return true;
34420
35247
  return false;
34421
35248
  }
34422
- async function fetchTableNames5(params, schema) {
35249
+ async function fetchTableNames4(params, schema) {
34423
35250
  const rows = await runQuery10(
34424
35251
  params,
34425
35252
  `SELECT table_name FROM information_schema.tables
@@ -34452,17 +35279,17 @@ var supabaseSetupFlow = {
34452
35279
  slug: "tables",
34453
35280
  type: "multiSelect",
34454
35281
  question: {
34455
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
34456
- en: "Select target tables (multi-select allowed)"
35282
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
35283
+ en: "Select target tables and views (multi-select allowed)"
34457
35284
  },
34458
35285
  async fetchOptions(state, rt) {
34459
35286
  if (!state.schema) return [];
34460
- const names = await fetchTableNames5(rt.params, state.schema);
35287
+ const names = await fetchTableNames4(rt.params, state.schema);
34461
35288
  const tableOptions = names.map((value) => ({ value }));
34462
35289
  return [
34463
35290
  {
34464
35291
  value: ALL_TABLES13,
34465
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
35292
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
34466
35293
  },
34467
35294
  ...tableOptions
34468
35295
  ];
@@ -34478,7 +35305,7 @@ var supabaseSetupFlow = {
34478
35305
  const targetTables = await resolveSetupSelection({
34479
35306
  selected: state.tables,
34480
35307
  allSentinel: ALL_TABLES13,
34481
- fetchAll: () => fetchTableNames5(rt.params, schema),
35308
+ fetchAll: () => fetchTableNames4(rt.params, schema),
34482
35309
  limit: SUPABASE_SETUP_MAX_TABLES
34483
35310
  });
34484
35311
  const sections = [
@@ -34713,13 +35540,13 @@ var parameters71 = {
34713
35540
  };
34714
35541
 
34715
35542
  // ../connectors/src/connectors/clickup/utils.ts
34716
- var BASE_URL61 = "https://api.clickup.com/api/v2";
35543
+ var BASE_URL62 = "https://api.clickup.com/api/v2";
34717
35544
  async function apiFetch30(params, path4, init) {
34718
35545
  const token = params[parameters71.apiToken.slug];
34719
35546
  if (!token) {
34720
35547
  throw new Error("clickup: missing required parameter: api-token");
34721
35548
  }
34722
- const url = `${BASE_URL61}${path4.startsWith("/") ? "" : "/"}${path4}`;
35549
+ const url = `${BASE_URL62}${path4.startsWith("/") ? "" : "/"}${path4}`;
34723
35550
  const headers = new Headers(init?.headers);
34724
35551
  headers.set("Authorization", token);
34725
35552
  if (!headers.has("Accept")) headers.set("Accept", "application/json");
@@ -34847,7 +35674,7 @@ var clickupSetupFlow = {
34847
35674
  import { z as z87 } from "zod";
34848
35675
  var BASE_HOST11 = "https://api.clickup.com";
34849
35676
  var BASE_PATH_SEGMENT11 = "/api/v2";
34850
- var BASE_URL62 = `${BASE_HOST11}${BASE_PATH_SEGMENT11}`;
35677
+ var BASE_URL63 = `${BASE_HOST11}${BASE_PATH_SEGMENT11}`;
34851
35678
  var REQUEST_TIMEOUT_MS69 = 6e4;
34852
35679
  var inputSchema87 = z87.object({
34853
35680
  toolUseIntent: z87.string().optional().describe(
@@ -34920,7 +35747,7 @@ Pagination: ClickUp uses zero-indexed \`page\` query parameter on list endpoints
34920
35747
  try {
34921
35748
  const token = parameters71.apiToken.getValue(connection);
34922
35749
  const normalizedPath = normalizeRequestPath(path4, BASE_PATH_SEGMENT11);
34923
- const url = `${BASE_URL62}${normalizedPath}`;
35750
+ const url = `${BASE_URL63}${normalizedPath}`;
34924
35751
  const controller = new AbortController();
34925
35752
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS69);
34926
35753
  try {
@@ -35250,7 +36077,7 @@ function quoteLiteral4(value) {
35250
36077
  }
35251
36078
  function buildFlow(options) {
35252
36079
  const { connectorName, forceEncrypt } = options;
35253
- async function fetchTableNames7(params, schema) {
36080
+ async function fetchTableNames5(params, schema) {
35254
36081
  const rows = await runSqlServerSetupQuery(
35255
36082
  params,
35256
36083
  `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
@@ -35285,17 +36112,17 @@ function buildFlow(options) {
35285
36112
  slug: "tables",
35286
36113
  type: "multiSelect",
35287
36114
  question: {
35288
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
35289
- en: "Select target tables (multi-select allowed)"
36115
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
36116
+ en: "Select target tables and views (multi-select allowed)"
35290
36117
  },
35291
36118
  async fetchOptions(state, rt) {
35292
36119
  if (!state.schema) return [];
35293
- const names = await fetchTableNames7(rt.params, state.schema);
36120
+ const names = await fetchTableNames5(rt.params, state.schema);
35294
36121
  const tableOptions = names.map((value) => ({ value }));
35295
36122
  return [
35296
36123
  {
35297
36124
  value: ALL_TABLES14,
35298
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
36125
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
35299
36126
  },
35300
36127
  ...tableOptions
35301
36128
  ];
@@ -35311,7 +36138,7 @@ function buildFlow(options) {
35311
36138
  const targetTables = await resolveSetupSelection({
35312
36139
  selected: state.tables,
35313
36140
  allSentinel: ALL_TABLES14,
35314
- fetchAll: () => fetchTableNames7(rt.params, schema),
36141
+ fetchAll: () => fetchTableNames5(rt.params, schema),
35315
36142
  limit: SQLSERVER_SETUP_MAX_TABLES
35316
36143
  });
35317
36144
  const sections = [
@@ -36306,14 +37133,15 @@ function isInternalOwner(name) {
36306
37133
  function quoteLiteral5(value) {
36307
37134
  return "'" + value.replace(/'/g, "''") + "'";
36308
37135
  }
36309
- async function fetchTableNames6(params, owner) {
37136
+ async function fetchTableAndViewNames2(params, owner) {
36310
37137
  const rows = await runOracleSetupQuery(
36311
37138
  params,
36312
- `SELECT TABLE_NAME FROM ALL_TABLES
36313
- WHERE OWNER = ${quoteLiteral5(owner)}
36314
- ORDER BY TABLE_NAME`
37139
+ `SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = ${quoteLiteral5(owner)}
37140
+ UNION
37141
+ SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER = ${quoteLiteral5(owner)}
37142
+ ORDER BY 1`
36315
37143
  );
36316
- return rows.map((r) => String(r["TABLE_NAME"] ?? "")).filter((name) => name);
37144
+ return rows.map((r) => String(r["TABLE_NAME"] ?? r["VIEW_NAME"] ?? "")).filter((name) => name);
36317
37145
  }
36318
37146
  var oracleSetupFlow = {
36319
37147
  initialState: () => ({}),
@@ -36338,17 +37166,17 @@ var oracleSetupFlow = {
36338
37166
  slug: "tables",
36339
37167
  type: "multiSelect",
36340
37168
  question: {
36341
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
36342
- en: "Select target tables (multi-select allowed)"
37169
+ ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
37170
+ en: "Select target tables and views (multi-select allowed)"
36343
37171
  },
36344
37172
  async fetchOptions(state, rt) {
36345
37173
  if (!state.owner) return [];
36346
- const names = await fetchTableNames6(rt.params, state.owner);
37174
+ const names = await fetchTableAndViewNames2(rt.params, state.owner);
36347
37175
  const tableOptions = names.map((value) => ({ value }));
36348
37176
  return [
36349
37177
  {
36350
37178
  value: ALL_TABLES15,
36351
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
37179
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
36352
37180
  },
36353
37181
  ...tableOptions
36354
37182
  ];
@@ -36364,9 +37192,22 @@ var oracleSetupFlow = {
36364
37192
  const targetTables = await resolveSetupSelection({
36365
37193
  selected: state.tables,
36366
37194
  allSentinel: ALL_TABLES15,
36367
- fetchAll: () => fetchTableNames6(rt.params, owner),
37195
+ fetchAll: () => fetchTableAndViewNames2(rt.params, owner),
36368
37196
  limit: ORACLE_SETUP_MAX_TABLES
36369
37197
  });
37198
+ const typeRows = targetTables.length > 0 ? await runOracleSetupQuery(
37199
+ rt.params,
37200
+ `SELECT OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS
37201
+ WHERE OWNER = ${quoteLiteral5(owner)}
37202
+ AND OBJECT_NAME IN (${targetTables.map(quoteLiteral5).join(", ")})
37203
+ AND OBJECT_TYPE IN ('TABLE', 'VIEW')`
37204
+ ) : [];
37205
+ const typeMap = new Map(
37206
+ typeRows.map((r) => [
37207
+ String(r["OBJECT_NAME"] ?? ""),
37208
+ String(r["OBJECT_TYPE"] ?? "TABLE")
37209
+ ])
37210
+ );
36370
37211
  const sections = [
36371
37212
  "## Oracle Database",
36372
37213
  "",
@@ -36374,6 +37215,7 @@ var oracleSetupFlow = {
36374
37215
  ""
36375
37216
  ];
36376
37217
  for (const table of targetTables) {
37218
+ const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
36377
37219
  const cols = await runOracleSetupQuery(
36378
37220
  rt.params,
36379
37221
  `SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
@@ -36382,7 +37224,7 @@ var oracleSetupFlow = {
36382
37224
  AND TABLE_NAME = ${quoteLiteral5(table)}
36383
37225
  ORDER BY COLUMN_ID`
36384
37226
  );
36385
- sections.push(`#### Table: ${table}`, "");
37227
+ sections.push(`#### ${heading}: ${table}`, "");
36386
37228
  sections.push("| Column | Type | Nullable | Default |");
36387
37229
  sections.push("|--------|------|----------|---------|");
36388
37230
  for (const c of cols) {
@@ -38687,7 +39529,7 @@ export default async function handler(c: Context) {
38687
39529
  import { z as z97 } from "zod";
38688
39530
  var BASE_HOST12 = "https://api.powerbi.com";
38689
39531
  var BASE_PATH_SEGMENT18 = "/v1.0/myorg";
38690
- var BASE_URL63 = `${BASE_HOST12}${BASE_PATH_SEGMENT18}`;
39532
+ var BASE_URL64 = `${BASE_HOST12}${BASE_PATH_SEGMENT18}`;
38691
39533
  var REQUEST_TIMEOUT_MS74 = 6e4;
38692
39534
  var cachedToken32 = null;
38693
39535
  async function getProxyToken32(config) {
@@ -38769,7 +39611,7 @@ The signed-in user must have access to the workspace; unlike Service Principals,
38769
39611
  );
38770
39612
  try {
38771
39613
  const normalizedPath = normalizeRequestPath(path4, BASE_PATH_SEGMENT18);
38772
- let url = `${BASE_URL63}${normalizedPath}`;
39614
+ let url = `${BASE_URL64}${normalizedPath}`;
38773
39615
  if (queryParams) {
38774
39616
  const searchParams = new URLSearchParams(queryParams);
38775
39617
  url += `?${searchParams.toString()}`;
@@ -38852,14 +39694,18 @@ var powerbiOauthOnboarding = new ConnectorOnboarding({
38852
39694
  var parameters80 = {};
38853
39695
 
38854
39696
  // ../connectors/src/connectors/powerbi-oauth/utils.ts
38855
- var BASE_URL64 = "https://api.powerbi.com/v1.0/myorg";
39697
+ var BASE_URL65 = "https://api.powerbi.com/v1.0/myorg";
38856
39698
  function apiFetch35(proxyFetch, path4, init) {
38857
- const url = `${BASE_URL64}${path4.startsWith("/") ? "" : "/"}${path4}`;
39699
+ const url = `${BASE_URL65}${path4.startsWith("/") ? "" : "/"}${path4}`;
38858
39700
  return proxyFetch(url, init);
38859
39701
  }
38860
39702
 
38861
39703
  // ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
38862
39704
  var ALL_WORKSPACES = "__ALL_WORKSPACES__";
39705
+ var MY_WORKSPACE = "__MY_WORKSPACE__";
39706
+ var ALL_DATASETS = "__ALL_DATASETS__";
39707
+ var ALL_REPORTS = "__ALL_REPORTS__";
39708
+ var ALL_DASHBOARDS = "__ALL_DASHBOARDS__";
38863
39709
  var POWERBI_SETUP_MAX_WORKSPACES = 10;
38864
39710
  var RESOURCE_DISPLAY_LIMIT = 25;
38865
39711
  var RESOURCE_DATASETS = "datasets";
@@ -38875,14 +39721,12 @@ async function listGroups(proxyFetch) {
38875
39721
  return data.value ?? [];
38876
39722
  }
38877
39723
  async function listResource(proxyFetch, groupId, resource) {
38878
- const res = await apiFetch35(
38879
- proxyFetch,
38880
- `/groups/${encodeURIComponent(groupId)}/${resource}`
38881
- );
39724
+ const path4 = groupId === MY_WORKSPACE ? `/${resource}` : `/groups/${encodeURIComponent(groupId)}/${resource}`;
39725
+ const res = await apiFetch35(proxyFetch, path4);
38882
39726
  if (!res.ok) {
38883
39727
  const body = await res.text().catch(() => res.statusText);
38884
39728
  throw new Error(
38885
- `powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
39729
+ `powerbi: list ${resource} for ${groupId === MY_WORKSPACE ? "My workspace" : `group ${groupId}`} failed (${res.status}): ${body}`
38886
39730
  );
38887
39731
  }
38888
39732
  const data = await res.json();
@@ -38891,6 +39735,99 @@ async function listResource(proxyFetch, groupId, resource) {
38891
39735
  function resourceLabel(r) {
38892
39736
  return r.name ?? r.displayName ?? r.id ?? "(unknown)";
38893
39737
  }
39738
+ var INTERNAL_TABLE_PREFIXES = [
39739
+ "DateTableTemplate_",
39740
+ "LocalDateTable_"
39741
+ ];
39742
+ function isInternalColumn(name) {
39743
+ return /^RowNumber-[0-9A-Fa-f-]+$/.test(name);
39744
+ }
39745
+ async function fetchDatasetSchema(proxyFetch, wsId, datasetId) {
39746
+ const pathPrefix = wsId === MY_WORKSPACE ? "" : `/groups/${encodeURIComponent(wsId)}`;
39747
+ const daxQuery = 'EVALUATE SELECTCOLUMNS(COLUMNSTATISTICS(), "T", [Table Name], "C", [Column Name])';
39748
+ const res = await apiFetch35(
39749
+ proxyFetch,
39750
+ `${pathPrefix}/datasets/${encodeURIComponent(datasetId)}/executeQueries`,
39751
+ {
39752
+ method: "POST",
39753
+ headers: { "Content-Type": "application/json" },
39754
+ body: JSON.stringify({
39755
+ queries: [{ query: daxQuery }],
39756
+ serializerSettings: { includeNulls: true }
39757
+ })
39758
+ }
39759
+ );
39760
+ if (!res.ok) return /* @__PURE__ */ new Map();
39761
+ const data = await res.json();
39762
+ const rows = data.results?.[0]?.tables?.[0]?.rows ?? [];
39763
+ const schema = /* @__PURE__ */ new Map();
39764
+ for (const row of rows) {
39765
+ const table = row["[T]"] ?? "";
39766
+ const column = row["[C]"] ?? "";
39767
+ if (!table || !column) continue;
39768
+ if (INTERNAL_TABLE_PREFIXES.some((p) => table.startsWith(p))) continue;
39769
+ if (isInternalColumn(column)) continue;
39770
+ if (!schema.has(table)) schema.set(table, []);
39771
+ schema.get(table).push(column);
39772
+ }
39773
+ return schema;
39774
+ }
39775
+ function workspaceName(wsId, groupById, language) {
39776
+ if (wsId === MY_WORKSPACE) {
39777
+ return language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace";
39778
+ }
39779
+ return groupById.get(wsId)?.name ?? wsId;
39780
+ }
39781
+ async function resolveWorkspaceIds(selected, proxyFetch) {
39782
+ return resolveSetupSelection({
39783
+ selected,
39784
+ allSentinel: ALL_WORKSPACES,
39785
+ fetchAll: async () => {
39786
+ const groups = await listGroups(proxyFetch);
39787
+ return [MY_WORKSPACE, ...groups.map((g) => g.id).filter(Boolean)];
39788
+ },
39789
+ limit: POWERBI_SETUP_MAX_WORKSPACES
39790
+ });
39791
+ }
39792
+ function compoundKey(wsId, objectId) {
39793
+ return `${wsId}:${objectId}`;
39794
+ }
39795
+ function parseCompoundKey(key) {
39796
+ const idx = key.indexOf(":");
39797
+ if (idx < 0) return { wsId: "", objectId: key };
39798
+ return { wsId: key.slice(0, idx), objectId: key.slice(idx + 1) };
39799
+ }
39800
+ async function fetchObjectOptions(state, resource, allSentinel, allLabelJa, allLabelEn, rt) {
39801
+ if (!state.workspaces?.length || !state.resources?.includes(resource))
39802
+ return [];
39803
+ const wsIds = await resolveWorkspaceIds(
39804
+ state.workspaces,
39805
+ rt.config.proxyFetch
39806
+ );
39807
+ const allGroups = await listGroups(rt.config.proxyFetch);
39808
+ const groupById = new Map(allGroups.map((g) => [g.id, g]));
39809
+ const multiWorkspace = wsIds.length > 1;
39810
+ const options = [];
39811
+ for (const wsId of wsIds) {
39812
+ const wsLabel = workspaceName(wsId, groupById, rt.language);
39813
+ const items = await listResource(rt.config.proxyFetch, wsId, resource);
39814
+ for (const item of items) {
39815
+ if (!item.id) continue;
39816
+ options.push({
39817
+ value: compoundKey(wsId, item.id),
39818
+ label: multiWorkspace ? `${wsLabel} / ${resourceLabel(item)}` : resourceLabel(item)
39819
+ });
39820
+ }
39821
+ }
39822
+ if (options.length === 0) return [];
39823
+ return [
39824
+ {
39825
+ value: allSentinel,
39826
+ label: rt.language === "ja" ? allLabelJa : allLabelEn
39827
+ },
39828
+ ...options
39829
+ ];
39830
+ }
38894
39831
  var powerbiOauthSetupFlow = {
38895
39832
  initialState: () => ({}),
38896
39833
  steps: [
@@ -38909,6 +39846,10 @@ var powerbiOauthSetupFlow = {
38909
39846
  value: ALL_WORKSPACES,
38910
39847
  label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
38911
39848
  },
39849
+ {
39850
+ value: MY_WORKSPACE,
39851
+ label: rt.language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace"
39852
+ },
38912
39853
  ...options
38913
39854
  ];
38914
39855
  },
@@ -38923,16 +39864,82 @@ var powerbiOauthSetupFlow = {
38923
39864
  },
38924
39865
  async fetchOptions(state, rt) {
38925
39866
  if (!state.workspaces?.length) return [];
38926
- const datasetsLabel = rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets";
38927
- const reportsLabel = rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports";
38928
- const dashboardsLabel = rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards";
38929
39867
  return [
38930
- { value: RESOURCE_DATASETS, label: datasetsLabel },
38931
- { value: RESOURCE_REPORTS, label: reportsLabel },
38932
- { value: RESOURCE_DASHBOARDS, label: dashboardsLabel }
39868
+ {
39869
+ value: RESOURCE_DATASETS,
39870
+ label: rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets"
39871
+ },
39872
+ {
39873
+ value: RESOURCE_REPORTS,
39874
+ label: rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports"
39875
+ },
39876
+ {
39877
+ value: RESOURCE_DASHBOARDS,
39878
+ label: rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards"
39879
+ }
38933
39880
  ];
38934
39881
  },
38935
39882
  applyAnswer: (state, answer) => ({ ...state, resources: answer })
39883
+ },
39884
+ {
39885
+ slug: "datasets",
39886
+ type: "multiSelect",
39887
+ question: {
39888
+ ja: "\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
39889
+ en: "Select the datasets you want to use (multi-select allowed)"
39890
+ },
39891
+ async fetchOptions(state, rt) {
39892
+ return fetchObjectOptions(
39893
+ state,
39894
+ RESOURCE_DATASETS,
39895
+ ALL_DATASETS,
39896
+ "\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8",
39897
+ "All datasets",
39898
+ rt
39899
+ );
39900
+ },
39901
+ applyAnswer: (state, answer) => ({ ...state, selectedDatasets: answer })
39902
+ },
39903
+ {
39904
+ slug: "reports",
39905
+ type: "multiSelect",
39906
+ question: {
39907
+ ja: "\u4F7F\u7528\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
39908
+ en: "Select the reports you want to use (multi-select allowed)"
39909
+ },
39910
+ async fetchOptions(state, rt) {
39911
+ return fetchObjectOptions(
39912
+ state,
39913
+ RESOURCE_REPORTS,
39914
+ ALL_REPORTS,
39915
+ "\u3059\u3079\u3066\u306E\u30EC\u30DD\u30FC\u30C8",
39916
+ "All reports",
39917
+ rt
39918
+ );
39919
+ },
39920
+ applyAnswer: (state, answer) => ({ ...state, selectedReports: answer })
39921
+ },
39922
+ {
39923
+ slug: "dashboards",
39924
+ type: "multiSelect",
39925
+ question: {
39926
+ ja: "\u4F7F\u7528\u3059\u308B\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
39927
+ en: "Select the dashboards you want to use (multi-select allowed)"
39928
+ },
39929
+ async fetchOptions(state, rt) {
39930
+ return fetchObjectOptions(
39931
+ state,
39932
+ RESOURCE_DASHBOARDS,
39933
+ ALL_DASHBOARDS,
39934
+ "\u3059\u3079\u3066\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9",
39935
+ "All dashboards",
39936
+ rt
39937
+ );
39938
+ },
39939
+ applyAnswer: (state, answer) => ({
39940
+ ...state,
39941
+ selectedDashboards: answer
39942
+ })
38936
39943
  }
38937
39944
  ],
38938
39945
  async finalize(state, rt) {
@@ -38941,37 +39948,119 @@ var powerbiOauthSetupFlow = {
38941
39948
  }
38942
39949
  const allGroups = await listGroups(rt.config.proxyFetch);
38943
39950
  const groupById = new Map(allGroups.map((g) => [g.id, g]));
38944
- const targetIds = await resolveSetupSelection({
38945
- selected: state.workspaces,
38946
- allSentinel: ALL_WORKSPACES,
38947
- fetchAll: async () => allGroups.map((g) => g.id).filter((id) => id),
38948
- limit: POWERBI_SETUP_MAX_WORKSPACES
38949
- });
39951
+ const wsIds = await resolveWorkspaceIds(
39952
+ state.workspaces,
39953
+ rt.config.proxyFetch
39954
+ );
38950
39955
  const selectedResources = new Set(state.resources);
39956
+ async function resolveObjects(selected, allSentinel, resource) {
39957
+ const byWorkspace = /* @__PURE__ */ new Map();
39958
+ if (!selected || !selectedResources.has(resource)) return byWorkspace;
39959
+ if (selected.includes(allSentinel)) {
39960
+ for (const wsId of wsIds) {
39961
+ const items = await listResource(
39962
+ rt.config.proxyFetch,
39963
+ wsId,
39964
+ resource
39965
+ );
39966
+ const ids = items.map((i) => i.id).filter((id) => !!id);
39967
+ if (ids.length > 0) byWorkspace.set(wsId, new Set(ids));
39968
+ }
39969
+ } else {
39970
+ for (const key of selected) {
39971
+ if (key === allSentinel) continue;
39972
+ const { wsId, objectId } = parseCompoundKey(key);
39973
+ if (!byWorkspace.has(wsId)) byWorkspace.set(wsId, /* @__PURE__ */ new Set());
39974
+ byWorkspace.get(wsId).add(objectId);
39975
+ }
39976
+ }
39977
+ return byWorkspace;
39978
+ }
39979
+ const datasetsByWs = await resolveObjects(
39980
+ state.selectedDatasets,
39981
+ ALL_DATASETS,
39982
+ RESOURCE_DATASETS
39983
+ );
39984
+ const reportsByWs = await resolveObjects(
39985
+ state.selectedReports,
39986
+ ALL_REPORTS,
39987
+ RESOURCE_REPORTS
39988
+ );
39989
+ const dashboardsByWs = await resolveObjects(
39990
+ state.selectedDashboards,
39991
+ ALL_DASHBOARDS,
39992
+ RESOURCE_DASHBOARDS
39993
+ );
39994
+ const allWsIds = /* @__PURE__ */ new Set([
39995
+ ...datasetsByWs.keys(),
39996
+ ...reportsByWs.keys(),
39997
+ ...dashboardsByWs.keys()
39998
+ ]);
38951
39999
  const sections = ["## Power BI", ""];
38952
- if (!targetIds.length) {
38953
- sections.push("_No workspaces selected._", "");
40000
+ if (allWsIds.size === 0) {
40001
+ sections.push("_No resources selected._", "");
38954
40002
  return sections.join("\n");
38955
40003
  }
38956
- for (const id of targetIds) {
38957
- const group = groupById.get(id);
38958
- const name = group?.name ?? id;
38959
- sections.push(`### Workspace: ${name}`, "", `- id: \`${id}\``);
38960
- for (const resource of [
38961
- RESOURCE_DATASETS,
38962
- RESOURCE_REPORTS,
38963
- RESOURCE_DASHBOARDS
40004
+ for (const wsId of wsIds) {
40005
+ if (!allWsIds.has(wsId)) continue;
40006
+ const name = workspaceName(wsId, groupById, rt.language);
40007
+ sections.push(`### Workspace: ${name}`, "");
40008
+ if (wsId !== MY_WORKSPACE) {
40009
+ sections.push(`- id: \`${wsId}\``);
40010
+ }
40011
+ const datasetIds = datasetsByWs.get(wsId);
40012
+ if (datasetIds?.size) {
40013
+ const items = await listResource(
40014
+ rt.config.proxyFetch,
40015
+ wsId,
40016
+ RESOURCE_DATASETS
40017
+ );
40018
+ const filtered = items.filter(
40019
+ (item) => item.id && datasetIds.has(item.id)
40020
+ );
40021
+ for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
40022
+ sections.push(`#### Dataset: ${resourceLabel(item)}`, "");
40023
+ const schema = await fetchDatasetSchema(
40024
+ rt.config.proxyFetch,
40025
+ wsId,
40026
+ item.id
40027
+ );
40028
+ if (schema.size > 0) {
40029
+ for (const [table, columns] of schema) {
40030
+ sections.push(`##### Table: ${table}`, "");
40031
+ sections.push("| Column |");
40032
+ sections.push("|--------|");
40033
+ for (const col of columns) {
40034
+ sections.push(`| ${col} |`);
40035
+ }
40036
+ sections.push("");
40037
+ }
40038
+ } else {
40039
+ sections.push("_Schema not available._", "");
40040
+ }
40041
+ }
40042
+ }
40043
+ for (const [resource, selectedByWs, heading] of [
40044
+ [RESOURCE_REPORTS, reportsByWs, "Reports"],
40045
+ [RESOURCE_DASHBOARDS, dashboardsByWs, "Dashboards"]
38964
40046
  ]) {
38965
- if (!selectedResources.has(resource)) continue;
38966
- const items = await listResource(rt.config.proxyFetch, id, resource);
38967
- const heading = resource === RESOURCE_DATASETS ? "Datasets" : resource === RESOURCE_REPORTS ? "Reports" : "Dashboards";
38968
- sections.push(`- ${heading} (${items.length}):`);
38969
- for (const item of items.slice(0, RESOURCE_DISPLAY_LIMIT)) {
40047
+ const selectedIds = selectedByWs.get(wsId);
40048
+ if (!selectedIds?.size) continue;
40049
+ const items = await listResource(
40050
+ rt.config.proxyFetch,
40051
+ wsId,
40052
+ resource
40053
+ );
40054
+ const filtered = items.filter(
40055
+ (item) => item.id && selectedIds.has(item.id)
40056
+ );
40057
+ sections.push(`- ${heading} (${filtered.length}):`);
40058
+ for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
38970
40059
  sections.push(` - ${resourceLabel(item)}`);
38971
40060
  }
38972
- if (items.length > RESOURCE_DISPLAY_LIMIT) {
40061
+ if (filtered.length > RESOURCE_DISPLAY_LIMIT) {
38973
40062
  sections.push(
38974
- ` - \u2026and ${items.length - RESOURCE_DISPLAY_LIMIT} more`
40063
+ ` - \u2026and ${filtered.length - RESOURCE_DISPLAY_LIMIT} more`
38975
40064
  );
38976
40065
  }
38977
40066
  }
@@ -39242,7 +40331,11 @@ async function tableauProxyApiFetch(proxyFetch, params, path4, init) {
39242
40331
 
39243
40332
  // ../connectors/src/connectors/tableau/setup-flow.ts
39244
40333
  var ALL_PROJECTS7 = "__ALL_PROJECTS__";
40334
+ var ALL_WORKBOOKS = "__ALL_WORKBOOKS__";
39245
40335
  var TABLEAU_SETUP_MAX_PROJECTS = 10;
40336
+ var MAX_WORKBOOKS_DETAIL = 10;
40337
+ var MAX_VIEWS_PER_WORKBOOK = 5;
40338
+ var MAX_SAMPLE_ROWS = 5;
39246
40339
  var PAGE_SIZE2 = 100;
39247
40340
  async function listAllProjects3(rt) {
39248
40341
  const all = [];
@@ -39291,6 +40384,57 @@ async function listProjectResources(rt, resource) {
39291
40384
  }
39292
40385
  return all;
39293
40386
  }
40387
+ async function listViewsForWorkbook(rt, workbookId) {
40388
+ const res = await tableauProxyApiFetch(
40389
+ rt.config.proxyFetch,
40390
+ rt.params,
40391
+ `/sites/{siteId}/workbooks/${encodeURIComponent(workbookId)}/views`
40392
+ );
40393
+ if (!res.ok) return [];
40394
+ const data = await res.json();
40395
+ return data.views?.view ?? [];
40396
+ }
40397
+ async function fetchViewDataSample(rt, viewId) {
40398
+ try {
40399
+ const res = await tableauProxyApiFetch(
40400
+ rt.config.proxyFetch,
40401
+ rt.params,
40402
+ `/sites/{siteId}/views/${encodeURIComponent(viewId)}/data`
40403
+ );
40404
+ if (!res.ok) return null;
40405
+ const csv = await res.text();
40406
+ const lines = csv.trim().split("\n").filter(Boolean);
40407
+ if (lines.length === 0) return null;
40408
+ const columns = parseCsvLine(lines[0]);
40409
+ const rows = lines.slice(1, 1 + MAX_SAMPLE_ROWS).map(parseCsvLine);
40410
+ return { columns, rows };
40411
+ } catch {
40412
+ return null;
40413
+ }
40414
+ }
40415
+ function parseCsvLine(line) {
40416
+ const result = [];
40417
+ let current = "";
40418
+ let inQuotes = false;
40419
+ for (let i = 0; i < line.length; i++) {
40420
+ const ch = line[i];
40421
+ if (ch === '"') {
40422
+ if (inQuotes && line[i + 1] === '"') {
40423
+ current += '"';
40424
+ i++;
40425
+ } else {
40426
+ inQuotes = !inQuotes;
40427
+ }
40428
+ } else if (ch === "," && !inQuotes) {
40429
+ result.push(current.trim());
40430
+ current = "";
40431
+ } else {
40432
+ current += ch;
40433
+ }
40434
+ }
40435
+ result.push(current.trim());
40436
+ return result;
40437
+ }
39294
40438
  var tableauSetupFlow = {
39295
40439
  initialState: () => ({}),
39296
40440
  steps: [
@@ -39313,6 +40457,39 @@ var tableauSetupFlow = {
39313
40457
  ];
39314
40458
  },
39315
40459
  applyAnswer: (state, answer) => ({ ...state, projects: answer })
40460
+ },
40461
+ {
40462
+ slug: "workbooks",
40463
+ type: "multiSelect",
40464
+ question: {
40465
+ ja: "\u5206\u6790\u5BFE\u8C61\u306E\u30EF\u30FC\u30AF\u30D6\u30C3\u30AF\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
40466
+ en: "Select the workbooks to analyze (multi-select allowed)"
40467
+ },
40468
+ async fetchOptions(state, rt) {
40469
+ if (!state.projects?.length) return [];
40470
+ const allProjects = await listAllProjects3(rt);
40471
+ const targetIds = await resolveSetupSelection({
40472
+ selected: state.projects,
40473
+ allSentinel: ALL_PROJECTS7,
40474
+ fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
40475
+ limit: TABLEAU_SETUP_MAX_PROJECTS
40476
+ });
40477
+ const targetSet = new Set(targetIds);
40478
+ const workbooks = await listProjectResources(rt, "workbooks");
40479
+ const options = workbooks.filter((wb) => wb.id && wb.project?.id && targetSet.has(wb.project.id)).map((wb) => ({
40480
+ value: wb.id,
40481
+ label: wb.name ?? wb.id ?? "(unknown)"
40482
+ }));
40483
+ if (options.length === 0) return [];
40484
+ return [
40485
+ {
40486
+ value: ALL_WORKBOOKS,
40487
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30D6\u30C3\u30AF" : "All workbooks"
40488
+ },
40489
+ ...options
40490
+ ];
40491
+ },
40492
+ applyAnswer: (state, answer) => ({ ...state, workbooks: answer })
39316
40493
  }
39317
40494
  ],
39318
40495
  async finalize(state, rt) {
@@ -39321,25 +40498,33 @@ var tableauSetupFlow = {
39321
40498
  }
39322
40499
  const allProjects = await listAllProjects3(rt);
39323
40500
  const projectById = new Map(allProjects.map((p) => [p.id, p]));
39324
- const targetIds = await resolveSetupSelection({
40501
+ const targetProjectIds = await resolveSetupSelection({
39325
40502
  selected: state.projects,
39326
40503
  allSentinel: ALL_PROJECTS7,
39327
40504
  fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
39328
40505
  limit: TABLEAU_SETUP_MAX_PROJECTS
39329
40506
  });
39330
40507
  const sections = ["## Tableau", ""];
39331
- if (!targetIds.length) {
40508
+ if (!targetProjectIds.length) {
39332
40509
  sections.push("_No projects selected._", "");
39333
40510
  return sections.join("\n");
39334
40511
  }
39335
- const [workbooks, datasources] = await Promise.all([
40512
+ const [allWorkbooks, datasources] = await Promise.all([
39336
40513
  listProjectResources(rt, "workbooks"),
39337
40514
  listProjectResources(rt, "datasources")
39338
40515
  ]);
40516
+ const projectIdSet = new Set(targetProjectIds);
40517
+ const targetWorkbooks = await resolveSetupSelection({
40518
+ selected: state.workbooks ?? [],
40519
+ allSentinel: ALL_WORKBOOKS,
40520
+ fetchAll: async () => allWorkbooks.filter((wb) => wb.id && wb.project?.id && projectIdSet.has(wb.project.id)).map((wb) => wb.id).filter(Boolean),
40521
+ limit: MAX_WORKBOOKS_DETAIL
40522
+ });
40523
+ const targetWorkbookSet = new Set(targetWorkbooks);
39339
40524
  const workbooksByProject = /* @__PURE__ */ new Map();
39340
- for (const wb of workbooks) {
40525
+ for (const wb of allWorkbooks) {
39341
40526
  const pid = wb.project?.id;
39342
- if (!pid) continue;
40527
+ if (!pid || !projectIdSet.has(pid)) continue;
39343
40528
  const bucket = workbooksByProject.get(pid) ?? [];
39344
40529
  bucket.push(wb);
39345
40530
  workbooksByProject.set(pid, bucket);
@@ -39347,32 +40532,78 @@ var tableauSetupFlow = {
39347
40532
  const datasourcesByProject = /* @__PURE__ */ new Map();
39348
40533
  for (const ds of datasources) {
39349
40534
  const pid = ds.project?.id;
39350
- if (!pid) continue;
40535
+ if (!pid || !projectIdSet.has(pid)) continue;
39351
40536
  const bucket = datasourcesByProject.get(pid) ?? [];
39352
40537
  bucket.push(ds);
39353
40538
  datasourcesByProject.set(pid, bucket);
39354
40539
  }
39355
- for (const id of targetIds) {
39356
- const project = projectById.get(id);
39357
- const name = project?.name ?? id;
39358
- sections.push(`### Project: ${name}`, "", `- id: \`${id}\``);
39359
- const projectWorkbooks = workbooksByProject.get(id) ?? [];
39360
- sections.push(`- Workbooks (${projectWorkbooks.length}):`);
39361
- for (const wb of projectWorkbooks.slice(0, 25)) {
39362
- sections.push(` - ${wb.name ?? wb.id ?? "(unknown)"}`);
39363
- }
39364
- if (projectWorkbooks.length > 25) {
39365
- sections.push(` - \u2026and ${projectWorkbooks.length - 25} more`);
40540
+ const allDiscoveredColumns = [];
40541
+ for (const pid of targetProjectIds) {
40542
+ const project = projectById.get(pid);
40543
+ sections.push(`### Project: ${project?.name ?? pid}`, "");
40544
+ const projectWorkbooks = workbooksByProject.get(pid) ?? [];
40545
+ for (const wb of projectWorkbooks) {
40546
+ if (!wb.id) continue;
40547
+ const isDetailed = targetWorkbookSet.has(wb.id);
40548
+ sections.push(`#### Workbook: ${wb.name ?? wb.id}`, "");
40549
+ if (!isDetailed) continue;
40550
+ const views = await listViewsForWorkbook(rt, wb.id);
40551
+ if (views.length === 0) {
40552
+ sections.push("_No views found._", "");
40553
+ continue;
40554
+ }
40555
+ for (const view of views.slice(0, MAX_VIEWS_PER_WORKBOOK)) {
40556
+ if (!view.id) continue;
40557
+ sections.push(`##### View: ${view.name ?? view.id}`, "");
40558
+ const sample = await fetchViewDataSample(rt, view.id);
40559
+ if (!sample || sample.columns.length === 0) {
40560
+ sections.push("_Data not available._", "");
40561
+ continue;
40562
+ }
40563
+ allDiscoveredColumns.push(...sample.columns);
40564
+ sections.push(`| ${sample.columns.join(" | ")} |`);
40565
+ sections.push(`|${sample.columns.map(() => "---").join("|")}|`);
40566
+ for (const row of sample.rows) {
40567
+ const cells = row.map((c) => c.replace(/\|/g, "\\|"));
40568
+ sections.push(`| ${cells.join(" | ")} |`);
40569
+ }
40570
+ sections.push("");
40571
+ }
39366
40572
  }
39367
- const projectDatasources = datasourcesByProject.get(id) ?? [];
39368
- sections.push(`- Datasources (${projectDatasources.length}):`);
39369
- for (const ds of projectDatasources.slice(0, 25)) {
39370
- sections.push(` - ${ds.name ?? ds.id ?? "(unknown)"}`);
40573
+ const projectDatasources = datasourcesByProject.get(pid) ?? [];
40574
+ if (projectDatasources.length > 0) {
40575
+ sections.push(`#### Datasources (${projectDatasources.length})`, "");
40576
+ for (const ds of projectDatasources.slice(0, 25)) {
40577
+ sections.push(`- ${ds.name ?? ds.id ?? "(unknown)"}`);
40578
+ }
40579
+ sections.push("");
39371
40580
  }
39372
- if (projectDatasources.length > 25) {
39373
- sections.push(` - \u2026and ${projectDatasources.length - 25} more`);
40581
+ }
40582
+ if (allDiscoveredColumns.length > 0) {
40583
+ const unique = [...new Set(allDiscoveredColumns.map((c) => c.toLowerCase()))];
40584
+ const themes = [];
40585
+ const hasPattern = (keywords) => unique.some((c) => keywords.some((k) => c.includes(k)));
40586
+ if (hasPattern(["revenue", "sales", "amount", "price", "cost", "profit", "\u58F2\u4E0A", "\u91D1\u984D", "\u5229\u76CA"]))
40587
+ themes.push("Revenue & profitability analysis (trends, breakdown by segment)");
40588
+ if (hasPattern(["date", "month", "year", "quarter", "day", "\u65E5\u4ED8", "\u6708", "\u5E74", "\u671F"]))
40589
+ themes.push("Time-series trend analysis (YoY, MoM comparisons)");
40590
+ if (hasPattern(["region", "country", "city", "state", "\u5730\u57DF", "\u56FD", "\u90FD\u5E02", "\u5E02"]))
40591
+ themes.push("Geographic/regional performance comparison");
40592
+ if (hasPattern(["product", "category", "item", "sku", "\u5546\u54C1", "\u30AB\u30C6\u30B4\u30EA"]))
40593
+ themes.push("Product/category mix analysis");
40594
+ if (hasPattern(["customer", "user", "account", "\u9867\u5BA2", "\u30E6\u30FC\u30B6\u30FC"]))
40595
+ themes.push("Customer segmentation and behavior analysis");
40596
+ if (hasPattern(["quantity", "count", "volume", "\u6570\u91CF", "\u4EF6\u6570"]))
40597
+ themes.push("Volume and demand pattern analysis");
40598
+ if (hasPattern(["rate", "ratio", "percentage", "%", "\u7387"]))
40599
+ themes.push("KPI ratio tracking and benchmarking");
40600
+ if (themes.length > 0) {
40601
+ sections.push("### Suggested Analysis Themes", "");
40602
+ for (const theme of themes) {
40603
+ sections.push(`- ${theme}`);
40604
+ }
40605
+ sections.push("");
39374
40606
  }
39375
- sections.push("");
39376
40607
  }
39377
40608
  return sections.join("\n");
39378
40609
  }
@@ -39382,27 +40613,36 @@ var tableauSetupFlow = {
39382
40613
  import { z as z98 } from "zod";
39383
40614
  var DEFAULT_API_VERSION2 = "3.28";
39384
40615
  var REQUEST_TIMEOUT_MS75 = 6e4;
39385
- async function fetchTableauSession(connectionId) {
39386
- const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
39387
- const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
39388
- if (!token || !sandboxId) {
39389
- throw new Error(
39390
- "Tableau session manager is not configured. Missing INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL or INTERNAL_SQUADBASE_SANDBOX_ID."
39391
- );
40616
+ var cachedToken33 = null;
40617
+ async function getProxyToken33(config) {
40618
+ if (cachedToken33 && cachedToken33.expiresAt > Date.now() + 6e4) {
40619
+ return cachedToken33.token;
39392
40620
  }
39393
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
39394
- const url = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
40621
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
39395
40622
  const res = await fetch(url, {
39396
40623
  method: "POST",
39397
- headers: { Authorization: `Bearer ${token}` }
40624
+ headers: {
40625
+ "Content-Type": "application/json",
40626
+ "x-api-key": config.appApiKey,
40627
+ "project-id": config.projectId
40628
+ },
40629
+ body: JSON.stringify({
40630
+ sandboxId: config.sandboxId,
40631
+ issuedBy: "coding-agent"
40632
+ })
39398
40633
  });
39399
40634
  if (!res.ok) {
39400
- const errBody = await res.text().catch(() => res.statusText);
40635
+ const errorText = await res.text().catch(() => res.statusText);
39401
40636
  throw new Error(
39402
- `Failed to fetch Tableau session from backend-api (HTTP ${res.status}): ${errBody}`
40637
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
39403
40638
  );
39404
40639
  }
39405
- return await res.json();
40640
+ const data = await res.json();
40641
+ cachedToken33 = {
40642
+ token: data.token,
40643
+ expiresAt: new Date(data.expiresAt).getTime()
40644
+ };
40645
+ return data.token;
39406
40646
  }
39407
40647
  function buildBaseUrl7(serverUrl, apiVersion) {
39408
40648
  return `${serverUrl.replace(/\/$/, "")}/api/${apiVersion}`;
@@ -39444,7 +40684,7 @@ All paths are relative to {serverUrl}/api/{apiVersion}. Use the literal placehol
39444
40684
  Accept and Content-Type headers default to application/json so list responses come back as JSON instead of Tableau's default XML.`,
39445
40685
  inputSchema: inputSchema98,
39446
40686
  outputSchema: outputSchema98,
39447
- async execute({ connectionId, method, path: path4, queryParams, body }, connections) {
40687
+ async execute({ connectionId, method, path: path4, queryParams, body }, connections, config) {
39448
40688
  const connection = connections.find((c) => c.id === connectionId);
39449
40689
  if (!connection) {
39450
40690
  return {
@@ -39459,50 +40699,42 @@ Accept and Content-Type headers default to application/json so list responses co
39459
40699
  const serverUrl = parameters81.serverUrl.getValue(connection);
39460
40700
  const apiVersion = parameters81.apiVersion.tryGetValue(connection) || DEFAULT_API_VERSION2;
39461
40701
  const trimmedPath = path4.trim().replace(/^([^/])/, "/$1");
39462
- const queryString = queryParams ? `?${new URLSearchParams(queryParams).toString()}` : "";
39463
40702
  const baseUrl = buildBaseUrl7(serverUrl, apiVersion);
40703
+ let url = `${baseUrl}${trimmedPath}`;
40704
+ if (queryParams) {
40705
+ url += `?${new URLSearchParams(queryParams).toString()}`;
40706
+ }
40707
+ const token = await getProxyToken33(config.oauthProxy);
40708
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
39464
40709
  const controller = new AbortController();
39465
40710
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS75);
39466
40711
  try {
39467
- let attempt = 0;
39468
- while (true) {
39469
- const session = await fetchTableauSession(connectionId);
39470
- const resolvedPath = trimmedPath.replace(
39471
- /\{siteId\}/g,
39472
- session.siteId
39473
- );
39474
- const url = `${baseUrl}${resolvedPath}${queryString}`;
39475
- const init = {
40712
+ const response = await fetch(proxyUrl, {
40713
+ method: "POST",
40714
+ headers: {
40715
+ "Content-Type": "application/json",
40716
+ Authorization: `Bearer ${token}`
40717
+ },
40718
+ body: JSON.stringify({
40719
+ url,
39476
40720
  method,
39477
- headers: {
39478
- "X-Tableau-Auth": session.authToken,
39479
- Accept: "application/json",
39480
- "Content-Type": "application/json"
39481
- },
39482
- signal: controller.signal
39483
- };
39484
- if (body !== void 0) {
39485
- init.body = JSON.stringify(body);
39486
- }
39487
- const response = await fetch(url, init);
39488
- const text = await response.text();
39489
- const data = text ? (() => {
39490
- try {
39491
- return JSON.parse(text);
39492
- } catch {
39493
- return text;
39494
- }
39495
- })() : null;
39496
- if (response.status === 401 && attempt === 0) {
39497
- attempt++;
39498
- continue;
39499
- }
39500
- if (!response.ok) {
39501
- const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
39502
- return { success: false, error: errorMessage };
40721
+ ...body !== void 0 ? { body } : {}
40722
+ }),
40723
+ signal: controller.signal
40724
+ });
40725
+ const text = await response.text();
40726
+ const data = text ? (() => {
40727
+ try {
40728
+ return JSON.parse(text);
40729
+ } catch {
40730
+ return text;
39503
40731
  }
39504
- return { success: true, status: response.status, data };
40732
+ })() : null;
40733
+ if (!response.ok) {
40734
+ const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
40735
+ return { success: false, error: errorMessage };
39505
40736
  }
40737
+ return { success: true, status: response.status, data };
39506
40738
  } finally {
39507
40739
  clearTimeout(timeout);
39508
40740
  }
@@ -39694,12 +40926,12 @@ export default async function handler(c: Context) {
39694
40926
  import { z as z99 } from "zod";
39695
40927
  var BASE_HOST13 = "https://graph.microsoft.com";
39696
40928
  var BASE_PATH_SEGMENT19 = "/v1.0";
39697
- var BASE_URL65 = `${BASE_HOST13}${BASE_PATH_SEGMENT19}`;
40929
+ var BASE_URL66 = `${BASE_HOST13}${BASE_PATH_SEGMENT19}`;
39698
40930
  var REQUEST_TIMEOUT_MS76 = 6e4;
39699
- var cachedToken33 = null;
39700
- async function getProxyToken33(config) {
39701
- if (cachedToken33 && cachedToken33.expiresAt > Date.now() + 6e4) {
39702
- return cachedToken33.token;
40931
+ var cachedToken34 = null;
40932
+ async function getProxyToken34(config) {
40933
+ if (cachedToken34 && cachedToken34.expiresAt > Date.now() + 6e4) {
40934
+ return cachedToken34.token;
39703
40935
  }
39704
40936
  const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
39705
40937
  const res = await fetch(url, {
@@ -39721,7 +40953,7 @@ async function getProxyToken33(config) {
39721
40953
  );
39722
40954
  }
39723
40955
  const data = await res.json();
39724
- cachedToken33 = {
40956
+ cachedToken34 = {
39725
40957
  token: data.token,
39726
40958
  expiresAt: new Date(data.expiresAt).getTime()
39727
40959
  };
@@ -39773,12 +41005,12 @@ For full-text search use the \`$search\` query parameter (must be wrapped in dou
39773
41005
  );
39774
41006
  try {
39775
41007
  const normalizedPath = normalizeRequestPath(path4, BASE_PATH_SEGMENT19);
39776
- let url = `${BASE_URL65}${normalizedPath}`;
41008
+ let url = `${BASE_URL66}${normalizedPath}`;
39777
41009
  if (queryParams) {
39778
41010
  const searchParams = new URLSearchParams(queryParams);
39779
41011
  url += `?${searchParams.toString()}`;
39780
41012
  }
39781
- const token = await getProxyToken33(config.oauthProxy);
41013
+ const token = await getProxyToken34(config.oauthProxy);
39782
41014
  const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
39783
41015
  const controller = new AbortController();
39784
41016
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS76);