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