@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/cli/index.js CHANGED
@@ -856,19 +856,34 @@ async function runSetupFlow(flow, params, ctx, config) {
856
856
  };
857
857
  let state = flow.initialState();
858
858
  let answerIdx = 0;
859
+ const pendingParameterUpdates = [];
859
860
  for (const step of flow.steps) {
860
861
  const ans = ctx.answers[answerIdx];
861
862
  if (ans && ans.questionSlug === step.slug) {
862
863
  state = step.applyAnswer(state, ans.answer);
864
+ if (step.toParameterUpdates) {
865
+ pendingParameterUpdates.push(...step.toParameterUpdates(state));
866
+ }
863
867
  answerIdx += 1;
864
868
  continue;
865
869
  }
870
+ const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
866
871
  if (step.type === "text") {
872
+ if (step.fetchOptions) {
873
+ const options2 = await step.fetchOptions(state, runtime);
874
+ if (options2.length === 0) {
875
+ continue;
876
+ }
877
+ }
867
878
  return {
868
879
  type: "nextQuestion",
869
880
  questionSlug: step.slug,
870
881
  question: step.question[ctx.language],
871
- questionType: "text"
882
+ questionType: "text",
883
+ allowFreeText: resolvedAllowFreeText,
884
+ ...pendingParameterUpdates.length > 0 && {
885
+ parameterUpdates: pendingParameterUpdates
886
+ }
872
887
  };
873
888
  }
874
889
  const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
@@ -880,11 +895,21 @@ async function runSetupFlow(flow, params, ctx, config) {
880
895
  questionSlug: step.slug,
881
896
  question: step.question[ctx.language],
882
897
  questionType: step.type,
883
- options
898
+ options,
899
+ allowFreeText: resolvedAllowFreeText,
900
+ ...pendingParameterUpdates.length > 0 && {
901
+ parameterUpdates: pendingParameterUpdates
902
+ }
884
903
  };
885
904
  }
886
905
  const dataInvestigationResult = await flow.finalize(state, runtime);
887
- return { type: "fulfilled", dataInvestigationResult };
906
+ return {
907
+ type: "fulfilled",
908
+ dataInvestigationResult,
909
+ ...pendingParameterUpdates.length > 0 && {
910
+ parameterUpdates: pendingParameterUpdates
911
+ }
912
+ };
888
913
  }
889
914
  async function resolveSetupSelection(params) {
890
915
  const { selected, allSentinel, fetchAll, limit } = params;
@@ -1063,7 +1088,46 @@ var INTERNAL_SCHEMAS = /* @__PURE__ */ new Set([
1063
1088
  "READER_ACCOUNT_USAGE",
1064
1089
  "DATA_SHARING_USAGE"
1065
1090
  ]);
1091
+ var OBJECT_TYPE_LABELS = {
1092
+ table: { ja: "\u30C6\u30FC\u30D6\u30EB", en: "Table" },
1093
+ view: { ja: "\u30D3\u30E5\u30FC", en: "View" },
1094
+ stream: { ja: "\u30B9\u30C8\u30EA\u30FC\u30E0", en: "Stream" },
1095
+ dynamic_table: { ja: "\u30C0\u30A4\u30CA\u30DF\u30C3\u30AF\u30C6\u30FC\u30D6\u30EB", en: "Dynamic Table" },
1096
+ pipe: { ja: "\u30D1\u30A4\u30D7", en: "Pipe" },
1097
+ task: { ja: "\u30BF\u30B9\u30AF", en: "Task" }
1098
+ };
1099
+ var HEADING_LABELS = {
1100
+ table: "Table",
1101
+ view: "View",
1102
+ stream: "Stream",
1103
+ dynamic_table: "Dynamic Table",
1104
+ pipe: "Pipe",
1105
+ task: "Task"
1106
+ };
1066
1107
  function createSnowflakeSetupFlow(runQuery11) {
1108
+ const objectTypes = /* @__PURE__ */ new Map();
1109
+ async function fetchAllObjects(params, db, schema) {
1110
+ objectTypes.clear();
1111
+ const typeQueries = [
1112
+ ["table", `SHOW TABLES IN SCHEMA "${db}"."${schema}"`],
1113
+ ["view", `SHOW VIEWS IN SCHEMA "${db}"."${schema}"`],
1114
+ ["stream", `SHOW STREAMS IN SCHEMA "${db}"."${schema}"`],
1115
+ ["dynamic_table", `SHOW DYNAMIC TABLES IN SCHEMA "${db}"."${schema}"`],
1116
+ ["pipe", `SHOW PIPES IN SCHEMA "${db}"."${schema}"`],
1117
+ ["task", `SHOW TASKS IN SCHEMA "${db}"."${schema}"`]
1118
+ ];
1119
+ const results = await Promise.all(
1120
+ typeQueries.map(([, sql]) => runQuery11(params, sql).catch(() => []))
1121
+ );
1122
+ for (let i = 0; i < results.length; i++) {
1123
+ const type = typeQueries[i][0];
1124
+ for (const r of results[i]) {
1125
+ const name = String(r["name"] ?? "");
1126
+ if (name) objectTypes.set(name, type);
1127
+ }
1128
+ }
1129
+ return Array.from(objectTypes.keys());
1130
+ }
1067
1131
  return {
1068
1132
  initialState: () => ({}),
1069
1133
  steps: [
@@ -1103,22 +1167,27 @@ function createSnowflakeSetupFlow(runQuery11) {
1103
1167
  slug: "tables",
1104
1168
  type: "multiSelect",
1105
1169
  question: {
1106
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
1107
- en: "Select target tables (multi-select allowed)"
1170
+ 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",
1171
+ en: "Select target objects (tables, views, streams, etc. \u2014 multi-select allowed)"
1108
1172
  },
1109
1173
  async fetchOptions(state, rt) {
1110
1174
  if (!state.database || !state.schema) return [];
1111
- const rows = await runQuery11(
1175
+ const allNames = await fetchAllObjects(
1112
1176
  rt.params,
1113
- `SHOW TABLES IN SCHEMA "${state.database}"."${state.schema}"`
1177
+ state.database,
1178
+ state.schema
1114
1179
  );
1115
- const tableOptions = rows.map((r) => String(r["name"] ?? "")).filter((name) => name).map((value) => ({ value }));
1180
+ const options = allNames.map((name) => {
1181
+ const type = objectTypes.get(name) ?? "table";
1182
+ const typeLabel = OBJECT_TYPE_LABELS[type][rt.language];
1183
+ return { value: name, label: `${name} (${typeLabel})` };
1184
+ });
1116
1185
  return [
1117
1186
  {
1118
1187
  value: ALL_TABLES,
1119
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
1188
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8" : "All objects"
1120
1189
  },
1121
- ...tableOptions
1190
+ ...options
1122
1191
  ];
1123
1192
  },
1124
1193
  applyAnswer: (state, answer) => ({ ...state, tables: answer })
@@ -1130,16 +1199,10 @@ function createSnowflakeSetupFlow(runQuery11) {
1130
1199
  }
1131
1200
  const db = state.database;
1132
1201
  const schema = state.schema;
1133
- const targetTables = await resolveSetupSelection({
1202
+ const targetObjects = await resolveSetupSelection({
1134
1203
  selected: state.tables,
1135
1204
  allSentinel: ALL_TABLES,
1136
- fetchAll: async () => {
1137
- const rows = await runQuery11(
1138
- rt.params,
1139
- `SHOW TABLES IN SCHEMA "${db}"."${schema}"`
1140
- );
1141
- return rows.map((r) => String(r["name"] ?? "")).filter((name) => name);
1142
- },
1205
+ fetchAll: () => fetchAllObjects(rt.params, db, schema),
1143
1206
  limit: SNOWFLAKE_SETUP_MAX_TABLES
1144
1207
  });
1145
1208
  const sections = [
@@ -1150,24 +1213,66 @@ function createSnowflakeSetupFlow(runQuery11) {
1150
1213
  `#### Schema: ${schema}`,
1151
1214
  ""
1152
1215
  ];
1153
- for (const table of targetTables) {
1154
- const cols = await runQuery11(
1155
- rt.params,
1156
- `DESCRIBE TABLE "${db}"."${schema}"."${table}"`
1157
- );
1158
- sections.push(`##### Table: ${table}`, "");
1159
- sections.push("| Column | Type | Nullable | Default |");
1160
- sections.push("|--------|------|----------|---------|");
1161
- for (const c of cols) {
1162
- const name = String(c["name"] ?? "");
1163
- const type = String(c["type"] ?? "");
1164
- const nullable = String(c["null?"] ?? "");
1165
- const defaultValue = c["default"] == null ? "-" : String(c["default"]);
1166
- sections.push(
1167
- `| ${name} | ${type} | ${nullable} | ${defaultValue} |`
1168
- );
1216
+ for (const name of targetObjects) {
1217
+ const type = objectTypes.get(name) ?? "table";
1218
+ const heading = HEADING_LABELS[type];
1219
+ switch (type) {
1220
+ case "table":
1221
+ case "view":
1222
+ case "dynamic_table":
1223
+ case "stream": {
1224
+ const cols = await runQuery11(
1225
+ rt.params,
1226
+ `DESCRIBE TABLE "${db}"."${schema}"."${name}"`
1227
+ ).catch(() => []);
1228
+ sections.push(`##### ${heading}: ${name}`, "");
1229
+ if (cols.length > 0) {
1230
+ sections.push("| Column | Type | Nullable | Default |");
1231
+ sections.push("|--------|------|----------|---------|");
1232
+ for (const c of cols) {
1233
+ const colName = String(c["name"] ?? "");
1234
+ const colType = String(c["type"] ?? "");
1235
+ const nullable = String(c["null?"] ?? "");
1236
+ const defaultValue = c["default"] == null ? "-" : String(c["default"]);
1237
+ sections.push(
1238
+ `| ${colName} | ${colType} | ${nullable} | ${defaultValue} |`
1239
+ );
1240
+ }
1241
+ }
1242
+ sections.push("");
1243
+ break;
1244
+ }
1245
+ case "pipe": {
1246
+ const rows = await runQuery11(
1247
+ rt.params,
1248
+ `SHOW PIPES LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
1249
+ ).catch(() => []);
1250
+ sections.push(`##### Pipe: ${name}`, "");
1251
+ if (rows.length > 0) {
1252
+ const definition = String(rows[0]["definition"] ?? "-");
1253
+ sections.push(`Definition: \`${definition}\``, "");
1254
+ }
1255
+ sections.push("");
1256
+ break;
1257
+ }
1258
+ case "task": {
1259
+ const rows = await runQuery11(
1260
+ rt.params,
1261
+ `SHOW TASKS LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
1262
+ ).catch(() => []);
1263
+ sections.push(`##### Task: ${name}`, "");
1264
+ if (rows.length > 0) {
1265
+ const schedule = String(rows[0]["schedule"] ?? "-");
1266
+ const taskState = String(rows[0]["state"] ?? "-");
1267
+ const definition = String(rows[0]["definition"] ?? "-");
1268
+ sections.push(`Schedule: ${schedule}`, "");
1269
+ sections.push(`State: ${taskState}`, "");
1270
+ sections.push(`Definition: \`${definition}\``, "");
1271
+ }
1272
+ sections.push("");
1273
+ break;
1274
+ }
1169
1275
  }
1170
- sections.push("");
1171
1276
  }
1172
1277
  return sections.join("\n");
1173
1278
  }
@@ -1980,8 +2085,8 @@ var postgresqlSetupFlow = {
1980
2085
  slug: "tables",
1981
2086
  type: "multiSelect",
1982
2087
  question: {
1983
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
1984
- en: "Select target tables (multi-select allowed)"
2088
+ 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",
2089
+ en: "Select target tables and views (multi-select allowed)"
1985
2090
  },
1986
2091
  async fetchOptions(state, rt) {
1987
2092
  if (!state.schema) return [];
@@ -1990,7 +2095,7 @@ var postgresqlSetupFlow = {
1990
2095
  return [
1991
2096
  {
1992
2097
  value: ALL_TABLES2,
1993
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
2098
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
1994
2099
  },
1995
2100
  ...tableOptions
1996
2101
  ];
@@ -2327,8 +2432,8 @@ var mysqlSetupFlow = {
2327
2432
  slug: "tables",
2328
2433
  type: "multiSelect",
2329
2434
  question: {
2330
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
2331
- en: "Select target tables (multi-select allowed)"
2435
+ 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",
2436
+ en: "Select target tables and views (multi-select allowed)"
2332
2437
  },
2333
2438
  async fetchOptions(state, rt) {
2334
2439
  if (!state.database) return [];
@@ -2337,7 +2442,7 @@ var mysqlSetupFlow = {
2337
2442
  return [
2338
2443
  {
2339
2444
  value: ALL_TABLES3,
2340
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
2445
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
2341
2446
  },
2342
2447
  ...tableOptions
2343
2448
  ];
@@ -2788,6 +2893,72 @@ var bigqueryOnboarding = new ConnectorOnboarding({
2788
2893
  }
2789
2894
  });
2790
2895
 
2896
+ // ../connectors/src/table-grouping.ts
2897
+ var SHARD_GROUP_PREFIX = "__SHARD__";
2898
+ var DEFAULT_MIN_SHARD_GROUP_SIZE = 3;
2899
+ function extractDateShardSuffix(name) {
2900
+ const m = name.match(/^(.+)_(\d{8})$/);
2901
+ if (!m) return null;
2902
+ const [, prefix, suffix] = m;
2903
+ const y = +suffix.slice(0, 4);
2904
+ const mo = +suffix.slice(4, 6);
2905
+ const d = +suffix.slice(6, 8);
2906
+ if (y < 2e3 || y > 2099 || mo < 1 || mo > 12 || d < 1 || d > 31) {
2907
+ return null;
2908
+ }
2909
+ return { prefix, suffix };
2910
+ }
2911
+ function detectDateShardCandidates(tableNames, minCount = DEFAULT_MIN_SHARD_GROUP_SIZE) {
2912
+ const prefixMap = /* @__PURE__ */ new Map();
2913
+ const nonSharded = [];
2914
+ for (const name of tableNames) {
2915
+ const parsed = extractDateShardSuffix(name);
2916
+ if (parsed) {
2917
+ const existing = prefixMap.get(parsed.prefix);
2918
+ if (existing) {
2919
+ existing.push(name);
2920
+ } else {
2921
+ prefixMap.set(parsed.prefix, [name]);
2922
+ }
2923
+ } else {
2924
+ nonSharded.push(name);
2925
+ }
2926
+ }
2927
+ const candidates = [];
2928
+ const singles = [...nonSharded];
2929
+ for (const [prefix, members] of prefixMap) {
2930
+ if (members.length >= minCount) {
2931
+ candidates.push({ prefix, count: members.length, members });
2932
+ } else {
2933
+ singles.push(...members);
2934
+ }
2935
+ }
2936
+ return { singles, candidates };
2937
+ }
2938
+ function schemasMatch(columnsA, columnsB) {
2939
+ if (columnsA.length !== columnsB.length) return false;
2940
+ return columnsA.every(
2941
+ (a, i) => String(a["column_name"] ?? "") === String(columnsB[i]["column_name"] ?? "") && String(a["data_type"] ?? "") === String(columnsB[i]["data_type"] ?? "")
2942
+ );
2943
+ }
2944
+ function isShardGroupValue(value) {
2945
+ return value.startsWith(SHARD_GROUP_PREFIX);
2946
+ }
2947
+ function getShardGroupPrefix(value) {
2948
+ return value.slice(SHARD_GROUP_PREFIX.length);
2949
+ }
2950
+ function shardGroupValue(prefix) {
2951
+ return `${SHARD_GROUP_PREFIX}${prefix}`;
2952
+ }
2953
+ function buildGroupedTableOptions(singles, confirmedGroups, language) {
2954
+ const groupOptions = confirmedGroups.sort((a, b) => a.prefix.localeCompare(b.prefix)).map((g) => ({
2955
+ value: shardGroupValue(g.prefix),
2956
+ label: language === "ja" ? `${g.prefix}_* (\u65E5\u4ED8\u30B7\u30E3\u30FC\u30C9: ${g.count} \u30C6\u30FC\u30D6\u30EB)` : `${g.prefix}_* (date-sharded: ${g.count} tables)`
2957
+ }));
2958
+ const singleOptions = singles.sort().map((name) => ({ value: name }));
2959
+ return [...groupOptions, ...singleOptions];
2960
+ }
2961
+
2791
2962
  // ../connectors/src/connectors/bigquery/utils.ts
2792
2963
  async function runQuery5(params, sql) {
2793
2964
  const { BigQuery } = await import("@google-cloud/bigquery");
@@ -2818,13 +2989,23 @@ async function listProjects(params) {
2818
2989
  scopes: ["https://www.googleapis.com/auth/bigquery"]
2819
2990
  });
2820
2991
  const client = await auth.getClient();
2821
- const res = await client.request({
2822
- url: "https://bigquery.googleapis.com/bigquery/v2/projects"
2823
- });
2824
- return (res.data.projects ?? []).map((p) => ({
2825
- projectId: p.projectReference?.projectId ?? "",
2826
- friendlyName: p.friendlyName ?? p.projectReference?.projectId ?? ""
2827
- })).filter((p) => p.projectId !== "");
2992
+ const projects = [];
2993
+ let pageToken;
2994
+ do {
2995
+ const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
2996
+ const res = await client.request({ url });
2997
+ for (const p of res.data.projects ?? []) {
2998
+ const id = p.projectReference?.projectId ?? "";
2999
+ if (id) {
3000
+ projects.push({
3001
+ projectId: id,
3002
+ friendlyName: p.friendlyName ?? id
3003
+ });
3004
+ }
3005
+ }
3006
+ pageToken = res.data.nextPageToken;
3007
+ } while (pageToken);
3008
+ return projects;
2828
3009
  }
2829
3010
  async function listDatasets(params, projectId2) {
2830
3011
  const { BigQuery } = await import("@google-cloud/bigquery");
@@ -2862,23 +3043,25 @@ var PUBLIC_DATASETS = [
2862
3043
  labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
2863
3044
  }
2864
3045
  ];
3046
+ var SAME_AS_BILLING = "__SAME_AS_BILLING__";
2865
3047
  function resolveDatasetRef(state) {
2866
3048
  const dataset = state.dataset ?? "";
2867
3049
  if (dataset.includes(".")) {
2868
3050
  const [datasetProject, ...rest] = dataset.split(".");
2869
3051
  return { datasetProject, datasetId: rest.join(".") };
2870
3052
  }
2871
- return { datasetProject: state.project ?? "", datasetId: dataset };
3053
+ return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
2872
3054
  }
2873
3055
  var bigquerySetupFlow = {
2874
3056
  initialState: () => ({}),
2875
3057
  steps: [
2876
3058
  {
2877
- slug: "project",
3059
+ slug: "billingProject",
2878
3060
  type: "select",
3061
+ allowFreeText: false,
2879
3062
  question: {
2880
- 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",
2881
- en: "Select the GCP project to use for setup (also required as the billing project when querying public datasets)"
3063
+ 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",
3064
+ en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
2882
3065
  },
2883
3066
  async fetchOptions(_state, rt) {
2884
3067
  const projects = await listProjects(rt.params);
@@ -2887,7 +3070,40 @@ var bigquerySetupFlow = {
2887
3070
  label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
2888
3071
  }));
2889
3072
  },
2890
- applyAnswer: (state, answer) => ({ ...state, project: answer[0] })
3073
+ applyAnswer: (state, answer) => ({
3074
+ ...state,
3075
+ billingProject: answer[0]
3076
+ }),
3077
+ toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
3078
+ },
3079
+ {
3080
+ slug: "databaseProject",
3081
+ type: "select",
3082
+ question: {
3083
+ 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",
3084
+ en: "Select the GCP project where your data resides"
3085
+ },
3086
+ async fetchOptions(state, rt) {
3087
+ if (!state.billingProject) return [];
3088
+ const sameAsBillingOption = {
3089
+ value: SAME_AS_BILLING,
3090
+ label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
3091
+ };
3092
+ const projects = await listProjects(rt.params);
3093
+ const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
3094
+ value: p.projectId,
3095
+ label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
3096
+ }));
3097
+ const publicProjectOption = {
3098
+ value: "bigquery-public-data",
3099
+ 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)"
3100
+ };
3101
+ return [sameAsBillingOption, ...projectOptions, publicProjectOption];
3102
+ },
3103
+ applyAnswer: (state, answer) => ({
3104
+ ...state,
3105
+ databaseProject: answer[0] === SAME_AS_BILLING ? state.billingProject : answer[0]
3106
+ })
2891
3107
  },
2892
3108
  {
2893
3109
  slug: "dataset",
@@ -2897,8 +3113,8 @@ var bigquerySetupFlow = {
2897
3113
  en: "Select the dataset to use for setup"
2898
3114
  },
2899
3115
  async fetchOptions(state, rt) {
2900
- if (!state.project) return [];
2901
- const datasets = await listDatasets(rt.params, state.project);
3116
+ if (!state.databaseProject) return [];
3117
+ const datasets = await listDatasets(rt.params, state.databaseProject);
2902
3118
  const projectDatasetOptions = datasets.map((d) => ({
2903
3119
  value: d.datasetId,
2904
3120
  label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
@@ -2915,66 +3131,140 @@ var bigquerySetupFlow = {
2915
3131
  slug: "tables",
2916
3132
  type: "multiSelect",
2917
3133
  question: {
2918
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
2919
- en: "Select target tables (multi-select allowed)"
3134
+ 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",
3135
+ en: "Select target tables and views (multi-select allowed)"
2920
3136
  },
2921
3137
  async fetchOptions(state, rt) {
2922
- if (!state.project || !state.dataset) return [];
3138
+ if (!state.billingProject || !state.dataset) return [];
2923
3139
  const { datasetProject, datasetId } = resolveDatasetRef(state);
2924
3140
  const rows = await runQuery5(
2925
3141
  rt.params,
2926
3142
  `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
2927
3143
  );
2928
- const tableOptions = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name).map((value) => ({ value }));
3144
+ const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3145
+ const { singles, candidates } = detectDateShardCandidates(tableNames);
3146
+ const confirmedGroups = [];
3147
+ const rejectedSingles = [];
3148
+ for (const candidate of candidates) {
3149
+ const [first, second] = candidate.members;
3150
+ const colRows = await runQuery5(
3151
+ rt.params,
3152
+ `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`
3153
+ );
3154
+ const colsA = colRows.filter(
3155
+ (r) => String(r["table_name"]) === first
3156
+ );
3157
+ const colsB = colRows.filter(
3158
+ (r) => String(r["table_name"]) === second
3159
+ );
3160
+ if (schemasMatch(colsA, colsB)) {
3161
+ confirmedGroups.push(candidate);
3162
+ } else {
3163
+ rejectedSingles.push(...candidate.members);
3164
+ }
3165
+ }
3166
+ const allSingles = [...singles, ...rejectedSingles];
2929
3167
  return [
2930
3168
  {
2931
3169
  value: ALL_TABLES4,
2932
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
3170
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
2933
3171
  },
2934
- ...tableOptions
3172
+ ...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
2935
3173
  ];
2936
3174
  },
2937
3175
  applyAnswer: (state, answer) => ({ ...state, tables: answer })
2938
3176
  }
2939
3177
  ],
2940
3178
  async finalize(state, rt) {
2941
- if (!state.project || !state.dataset || !state.tables) {
3179
+ if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
2942
3180
  throw new Error("BigQuery setup: incomplete state on finalize");
2943
3181
  }
2944
3182
  const { datasetProject, datasetId } = resolveDatasetRef(state);
2945
- const targetTables = await resolveSetupSelection({
2946
- selected: state.tables,
2947
- allSentinel: ALL_TABLES4,
2948
- fetchAll: async () => {
2949
- const rows = await runQuery5(
2950
- rt.params,
2951
- `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
2952
- );
2953
- return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
2954
- },
2955
- limit: BIGQUERY_SETUP_MAX_TABLES
2956
- });
3183
+ const fetchAllTableNames = async () => {
3184
+ const rows = await runQuery5(
3185
+ rt.params,
3186
+ `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3187
+ );
3188
+ return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3189
+ };
3190
+ let entries;
3191
+ if (state.tables.includes(ALL_TABLES4)) {
3192
+ const allNames = await fetchAllTableNames();
3193
+ const { singles, candidates } = detectDateShardCandidates(allNames);
3194
+ entries = [
3195
+ ...candidates.map(
3196
+ (g) => ({
3197
+ type: "shardGroup",
3198
+ prefix: g.prefix,
3199
+ count: g.count,
3200
+ representative: g.members[0]
3201
+ })
3202
+ ),
3203
+ ...singles.map((name) => ({ type: "table", name }))
3204
+ ];
3205
+ } else {
3206
+ const shardSelections = state.tables.filter(isShardGroupValue);
3207
+ const tableSelections = state.tables.filter(
3208
+ (v) => !isShardGroupValue(v)
3209
+ );
3210
+ entries = tableSelections.map(
3211
+ (name) => ({ type: "table", name })
3212
+ );
3213
+ if (shardSelections.length > 0) {
3214
+ const allNames = await fetchAllTableNames();
3215
+ for (const value of shardSelections) {
3216
+ const prefix = getShardGroupPrefix(value);
3217
+ const members = allNames.filter((n) => {
3218
+ const parsed = extractDateShardSuffix(n);
3219
+ return parsed != null && parsed.prefix === prefix;
3220
+ });
3221
+ if (members.length > 0) {
3222
+ entries.push({
3223
+ type: "shardGroup",
3224
+ prefix,
3225
+ count: members.length,
3226
+ representative: members[0]
3227
+ });
3228
+ }
3229
+ }
3230
+ }
3231
+ }
3232
+ entries = entries.slice(0, BIGQUERY_SETUP_MAX_TABLES);
3233
+ const queryColumns = async (tableName) => runQuery5(
3234
+ rt.params,
3235
+ `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
3236
+ );
2957
3237
  const sections = [
2958
3238
  "## BigQuery",
2959
3239
  "",
2960
- `### Billing project: ${state.project}`,
3240
+ `### Billing project: ${state.billingProject}`,
3241
+ "",
3242
+ `### Database project: ${state.databaseProject}`,
2961
3243
  "",
2962
3244
  `#### Dataset: ${datasetProject}.${datasetId}`,
2963
3245
  ""
2964
3246
  ];
2965
- for (const table of targetTables) {
2966
- const cols = await runQuery5(
2967
- rt.params,
2968
- `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${table.replaceAll("'", "''")}' ORDER BY ordinal_position`
2969
- );
2970
- sections.push(`##### Table: ${table}`, "");
3247
+ for (const entry of entries) {
3248
+ const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
3249
+ const cols = await queryColumns(tableName);
3250
+ if (entry.type === "shardGroup") {
3251
+ sections.push(
3252
+ `##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
3253
+ ""
3254
+ );
3255
+ sections.push(
3256
+ `_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
3257
+ ""
3258
+ );
3259
+ } else {
3260
+ sections.push(`##### Table: ${entry.name}`, "");
3261
+ }
2971
3262
  sections.push("| Column | Type | Nullable |");
2972
3263
  sections.push("|--------|------|----------|");
2973
3264
  for (const c of cols) {
2974
- const name = String(c["column_name"] ?? "");
2975
- const type = String(c["data_type"] ?? "");
2976
- const nullable = String(c["is_nullable"] ?? "");
2977
- sections.push(`| ${name} | ${type} | ${nullable} |`);
3265
+ sections.push(
3266
+ `| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
3267
+ );
2978
3268
  }
2979
3269
  sections.push("");
2980
3270
  }
@@ -3472,21 +3762,30 @@ async function runQuery6(proxyFetch, projectId2, sql) {
3472
3762
  return parseQueryResponse(data);
3473
3763
  }
3474
3764
  async function listProjects2(proxyFetch) {
3475
- const res = await proxyFetch(
3476
- "https://bigquery.googleapis.com/bigquery/v2/projects",
3477
- { method: "GET" }
3478
- );
3479
- if (!res.ok) {
3480
- const errorText = await res.text().catch(() => res.statusText);
3481
- throw new Error(
3482
- `BigQuery listProjects failed: HTTP ${res.status} ${errorText}`
3483
- );
3484
- }
3485
- const data = await res.json();
3486
- return (data.projects ?? []).map((p) => ({
3487
- projectId: p.projectReference?.projectId ?? "",
3488
- friendlyName: p.friendlyName ?? p.projectReference?.projectId ?? ""
3489
- })).filter((p) => p.projectId !== "");
3765
+ const projects = [];
3766
+ let pageToken;
3767
+ do {
3768
+ const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
3769
+ const res = await proxyFetch(url, { method: "GET" });
3770
+ if (!res.ok) {
3771
+ const errorText = await res.text().catch(() => res.statusText);
3772
+ throw new Error(
3773
+ `BigQuery listProjects failed: HTTP ${res.status} ${errorText}`
3774
+ );
3775
+ }
3776
+ const data = await res.json();
3777
+ for (const p of data.projects ?? []) {
3778
+ const id = p.projectReference?.projectId ?? "";
3779
+ if (id) {
3780
+ projects.push({
3781
+ projectId: id,
3782
+ friendlyName: p.friendlyName ?? id
3783
+ });
3784
+ }
3785
+ }
3786
+ pageToken = data.nextPageToken;
3787
+ } while (pageToken);
3788
+ return projects;
3490
3789
  }
3491
3790
  async function listDatasets2(proxyFetch, projectId2) {
3492
3791
  const res = await proxyFetch(
@@ -3526,23 +3825,25 @@ var PUBLIC_DATASETS2 = [
3526
3825
  labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
3527
3826
  }
3528
3827
  ];
3828
+ var SAME_AS_BILLING2 = "__SAME_AS_BILLING__";
3529
3829
  function resolveDatasetRef2(state) {
3530
3830
  const dataset = state.dataset ?? "";
3531
3831
  if (dataset.includes(".")) {
3532
3832
  const [datasetProject, ...rest] = dataset.split(".");
3533
3833
  return { datasetProject, datasetId: rest.join(".") };
3534
3834
  }
3535
- return { datasetProject: state.project ?? "", datasetId: dataset };
3835
+ return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
3536
3836
  }
3537
3837
  var bigqueryOauthSetupFlow = {
3538
3838
  initialState: () => ({}),
3539
3839
  steps: [
3540
3840
  {
3541
- slug: "project",
3841
+ slug: "billingProject",
3542
3842
  type: "select",
3843
+ allowFreeText: false,
3543
3844
  question: {
3544
- 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",
3545
- en: "Select the GCP project to use for setup (also required as the billing project when querying public datasets)"
3845
+ 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",
3846
+ en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
3546
3847
  },
3547
3848
  async fetchOptions(_state, rt) {
3548
3849
  const projects = await listProjects2(rt.config.proxyFetch);
@@ -3551,7 +3852,40 @@ var bigqueryOauthSetupFlow = {
3551
3852
  label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
3552
3853
  }));
3553
3854
  },
3554
- applyAnswer: (state, answer) => ({ ...state, project: answer[0] })
3855
+ applyAnswer: (state, answer) => ({
3856
+ ...state,
3857
+ billingProject: answer[0]
3858
+ }),
3859
+ toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
3860
+ },
3861
+ {
3862
+ slug: "databaseProject",
3863
+ type: "select",
3864
+ question: {
3865
+ 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",
3866
+ en: "Select the GCP project where your data resides"
3867
+ },
3868
+ async fetchOptions(state, rt) {
3869
+ if (!state.billingProject) return [];
3870
+ const sameAsBillingOption = {
3871
+ value: SAME_AS_BILLING2,
3872
+ label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
3873
+ };
3874
+ const projects = await listProjects2(rt.config.proxyFetch);
3875
+ const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
3876
+ value: p.projectId,
3877
+ label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
3878
+ }));
3879
+ const publicProjectOption = {
3880
+ value: "bigquery-public-data",
3881
+ 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)"
3882
+ };
3883
+ return [sameAsBillingOption, ...projectOptions, publicProjectOption];
3884
+ },
3885
+ applyAnswer: (state, answer) => ({
3886
+ ...state,
3887
+ databaseProject: answer[0] === SAME_AS_BILLING2 ? state.billingProject : answer[0]
3888
+ })
3555
3889
  },
3556
3890
  {
3557
3891
  slug: "dataset",
@@ -3561,8 +3895,11 @@ var bigqueryOauthSetupFlow = {
3561
3895
  en: "Select the dataset to use for setup"
3562
3896
  },
3563
3897
  async fetchOptions(state, rt) {
3564
- if (!state.project) return [];
3565
- const datasets = await listDatasets2(rt.config.proxyFetch, state.project);
3898
+ if (!state.databaseProject) return [];
3899
+ const datasets = await listDatasets2(
3900
+ rt.config.proxyFetch,
3901
+ state.databaseProject
3902
+ );
3566
3903
  const projectDatasetOptions = datasets.map((d) => ({
3567
3904
  value: d.datasetId,
3568
3905
  label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
@@ -3579,70 +3916,145 @@ var bigqueryOauthSetupFlow = {
3579
3916
  slug: "tables",
3580
3917
  type: "multiSelect",
3581
3918
  question: {
3582
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
3583
- en: "Select target tables (multi-select allowed)"
3919
+ 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",
3920
+ en: "Select target tables and views (multi-select allowed)"
3584
3921
  },
3585
3922
  async fetchOptions(state, rt) {
3586
- if (!state.project || !state.dataset) return [];
3923
+ if (!state.billingProject || !state.dataset) return [];
3587
3924
  const { datasetProject, datasetId } = resolveDatasetRef2(state);
3588
3925
  const rows = await runQuery6(
3589
3926
  rt.config.proxyFetch,
3590
- state.project,
3927
+ state.billingProject,
3591
3928
  `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3592
3929
  );
3593
- const tableOptions = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name).map((value) => ({ value }));
3930
+ const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3931
+ const { singles, candidates } = detectDateShardCandidates(tableNames);
3932
+ const confirmedGroups = [];
3933
+ const rejectedSingles = [];
3934
+ for (const candidate of candidates) {
3935
+ const [first, second] = candidate.members;
3936
+ const colRows = await runQuery6(
3937
+ rt.config.proxyFetch,
3938
+ state.billingProject,
3939
+ `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`
3940
+ );
3941
+ const colsA = colRows.filter(
3942
+ (r) => String(r["table_name"]) === first
3943
+ );
3944
+ const colsB = colRows.filter(
3945
+ (r) => String(r["table_name"]) === second
3946
+ );
3947
+ if (schemasMatch(colsA, colsB)) {
3948
+ confirmedGroups.push(candidate);
3949
+ } else {
3950
+ rejectedSingles.push(...candidate.members);
3951
+ }
3952
+ }
3953
+ const allSingles = [...singles, ...rejectedSingles];
3594
3954
  return [
3595
3955
  {
3596
3956
  value: ALL_TABLES5,
3597
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
3957
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
3598
3958
  },
3599
- ...tableOptions
3959
+ ...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
3600
3960
  ];
3601
3961
  },
3602
3962
  applyAnswer: (state, answer) => ({ ...state, tables: answer })
3603
3963
  }
3604
3964
  ],
3605
3965
  async finalize(state, rt) {
3606
- if (!state.project || !state.dataset || !state.tables) {
3966
+ if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
3607
3967
  throw new Error("BigQuery OAuth setup: incomplete state on finalize");
3608
3968
  }
3609
- const billingProject = state.project;
3969
+ const billingProject = state.billingProject;
3610
3970
  const { datasetProject, datasetId } = resolveDatasetRef2(state);
3611
- const targetTables = await resolveSetupSelection({
3612
- selected: state.tables,
3613
- allSentinel: ALL_TABLES5,
3614
- fetchAll: async () => {
3615
- const rows = await runQuery6(
3616
- rt.config.proxyFetch,
3617
- billingProject,
3618
- `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3619
- );
3620
- return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3621
- },
3622
- limit: BIGQUERY_OAUTH_SETUP_MAX_TABLES
3623
- });
3971
+ const fetchAllTableNames = async () => {
3972
+ const rows = await runQuery6(
3973
+ rt.config.proxyFetch,
3974
+ billingProject,
3975
+ `SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
3976
+ );
3977
+ return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
3978
+ };
3979
+ let entries;
3980
+ if (state.tables.includes(ALL_TABLES5)) {
3981
+ const allNames = await fetchAllTableNames();
3982
+ const { singles, candidates } = detectDateShardCandidates(allNames);
3983
+ entries = [
3984
+ ...candidates.map(
3985
+ (g) => ({
3986
+ type: "shardGroup",
3987
+ prefix: g.prefix,
3988
+ count: g.count,
3989
+ representative: g.members[0]
3990
+ })
3991
+ ),
3992
+ ...singles.map((name) => ({ type: "table", name }))
3993
+ ];
3994
+ } else {
3995
+ const shardSelections = state.tables.filter(isShardGroupValue);
3996
+ const tableSelections = state.tables.filter(
3997
+ (v) => !isShardGroupValue(v)
3998
+ );
3999
+ entries = tableSelections.map(
4000
+ (name) => ({ type: "table", name })
4001
+ );
4002
+ if (shardSelections.length > 0) {
4003
+ const allNames = await fetchAllTableNames();
4004
+ for (const value of shardSelections) {
4005
+ const prefix = getShardGroupPrefix(value);
4006
+ const members = allNames.filter((n) => {
4007
+ const parsed = extractDateShardSuffix(n);
4008
+ return parsed != null && parsed.prefix === prefix;
4009
+ });
4010
+ if (members.length > 0) {
4011
+ entries.push({
4012
+ type: "shardGroup",
4013
+ prefix,
4014
+ count: members.length,
4015
+ representative: members[0]
4016
+ });
4017
+ }
4018
+ }
4019
+ }
4020
+ }
4021
+ entries = entries.slice(0, BIGQUERY_OAUTH_SETUP_MAX_TABLES);
4022
+ const queryColumns = async (tableName) => runQuery6(
4023
+ rt.config.proxyFetch,
4024
+ billingProject,
4025
+ `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
4026
+ );
3624
4027
  const sections = [
3625
4028
  "## BigQuery (OAuth)",
3626
4029
  "",
3627
4030
  `### Billing project: ${billingProject}`,
3628
4031
  "",
4032
+ `### Database project: ${state.databaseProject}`,
4033
+ "",
3629
4034
  `#### Dataset: ${datasetProject}.${datasetId}`,
3630
4035
  ""
3631
4036
  ];
3632
- for (const table of targetTables) {
3633
- const cols = await runQuery6(
3634
- rt.config.proxyFetch,
3635
- billingProject,
3636
- `SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${table.replaceAll("'", "''")}' ORDER BY ordinal_position`
3637
- );
3638
- sections.push(`##### Table: ${table}`, "");
4037
+ for (const entry of entries) {
4038
+ const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
4039
+ const cols = await queryColumns(tableName);
4040
+ if (entry.type === "shardGroup") {
4041
+ sections.push(
4042
+ `##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
4043
+ ""
4044
+ );
4045
+ sections.push(
4046
+ `_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
4047
+ ""
4048
+ );
4049
+ } else {
4050
+ sections.push(`##### Table: ${entry.name}`, "");
4051
+ }
3639
4052
  sections.push("| Column | Type | Nullable |");
3640
4053
  sections.push("|--------|------|----------|");
3641
4054
  for (const c of cols) {
3642
- const name = String(c["column_name"] ?? "");
3643
- const type = String(c["data_type"] ?? "");
3644
- const nullable = String(c["is_nullable"] ?? "");
3645
- sections.push(`| ${name} | ${type} | ${nullable} |`);
4055
+ sections.push(
4056
+ `| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
4057
+ );
3646
4058
  }
3647
4059
  sections.push("");
3648
4060
  }
@@ -5351,14 +5763,15 @@ function isInternalSchema2(name) {
5351
5763
  function quoteLiteral(value) {
5352
5764
  return "'" + value.replace(/'/g, "''") + "'";
5353
5765
  }
5354
- async function fetchTableNames3(params, schema) {
5766
+ async function fetchTableAndViewNames(params, schema) {
5355
5767
  const rows = await runQuery7(
5356
5768
  params,
5357
- `SELECT tablename FROM pg_tables
5358
- WHERE schemaname = ${quoteLiteral(schema)}
5359
- ORDER BY tablename`
5769
+ `SELECT table_name FROM information_schema.tables
5770
+ WHERE table_schema = ${quoteLiteral(schema)}
5771
+ AND table_type IN ('BASE TABLE', 'VIEW')
5772
+ ORDER BY table_name`
5360
5773
  );
5361
- return rows.map((r) => String(r["tablename"] ?? "")).filter((name) => name);
5774
+ return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
5362
5775
  }
5363
5776
  var redshiftSetupFlow = {
5364
5777
  initialState: () => ({}),
@@ -5373,9 +5786,11 @@ var redshiftSetupFlow = {
5373
5786
  async fetchOptions(_state, rt) {
5374
5787
  const rows = await runQuery7(
5375
5788
  rt.params,
5376
- `SELECT DISTINCT schemaname FROM pg_tables ORDER BY schemaname`
5789
+ `SELECT DISTINCT table_schema FROM information_schema.tables
5790
+ WHERE table_type IN ('BASE TABLE', 'VIEW')
5791
+ ORDER BY table_schema`
5377
5792
  );
5378
- return rows.map((r) => String(r["schemaname"] ?? "")).filter((name) => name && !isInternalSchema2(name)).map((value) => ({ value }));
5793
+ return rows.map((r) => String(r["table_schema"] ?? "")).filter((name) => name && !isInternalSchema2(name)).map((value) => ({ value }));
5379
5794
  },
5380
5795
  applyAnswer: (state, answer) => ({ ...state, schema: answer[0] })
5381
5796
  },
@@ -5383,17 +5798,17 @@ var redshiftSetupFlow = {
5383
5798
  slug: "tables",
5384
5799
  type: "multiSelect",
5385
5800
  question: {
5386
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
5387
- en: "Select target tables (multi-select allowed)"
5801
+ 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",
5802
+ en: "Select target tables and views (multi-select allowed)"
5388
5803
  },
5389
5804
  async fetchOptions(state, rt) {
5390
5805
  if (!state.schema) return [];
5391
- const names = await fetchTableNames3(rt.params, state.schema);
5806
+ const names = await fetchTableAndViewNames(rt.params, state.schema);
5392
5807
  const tableOptions = names.map((value) => ({ value }));
5393
5808
  return [
5394
5809
  {
5395
5810
  value: ALL_TABLES7,
5396
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
5811
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
5397
5812
  },
5398
5813
  ...tableOptions
5399
5814
  ];
@@ -5409,9 +5824,21 @@ var redshiftSetupFlow = {
5409
5824
  const targetTables = await resolveSetupSelection({
5410
5825
  selected: state.tables,
5411
5826
  allSentinel: ALL_TABLES7,
5412
- fetchAll: () => fetchTableNames3(rt.params, schema),
5827
+ fetchAll: () => fetchTableAndViewNames(rt.params, schema),
5413
5828
  limit: REDSHIFT_SETUP_MAX_TABLES
5414
5829
  });
5830
+ const typeRows = targetTables.length > 0 ? await runQuery7(
5831
+ rt.params,
5832
+ `SELECT table_name, table_type FROM information_schema.tables
5833
+ WHERE table_schema = ${quoteLiteral(schema)}
5834
+ AND table_name IN (${targetTables.map(quoteLiteral).join(", ")})`
5835
+ ) : [];
5836
+ const typeMap = new Map(
5837
+ typeRows.map((r) => [
5838
+ String(r["table_name"] ?? ""),
5839
+ String(r["table_type"] ?? "BASE TABLE")
5840
+ ])
5841
+ );
5415
5842
  const sections = [
5416
5843
  "## Redshift",
5417
5844
  "",
@@ -5419,6 +5846,7 @@ var redshiftSetupFlow = {
5419
5846
  ""
5420
5847
  ];
5421
5848
  for (const table of targetTables) {
5849
+ const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
5422
5850
  const cols = await runQuery7(
5423
5851
  rt.params,
5424
5852
  `SELECT column_name, data_type, is_nullable, column_default
@@ -5427,7 +5855,7 @@ var redshiftSetupFlow = {
5427
5855
  AND table_name = ${quoteLiteral(table)}
5428
5856
  ORDER BY ordinal_position`
5429
5857
  );
5430
- sections.push(`#### Table: ${table}`, "");
5858
+ sections.push(`#### ${heading}: ${table}`, "");
5431
5859
  sections.push("| Column | Type | Nullable | Default |");
5432
5860
  sections.push("|--------|------|----------|---------|");
5433
5861
  for (const c of cols) {
@@ -5855,8 +6283,8 @@ var databricksSetupFlow = {
5855
6283
  slug: "tables",
5856
6284
  type: "multiSelect",
5857
6285
  question: {
5858
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
5859
- en: "Select target tables (multi-select allowed)"
6286
+ 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",
6287
+ en: "Select target tables and views (multi-select allowed)"
5860
6288
  },
5861
6289
  async fetchOptions(state, rt) {
5862
6290
  if (!state.catalog || !state.schema) return [];
@@ -5868,7 +6296,7 @@ var databricksSetupFlow = {
5868
6296
  return [
5869
6297
  {
5870
6298
  value: ALL_TABLES8,
5871
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
6299
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
5872
6300
  },
5873
6301
  ...tableOptions
5874
6302
  ];
@@ -7244,15 +7672,6 @@ var parameters13 = {
7244
7672
  type: "base64EncodedJson",
7245
7673
  secret: true,
7246
7674
  required: true
7247
- }),
7248
- propertyId: new ParameterDefinition({
7249
- slug: "property-id",
7250
- name: "Google Analytics Property ID",
7251
- description: "The Google Analytics 4 property ID (e.g., 123456789).",
7252
- envVarBaseKey: "GA_PROPERTY_ID",
7253
- type: "text",
7254
- secret: false,
7255
- required: true
7256
7675
  })
7257
7676
  };
7258
7677
 
@@ -7260,6 +7679,7 @@ var parameters13 = {
7260
7679
  import * as crypto2 from "crypto";
7261
7680
  var TOKEN_URL = "https://oauth2.googleapis.com/token";
7262
7681
  var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta";
7682
+ var DATA_BASE_URL = "https://analyticsdata.googleapis.com/v1beta";
7263
7683
  var SCOPE = "https://www.googleapis.com/auth/analytics.readonly";
7264
7684
  function base64url(input) {
7265
7685
  const buf = typeof input === "string" ? Buffer.from(input) : input;
@@ -7341,10 +7761,25 @@ async function adminFetch(params, path5, init) {
7341
7761
  headers.set("Authorization", `Bearer ${accessToken}`);
7342
7762
  return fetch(url, { ...init, headers });
7343
7763
  }
7764
+ async function dataFetch(params, path5, init) {
7765
+ const keyJsonBase64 = params[parameters13.serviceAccountKeyJsonBase64.slug];
7766
+ if (!keyJsonBase64) {
7767
+ throw new Error(
7768
+ "google-analytics: missing required parameter: service-account-key-json-base64"
7769
+ );
7770
+ }
7771
+ const serviceAccountKey = decodeServiceAccount(keyJsonBase64);
7772
+ const accessToken = await getAccessToken(serviceAccountKey);
7773
+ const url = `${DATA_BASE_URL}${path5.startsWith("/") ? "" : "/"}${path5}`;
7774
+ const headers = new Headers(init?.headers);
7775
+ headers.set("Authorization", `Bearer ${accessToken}`);
7776
+ return fetch(url, { ...init, headers });
7777
+ }
7344
7778
 
7345
7779
  // ../connectors/src/connectors/google-analytics/setup-flow.ts
7346
7780
  var ALL_PROPERTIES = "__ALL_PROPERTIES__";
7347
7781
  var GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES = 20;
7782
+ var METADATA_DISPLAY_LIMIT = 30;
7348
7783
  async function listAccountSummaries(params) {
7349
7784
  const summaries = [];
7350
7785
  let pageToken;
@@ -7371,6 +7806,48 @@ async function getProperty(params, propertyId) {
7371
7806
  if (!res.ok) return null;
7372
7807
  return await res.json();
7373
7808
  }
7809
+ async function getMetadata(params, propertyId) {
7810
+ try {
7811
+ const res = await dataFetch(
7812
+ params,
7813
+ `/properties/${propertyId}/metadata`
7814
+ );
7815
+ if (!res.ok) return { dimensions: [], metrics: [] };
7816
+ const data = await res.json();
7817
+ return {
7818
+ dimensions: data.dimensions ?? [],
7819
+ metrics: data.metrics ?? []
7820
+ };
7821
+ } catch {
7822
+ return { dimensions: [], metrics: [] };
7823
+ }
7824
+ }
7825
+ function appendMetadataSection(sections, dimensions, metrics) {
7826
+ if (dimensions.length > 0) {
7827
+ sections.push(`#### Dimensions (${dimensions.length})`, "");
7828
+ for (const d of dimensions.slice(0, METADATA_DISPLAY_LIMIT)) {
7829
+ sections.push(`- ${d.apiName ?? d.uiName ?? "(unknown)"}`);
7830
+ }
7831
+ if (dimensions.length > METADATA_DISPLAY_LIMIT) {
7832
+ sections.push(
7833
+ `- \u2026and ${dimensions.length - METADATA_DISPLAY_LIMIT} more`
7834
+ );
7835
+ }
7836
+ sections.push("");
7837
+ }
7838
+ if (metrics.length > 0) {
7839
+ sections.push(`#### Metrics (${metrics.length})`, "");
7840
+ for (const m of metrics.slice(0, METADATA_DISPLAY_LIMIT)) {
7841
+ sections.push(`- ${m.apiName ?? m.uiName ?? "(unknown)"}`);
7842
+ }
7843
+ if (metrics.length > METADATA_DISPLAY_LIMIT) {
7844
+ sections.push(
7845
+ `- \u2026and ${metrics.length - METADATA_DISPLAY_LIMIT} more`
7846
+ );
7847
+ }
7848
+ sections.push("");
7849
+ }
7850
+ }
7374
7851
  var googleAnalyticsSetupFlow = {
7375
7852
  initialState: () => ({}),
7376
7853
  steps: [
@@ -7382,15 +7859,19 @@ var googleAnalyticsSetupFlow = {
7382
7859
  en: "Select a Google Analytics account"
7383
7860
  },
7384
7861
  async fetchOptions(_state, rt) {
7385
- const summaries = await listAccountSummaries(rt.params);
7386
- return summaries.map((s) => {
7387
- const accountResource = s.account ?? s.name ?? "";
7388
- if (!accountResource) return null;
7389
- return {
7390
- value: accountResource,
7391
- label: s.displayName ?? accountResource
7392
- };
7393
- }).filter((v) => v != null);
7862
+ try {
7863
+ const summaries = await listAccountSummaries(rt.params);
7864
+ return summaries.map((s) => {
7865
+ const accountResource = s.account ?? s.name ?? "";
7866
+ if (!accountResource) return null;
7867
+ return {
7868
+ value: accountResource,
7869
+ label: s.displayName ?? accountResource
7870
+ };
7871
+ }).filter((v) => v != null);
7872
+ } catch {
7873
+ return [];
7874
+ }
7394
7875
  },
7395
7876
  applyAnswer: (state, answer) => ({ ...state, account: answer[0] })
7396
7877
  },
@@ -7403,68 +7884,117 @@ var googleAnalyticsSetupFlow = {
7403
7884
  },
7404
7885
  async fetchOptions(state, rt) {
7405
7886
  if (!state.account) return [];
7406
- const summaries = await listAccountSummaries(rt.params);
7407
- const account = summaries.find(
7408
- (s) => (s.account ?? s.name) === state.account
7409
- );
7410
- const props = (account?.propertySummaries ?? []).map((p) => {
7411
- const id = propertyIdFromResource(p.property);
7412
- if (!id) return null;
7413
- return {
7414
- value: id,
7415
- label: p.displayName ? `${p.displayName} (${id})` : id
7416
- };
7417
- }).filter((v) => v != null);
7418
- if (props.length === 0) return [];
7419
- return [
7420
- {
7421
- value: ALL_PROPERTIES,
7422
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
7423
- },
7424
- ...props
7425
- ];
7887
+ try {
7888
+ const summaries = await listAccountSummaries(rt.params);
7889
+ const account = summaries.find(
7890
+ (s) => (s.account ?? s.name) === state.account
7891
+ );
7892
+ const props = (account?.propertySummaries ?? []).map((p) => {
7893
+ const id = propertyIdFromResource(p.property);
7894
+ if (!id) return null;
7895
+ return {
7896
+ value: id,
7897
+ label: p.displayName ? `${p.displayName} (${id})` : id
7898
+ };
7899
+ }).filter((v) => v != null);
7900
+ if (props.length === 0) return [];
7901
+ return [
7902
+ {
7903
+ value: ALL_PROPERTIES,
7904
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
7905
+ },
7906
+ ...props
7907
+ ];
7908
+ } catch {
7909
+ return [];
7910
+ }
7426
7911
  },
7427
7912
  applyAnswer: (state, answer) => ({ ...state, properties: answer })
7913
+ },
7914
+ {
7915
+ slug: "manualPropertyId",
7916
+ type: "text",
7917
+ question: {
7918
+ 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",
7919
+ en: "Enter your GA4 Property ID (e.g., 123456789). Found in GA4 Admin > Property Settings."
7920
+ },
7921
+ async fetchOptions(state) {
7922
+ if (state.properties?.length) return [];
7923
+ return [{ value: "_show", label: "" }];
7924
+ },
7925
+ applyAnswer: (state, answer) => ({
7926
+ ...state,
7927
+ manualPropertyId: answer[0]
7928
+ })
7428
7929
  }
7429
7930
  ],
7430
7931
  async finalize(state, rt) {
7431
- if (!state.account || !state.properties) {
7432
- throw new Error("Google Analytics setup: incomplete state on finalize");
7433
- }
7434
- const summaries = await listAccountSummaries(rt.params);
7435
- const account = summaries.find(
7436
- (s) => (s.account ?? s.name) === state.account
7437
- );
7438
- const accountLabel2 = account?.displayName ?? state.account.replace(/^accounts\//, "");
7439
- const targetPropertyIds = await resolveSetupSelection({
7440
- selected: state.properties,
7441
- allSentinel: ALL_PROPERTIES,
7442
- fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
7443
- limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
7444
- });
7445
- const sections = [
7446
- "## Google Analytics",
7447
- "",
7448
- `### Account: ${accountLabel2}`,
7449
- ""
7450
- ];
7451
- if (targetPropertyIds.length === 0) {
7452
- sections.push("_No properties selected._", "");
7932
+ const sections = ["## Google Analytics", ""];
7933
+ if (state.account && state.properties) {
7934
+ let summaries = [];
7935
+ try {
7936
+ summaries = await listAccountSummaries(rt.params);
7937
+ } catch {
7938
+ }
7939
+ const account = summaries.find(
7940
+ (s) => (s.account ?? s.name) === state.account
7941
+ );
7942
+ const accountLabel2 = account?.displayName ?? state.account.replace(/^accounts\//, "");
7943
+ const targetPropertyIds = await resolveSetupSelection({
7944
+ selected: state.properties,
7945
+ allSentinel: ALL_PROPERTIES,
7946
+ fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
7947
+ limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
7948
+ });
7949
+ sections.push(`### Account: ${accountLabel2}`, "");
7950
+ if (targetPropertyIds.length === 0) {
7951
+ sections.push("_No properties selected._", "");
7952
+ return sections.join("\n");
7953
+ }
7954
+ sections.push(
7955
+ "| Property ID | Display Name | Time Zone | Currency | Industry |"
7956
+ );
7957
+ sections.push(
7958
+ "|-------------|--------------|-----------|----------|----------|"
7959
+ );
7960
+ for (const pid of targetPropertyIds) {
7961
+ const prop = await getProperty(rt.params, pid).catch(() => null);
7962
+ const displayName3 = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
7963
+ const timeZone = prop?.timeZone ?? "-";
7964
+ const currency = prop?.currencyCode ?? "-";
7965
+ const industry = (prop?.industryCategory ?? "-").replace(
7966
+ /\|/g,
7967
+ "\\|"
7968
+ );
7969
+ sections.push(
7970
+ `| ${pid} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
7971
+ );
7972
+ }
7973
+ sections.push("");
7974
+ const firstPropertyId = targetPropertyIds[0];
7975
+ if (firstPropertyId) {
7976
+ const { dimensions, metrics } = await getMetadata(
7977
+ rt.params,
7978
+ firstPropertyId
7979
+ );
7980
+ appendMetadataSection(sections, dimensions, metrics);
7981
+ }
7453
7982
  return sections.join("\n");
7454
7983
  }
7455
- sections.push("| Property ID | Display Name | Time Zone | Currency | Industry |");
7456
- sections.push("|-------------|--------------|-----------|----------|----------|");
7457
- for (const propertyId of targetPropertyIds) {
7458
- const prop = await getProperty(rt.params, propertyId);
7459
- const displayName3 = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
7460
- const timeZone = prop?.timeZone ?? "-";
7461
- const currency = prop?.currencyCode ?? "-";
7462
- const industry = (prop?.industryCategory ?? "-").replace(/\|/g, "\\|");
7463
- sections.push(
7464
- `| ${propertyId} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
7984
+ const propertyId = state.manualPropertyId;
7985
+ if (propertyId) {
7986
+ sections.push(`### Property: ${propertyId}`, "");
7987
+ const { dimensions, metrics } = await getMetadata(
7988
+ rt.params,
7989
+ propertyId
7465
7990
  );
7991
+ appendMetadataSection(sections, dimensions, metrics);
7992
+ return sections.join("\n");
7466
7993
  }
7467
- sections.push("");
7994
+ sections.push(
7995
+ "_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._",
7996
+ ""
7997
+ );
7468
7998
  return sections.join("\n");
7469
7999
  }
7470
8000
  };
@@ -7476,8 +8006,9 @@ var REQUEST_TIMEOUT_MS10 = 6e4;
7476
8006
  var inputSchema20 = z20.object({
7477
8007
  toolUseIntent: z20.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
7478
8008
  connectionId: z20.string().describe("ID of the Google Analytics connection to use"),
8009
+ propertyId: z20.string().describe("GA4 property ID (e.g., '123456789')"),
7479
8010
  method: z20.enum(["GET", "POST"]).describe("HTTP method"),
7480
- path: z20.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."),
8011
+ path: z20.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is replaced with the propertyId parameter."),
7481
8012
  body: z20.record(z20.string(), z20.unknown()).optional().describe("POST request body (JSON)")
7482
8013
  });
7483
8014
  var outputSchema20 = z20.discriminatedUnion("success", [
@@ -7495,10 +8026,10 @@ var requestTool3 = new ConnectorTool({
7495
8026
  name: "request",
7496
8027
  description: `Send authenticated requests to the Google Analytics Data API.
7497
8028
  Authentication is handled automatically using a service account.
7498
- {propertyId} in the path is automatically replaced with the connection's property-id.`,
8029
+ {propertyId} in the path is automatically replaced with the propertyId parameter.`,
7499
8030
  inputSchema: inputSchema20,
7500
8031
  outputSchema: outputSchema20,
7501
- async execute({ connectionId, method, path: path5, body }, connections) {
8032
+ async execute({ connectionId, propertyId, method, path: path5, body }, connections) {
7502
8033
  const connection = connections.find((c) => c.id === connectionId);
7503
8034
  if (!connection) {
7504
8035
  return { success: false, error: `Connection ${connectionId} not found` };
@@ -7507,7 +8038,6 @@ Authentication is handled automatically using a service account.
7507
8038
  try {
7508
8039
  const { GoogleAuth } = await import("google-auth-library");
7509
8040
  const keyJsonBase64 = parameters13.serviceAccountKeyJsonBase64.getValue(connection);
7510
- const propertyId = parameters13.propertyId.getValue(connection);
7511
8041
  const credentials = JSON.parse(
7512
8042
  Buffer.from(keyJsonBase64, "base64").toString("utf-8")
7513
8043
  );
@@ -7567,16 +8097,16 @@ var googleAnalyticsConnector = new ConnectorPlugin({
7567
8097
  systemPrompt: {
7568
8098
  en: `### Tools
7569
8099
 
7570
- - \`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.
8100
+ - \`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.
7571
8101
 
7572
8102
  ### Business Logic
7573
8103
 
7574
8104
  The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
7575
8105
 
7576
8106
  SDK methods (client created via \`connection(connectionId)\`):
7577
- - \`client.runReport(request)\` \u2014 run a GA4 report
7578
- - \`client.runRealtimeReport(request)\` \u2014 run a realtime report
7579
- - \`client.getMetadata()\` \u2014 fetch available dimensions/metrics
8107
+ - \`client.runReport(propertyId, request)\` \u2014 run a GA4 report
8108
+ - \`client.runRealtimeReport(propertyId, request)\` \u2014 run a realtime report
8109
+ - \`client.getMetadata(propertyId)\` \u2014 fetch available dimensions/metrics
7580
8110
  - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
7581
8111
 
7582
8112
  \`\`\`ts
@@ -7586,12 +8116,13 @@ import { connection } from "@squadbase/vite-server/connectors/google-analytics";
7586
8116
  const ga = connection("<connectionId>");
7587
8117
 
7588
8118
  export default async function handler(c: Context) {
7589
- const { startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8119
+ const { propertyId, startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8120
+ propertyId: string;
7590
8121
  startDate?: string;
7591
8122
  endDate?: string;
7592
8123
  }>();
7593
8124
 
7594
- const { rows } = await ga.runReport({
8125
+ const { rows } = await ga.runReport(propertyId, {
7595
8126
  dateRanges: [{ startDate, endDate }],
7596
8127
  dimensions: [{ name: "date" }],
7597
8128
  metrics: [{ name: "activeUsers" }, { name: "sessions" }],
@@ -7635,16 +8166,16 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
7635
8166
  - Relative: \`"today"\`, \`"yesterday"\`, \`"7daysAgo"\`, \`"30daysAgo"\``,
7636
8167
  ja: `### \u30C4\u30FC\u30EB
7637
8168
 
7638
- - \`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
8169
+ - \`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
7639
8170
 
7640
8171
  ### Business Logic
7641
8172
 
7642
8173
  \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
7643
8174
 
7644
8175
  SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
7645
- - \`client.runReport(request)\` \u2014 GA4\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
7646
- - \`client.runRealtimeReport(request)\` \u2014 \u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
7647
- - \`client.getMetadata()\` \u2014 \u5229\u7528\u53EF\u80FD\u306A\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3/\u30E1\u30C8\u30EA\u30AF\u30B9\u3092\u53D6\u5F97
8176
+ - \`client.runReport(propertyId, request)\` \u2014 GA4\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
8177
+ - \`client.runRealtimeReport(propertyId, request)\` \u2014 \u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u3092\u5B9F\u884C
8178
+ - \`client.getMetadata(propertyId)\` \u2014 \u5229\u7528\u53EF\u80FD\u306A\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3/\u30E1\u30C8\u30EA\u30AF\u30B9\u3092\u53D6\u5F97
7648
8179
  - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
7649
8180
 
7650
8181
  \`\`\`ts
@@ -7654,12 +8185,13 @@ import { connection } from "@squadbase/vite-server/connectors/google-analytics";
7654
8185
  const ga = connection("<connectionId>");
7655
8186
 
7656
8187
  export default async function handler(c: Context) {
7657
- const { startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8188
+ const { propertyId, startDate = "7daysAgo", endDate = "today" } = await c.req.json<{
8189
+ propertyId: string;
7658
8190
  startDate?: string;
7659
8191
  endDate?: string;
7660
8192
  }>();
7661
8193
 
7662
- const { rows } = await ga.runReport({
8194
+ const { rows } = await ga.runReport(propertyId, {
7663
8195
  dateRanges: [{ startDate, endDate }],
7664
8196
  dimensions: [{ name: "date" }],
7665
8197
  metrics: [{ name: "activeUsers" }, { name: "sessions" }],
@@ -7713,12 +8245,12 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
7713
8245
  };
7714
8246
  }
7715
8247
  try {
7716
- const res = await adminFetch(params, "/accountSummaries?pageSize=1");
8248
+ const res = await dataFetch(params, `/metadata`);
7717
8249
  if (!res.ok) {
7718
8250
  const body = await res.text().catch(() => res.statusText);
7719
8251
  return {
7720
8252
  success: false,
7721
- error: `google-analytics: accountSummaries failed (${res.status}): ${body}`
8253
+ error: `Google Analytics API failed: HTTP ${res.status} ${body}`
7722
8254
  };
7723
8255
  }
7724
8256
  return { success: true };
@@ -19358,7 +19890,7 @@ function escapeIdentifier(name) {
19358
19890
  function quoteLiteral2(value) {
19359
19891
  return "'" + value.replace(/'/g, "''") + "'";
19360
19892
  }
19361
- async function fetchTableNames4(params, database) {
19893
+ async function fetchTableNames3(params, database) {
19362
19894
  const rows = await runQuery9(
19363
19895
  params,
19364
19896
  `SELECT name FROM system.tables
@@ -19387,17 +19919,17 @@ var clickhouseSetupFlow = {
19387
19919
  slug: "tables",
19388
19920
  type: "multiSelect",
19389
19921
  question: {
19390
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
19391
- en: "Select target tables (multi-select allowed)"
19922
+ 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",
19923
+ en: "Select target tables and views (multi-select allowed)"
19392
19924
  },
19393
19925
  async fetchOptions(state, rt) {
19394
19926
  if (!state.database) return [];
19395
- const names = await fetchTableNames4(rt.params, state.database);
19927
+ const names = await fetchTableNames3(rt.params, state.database);
19396
19928
  const tableOptions = names.map((value) => ({ value }));
19397
19929
  return [
19398
19930
  {
19399
19931
  value: ALL_TABLES11,
19400
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
19932
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
19401
19933
  },
19402
19934
  ...tableOptions
19403
19935
  ];
@@ -19413,7 +19945,7 @@ var clickhouseSetupFlow = {
19413
19945
  const targetTables = await resolveSetupSelection({
19414
19946
  selected: state.tables,
19415
19947
  allSentinel: ALL_TABLES11,
19416
- fetchAll: () => fetchTableNames4(rt.params, database),
19948
+ fetchAll: () => fetchTableNames3(rt.params, database),
19417
19949
  limit: CLICKHOUSE_SETUP_MAX_TABLES
19418
19950
  });
19419
19951
  const sections = [
@@ -24012,7 +24544,7 @@ export default async function handler(c: Context) {
24012
24544
  const region = params[parameters50.region.slug];
24013
24545
  const baseUrl = region === "eu" ? "https://api-eu.customer.io" : "https://api.customer.io";
24014
24546
  try {
24015
- const res = await fetch(`${baseUrl}/v1/accounts/region`, {
24547
+ const res = await fetch(`${baseUrl}/v1/segments`, {
24016
24548
  method: "GET",
24017
24549
  headers: {
24018
24550
  Authorization: `Bearer ${appApiKey}`,
@@ -29568,7 +30100,7 @@ function apiFetch27(params, path5, init) {
29568
30100
  // ../connectors/src/connectors/gamma/setup-flow.ts
29569
30101
  var ALL_FOLDERS = "__ALL_FOLDERS__";
29570
30102
  var GAMMA_SETUP_MAX_FOLDERS = 20;
29571
- var FOLDERS_PAGE_LIMIT = 100;
30103
+ var FOLDERS_PAGE_LIMIT = 50;
29572
30104
  async function listAllFolders(params) {
29573
30105
  const results = [];
29574
30106
  let after;
@@ -29589,7 +30121,7 @@ async function listAllFolders(params) {
29589
30121
  return results;
29590
30122
  }
29591
30123
  async function listThemes(params) {
29592
- const res = await apiFetch27(params, "/themes?limit=100");
30124
+ const res = await apiFetch27(params, "/themes?limit=50");
29593
30125
  if (!res.ok) {
29594
30126
  return [];
29595
30127
  }
@@ -33426,7 +33958,8 @@ var semrushOnboarding = new ConnectorOnboarding({
33426
33958
  });
33427
33959
 
33428
33960
  // ../connectors/src/connectors/semrush/utils.ts
33429
- var PROJECTS_BASE_URL = "https://api.semrush.com/management/v1";
33961
+ var BASE_URL59 = "https://api.semrush.com";
33962
+ var PROJECTS_BASE_URL = `${BASE_URL59}/management/v1`;
33430
33963
  function projectsApiFetch(params, path5, init) {
33431
33964
  const apiKey = params[parameters68.apiKey.slug];
33432
33965
  if (!apiKey) {
@@ -33443,10 +33976,103 @@ function projectsApiFetch(params, path5, init) {
33443
33976
  if (!headers.has("Accept")) headers.set("Accept", "application/json");
33444
33977
  return fetch(url.toString(), { ...init, headers });
33445
33978
  }
33979
+ async function reportFetch(params, query) {
33980
+ const apiKey = params[parameters68.apiKey.slug];
33981
+ if (!apiKey) {
33982
+ throw new Error(
33983
+ `semrush: missing required parameter: ${parameters68.apiKey.slug}`
33984
+ );
33985
+ }
33986
+ const url = new URL(`${BASE_URL59}/`);
33987
+ for (const [k, v] of Object.entries(query)) {
33988
+ url.searchParams.set(k, v);
33989
+ }
33990
+ url.searchParams.set("key", apiKey);
33991
+ const res = await fetch(url.toString());
33992
+ const text = await res.text();
33993
+ if (text.startsWith("ERROR ")) throw new Error(text.trim());
33994
+ return parseSemicolonCsv(text);
33995
+ }
33996
+ async function backlinksFetch(params, query) {
33997
+ const apiKey = params[parameters68.apiKey.slug];
33998
+ if (!apiKey) {
33999
+ throw new Error(
34000
+ `semrush: missing required parameter: ${parameters68.apiKey.slug}`
34001
+ );
34002
+ }
34003
+ const url = new URL(`${BASE_URL59}/analytics/v1/`);
34004
+ for (const [k, v] of Object.entries(query)) {
34005
+ url.searchParams.set(k, v);
34006
+ }
34007
+ url.searchParams.set("key", apiKey);
34008
+ const res = await fetch(url.toString());
34009
+ const text = await res.text();
34010
+ if (text.startsWith("ERROR ")) throw new Error(text.trim());
34011
+ return parseSemicolonCsv(text);
34012
+ }
34013
+ function parseSemicolonCsv(raw) {
34014
+ const lines = raw.trim().split("\n").filter(Boolean);
34015
+ if (lines.length === 0) return { columns: [], rows: [] };
34016
+ const columns = lines[0].split(";");
34017
+ const rows = lines.slice(1).map((line) => {
34018
+ const values = line.split(";");
34019
+ const row = {};
34020
+ for (let i = 0; i < columns.length; i++) {
34021
+ row[columns[i]] = values[i] ?? "";
34022
+ }
34023
+ return row;
34024
+ });
34025
+ return { columns, rows };
34026
+ }
33446
34027
 
33447
34028
  // ../connectors/src/connectors/semrush/setup-flow.ts
33448
34029
  var ALL_PROJECTS6 = "__ALL_PROJECTS__";
33449
34030
  var SEMRUSH_SETUP_MAX_PROJECTS = 10;
34031
+ var SEMRUSH_DATABASES = [
34032
+ { value: "us", label: "United States" },
34033
+ { value: "uk", label: "United Kingdom" },
34034
+ { value: "ca", label: "Canada" },
34035
+ { value: "au", label: "Australia" },
34036
+ { value: "de", label: "Germany" },
34037
+ { value: "fr", label: "France" },
34038
+ { value: "es", label: "Spain" },
34039
+ { value: "it", label: "Italy" },
34040
+ { value: "br", label: "Brazil" },
34041
+ { value: "jp", label: "Japan" },
34042
+ { value: "in", label: "India" },
34043
+ { value: "ru", label: "Russia" },
34044
+ { value: "nl", label: "Netherlands" },
34045
+ { value: "se", label: "Sweden" },
34046
+ { value: "mx", label: "Mexico" },
34047
+ { value: "kr", label: "South Korea" },
34048
+ { value: "sg", label: "Singapore" },
34049
+ { value: "hk", label: "Hong Kong" },
34050
+ { value: "tw", label: "Taiwan" }
34051
+ ];
34052
+ var REPORT_TYPE_LABELS = {
34053
+ domain_overview: {
34054
+ en: "Domain Overview (rank, traffic, keyword count)",
34055
+ ja: "Domain Overview (\u30E9\u30F3\u30AF\u30FB\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u30FB\u30AD\u30FC\u30EF\u30FC\u30C9\u6570)"
34056
+ },
34057
+ organic_search: {
34058
+ en: "Organic Search (top organic keywords)",
34059
+ ja: "Organic Search (\u4E0A\u4F4D\u30AA\u30FC\u30AC\u30CB\u30C3\u30AF\u30AD\u30FC\u30EF\u30FC\u30C9)"
34060
+ },
34061
+ paid_search: {
34062
+ en: "Paid Search (top paid keywords)",
34063
+ ja: "Paid Search (\u4E0A\u4F4D\u6709\u6599\u30AD\u30FC\u30EF\u30FC\u30C9)"
34064
+ },
34065
+ backlinks: {
34066
+ en: "Backlinks (referring domains, backlink count)",
34067
+ ja: "Backlinks (\u53C2\u7167\u30C9\u30E1\u30A4\u30F3\u30FB\u88AB\u30EA\u30F3\u30AF\u6570)"
34068
+ }
34069
+ };
34070
+ var REPORT_TYPE_VALUES = [
34071
+ "domain_overview",
34072
+ "organic_search",
34073
+ "paid_search",
34074
+ "backlinks"
34075
+ ];
33450
34076
  function projectId(p) {
33451
34077
  const raw = p.project_id ?? p.id;
33452
34078
  return raw == null ? "" : String(raw);
@@ -33455,7 +34081,7 @@ function projectName(p) {
33455
34081
  return p.project_name ?? p.name ?? p.domain ?? p.url ?? projectId(p);
33456
34082
  }
33457
34083
  function projectDomain(p) {
33458
- return p.domain ?? p.url ?? "";
34084
+ return p.domain ?? p.domain_unicode ?? p.url ?? "";
33459
34085
  }
33460
34086
  function projectCreatedAt(p) {
33461
34087
  return p.created_at ?? p.date_created ?? "";
@@ -33463,13 +34089,19 @@ function projectCreatedAt(p) {
33463
34089
  async function fetchProjects(params) {
33464
34090
  let res;
33465
34091
  try {
33466
- res = await projectsApiFetch(params, "/projects/");
34092
+ res = await projectsApiFetch(params, "/projects");
33467
34093
  } catch (err) {
33468
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
34094
+ return {
34095
+ ok: false,
34096
+ error: err instanceof Error ? err.message : String(err)
34097
+ };
33469
34098
  }
33470
34099
  if (!res.ok) {
33471
34100
  const body2 = await res.text().catch(() => res.statusText);
33472
- return { ok: false, error: `HTTP ${res.status} ${body2 || res.statusText}` };
34101
+ return {
34102
+ ok: false,
34103
+ error: `HTTP ${res.status} ${body2 || res.statusText}`
34104
+ };
33473
34105
  }
33474
34106
  let body;
33475
34107
  try {
@@ -33483,9 +34115,171 @@ async function fetchProjects(params) {
33483
34115
  const projects = Array.isArray(body) ? body : Array.isArray(body?.projects) ? body.projects : Array.isArray(body?.data) ? body.data : [];
33484
34116
  return { ok: true, projects };
33485
34117
  }
34118
+ function formatNumber(n) {
34119
+ return n.toLocaleString("en-US");
34120
+ }
34121
+ async function fetchDomainOverview(params, domain, database) {
34122
+ const sections = [];
34123
+ try {
34124
+ const report = await reportFetch(params, {
34125
+ type: "domain_ranks",
34126
+ domain,
34127
+ database
34128
+ });
34129
+ if (report.rows.length === 0) {
34130
+ sections.push("_No data found for this domain._", "");
34131
+ return sections;
34132
+ }
34133
+ const row = report.rows[0];
34134
+ sections.push("| Metric | Value |");
34135
+ sections.push("|--------|-------|");
34136
+ sections.push(
34137
+ `| Rank | ${row["Rank"] ?? "-"} |`,
34138
+ `| Organic Keywords | ${formatNumber(Number(row["Organic Keywords"]) || 0)} |`,
34139
+ `| Organic Traffic | ${formatNumber(Number(row["Organic Traffic"]) || 0)} |`,
34140
+ `| Organic Cost | $${formatNumber(Number(row["Organic Cost"]) || 0)} |`,
34141
+ `| Adwords Keywords | ${formatNumber(Number(row["Adwords Keywords"]) || 0)} |`,
34142
+ `| Adwords Traffic | ${formatNumber(Number(row["Adwords Traffic"]) || 0)} |`,
34143
+ `| Adwords Cost | $${formatNumber(Number(row["Adwords Cost"]) || 0)} |`
34144
+ );
34145
+ sections.push("");
34146
+ } catch (err) {
34147
+ sections.push(
34148
+ `_Error: ${err instanceof Error ? err.message : String(err)}_`,
34149
+ ""
34150
+ );
34151
+ }
34152
+ return sections;
34153
+ }
34154
+ async function fetchOrganicSearch(params, domain, database) {
34155
+ return fetchKeywordReport(params, "domain_organic", domain, database);
34156
+ }
34157
+ async function fetchPaidSearch(params, domain, database) {
34158
+ return fetchKeywordReport(params, "domain_adwords", domain, database);
34159
+ }
34160
+ async function fetchKeywordReport(params, type, domain, database) {
34161
+ const sections = [];
34162
+ try {
34163
+ const report = await reportFetch(params, {
34164
+ type,
34165
+ domain,
34166
+ database,
34167
+ display_limit: "5"
34168
+ });
34169
+ if (report.rows.length === 0) {
34170
+ sections.push("_No data found._", "");
34171
+ return sections;
34172
+ }
34173
+ sections.push(...renderCsvTable(report, 5));
34174
+ sections.push("");
34175
+ } catch (err) {
34176
+ sections.push(
34177
+ `_Error: ${err instanceof Error ? err.message : String(err)}_`,
34178
+ ""
34179
+ );
34180
+ }
34181
+ return sections;
34182
+ }
34183
+ async function fetchBacklinks(params, domain) {
34184
+ const sections = [];
34185
+ try {
34186
+ const report = await backlinksFetch(params, {
34187
+ type: "backlinks_overview",
34188
+ target: domain,
34189
+ target_type: "root_domain"
34190
+ });
34191
+ if (report.rows.length === 0) {
34192
+ sections.push("_No backlink data found._", "");
34193
+ return sections;
34194
+ }
34195
+ const row = report.rows[0];
34196
+ sections.push("| Metric | Value |");
34197
+ sections.push("|--------|-------|");
34198
+ for (const col of report.columns) {
34199
+ sections.push(`| ${col} | ${formatNumber(Number(row[col]) || 0)} |`);
34200
+ }
34201
+ sections.push("");
34202
+ } catch (err) {
34203
+ sections.push(
34204
+ `_Error: ${err instanceof Error ? err.message : String(err)}_`,
34205
+ ""
34206
+ );
34207
+ }
34208
+ return sections;
34209
+ }
34210
+ function renderCsvTable(report, maxRows) {
34211
+ const cols = report.columns;
34212
+ const rows = report.rows.slice(0, maxRows);
34213
+ const lines = [];
34214
+ lines.push(`| ${cols.join(" | ")} |`);
34215
+ lines.push(`|${cols.map(() => "---").join("|")}|`);
34216
+ for (const row of rows) {
34217
+ const cells = cols.map((c) => (row[c] ?? "").replace(/\|/g, "\\|"));
34218
+ lines.push(`| ${cells.join(" | ")} |`);
34219
+ }
34220
+ return lines;
34221
+ }
33486
34222
  var semrushSetupFlow = {
33487
34223
  initialState: () => ({}),
33488
34224
  steps: [
34225
+ {
34226
+ slug: "domain",
34227
+ type: "select",
34228
+ allowFreeText: true,
34229
+ question: {
34230
+ ja: "\u5206\u6790\u5BFE\u8C61\u306E\u30C9\u30E1\u30A4\u30F3\u3092\u9078\u629E\u307E\u305F\u306F\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044",
34231
+ en: "Select or enter the domain to analyze"
34232
+ },
34233
+ async fetchOptions(_state, rt) {
34234
+ const result = await fetchProjects(rt.params);
34235
+ if (!result.ok || result.projects.length === 0) return [];
34236
+ const seen = /* @__PURE__ */ new Set();
34237
+ const options = [];
34238
+ for (const p of result.projects) {
34239
+ const d = projectDomain(p);
34240
+ if (d && !seen.has(d)) {
34241
+ seen.add(d);
34242
+ options.push({
34243
+ value: d,
34244
+ label: `${d} (${projectName(p)})`
34245
+ });
34246
+ }
34247
+ }
34248
+ return options;
34249
+ },
34250
+ applyAnswer: (state, answer) => ({ ...state, domain: answer[0] })
34251
+ },
34252
+ {
34253
+ slug: "database",
34254
+ type: "select",
34255
+ allowFreeText: false,
34256
+ question: {
34257
+ 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",
34258
+ en: "Select the region (primary market for the target domain)"
34259
+ },
34260
+ async fetchOptions() {
34261
+ return SEMRUSH_DATABASES.map((db) => ({
34262
+ value: db.value,
34263
+ label: `${db.label} (${db.value})`
34264
+ }));
34265
+ },
34266
+ applyAnswer: (state, answer) => ({ ...state, database: answer[0] })
34267
+ },
34268
+ {
34269
+ slug: "reportTypes",
34270
+ type: "multiSelect",
34271
+ question: {
34272
+ 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",
34273
+ en: "Select report types to explore (multi-select allowed)"
34274
+ },
34275
+ async fetchOptions(_state, rt) {
34276
+ return REPORT_TYPE_VALUES.map((value) => ({
34277
+ value,
34278
+ label: REPORT_TYPE_LABELS[value][rt.language]
34279
+ }));
34280
+ },
34281
+ applyAnswer: (state, answer) => ({ ...state, reportTypes: answer })
34282
+ },
33489
34283
  {
33490
34284
  slug: "projects",
33491
34285
  type: "multiSelect",
@@ -33502,7 +34296,9 @@ var semrushSetupFlow = {
33502
34296
  const id = projectId(p);
33503
34297
  if (!id) return null;
33504
34298
  return { value: id, label: projectName(p) };
33505
- }).filter((opt) => opt !== null);
34299
+ }).filter(
34300
+ (opt) => opt !== null
34301
+ );
33506
34302
  if (options.length === 0) return [];
33507
34303
  return [
33508
34304
  {
@@ -33516,49 +34312,80 @@ var semrushSetupFlow = {
33516
34312
  }
33517
34313
  ],
33518
34314
  async finalize(state, rt) {
33519
- const sections = ["## Semrush", ""];
33520
- if (!state.projects?.length) {
34315
+ if (!state.domain || !state.database || !state.reportTypes) {
34316
+ throw new Error("Semrush setup: incomplete state on finalize");
34317
+ }
34318
+ const domain = state.domain;
34319
+ const database = state.database;
34320
+ const selected = state.reportTypes.filter(
34321
+ (r) => REPORT_TYPE_VALUES.includes(r)
34322
+ );
34323
+ const sections = [
34324
+ "## Semrush",
34325
+ "",
34326
+ `**Domain:** ${domain}`,
34327
+ `**Region:** ${database}`,
34328
+ ""
34329
+ ];
34330
+ for (const reportType of selected) {
33521
34331
  sections.push(
33522
- "_No Semrush Projects API access detected; Standard Analytics reports run by domain/keyword and don't require pre-selection._",
34332
+ `### ${REPORT_TYPE_LABELS[reportType].en}`,
33523
34333
  ""
33524
34334
  );
33525
- return sections.join("\n");
33526
- }
33527
- const result = await fetchProjects(rt.params);
33528
- if (!result.ok) {
33529
- throw new Error(
33530
- `semrush: listProjects failed on finalize: ${result.error}`
33531
- );
33532
- }
33533
- const projectByIdMap = /* @__PURE__ */ new Map();
33534
- for (const p of result.projects) {
33535
- const id = projectId(p);
33536
- if (id) projectByIdMap.set(id, p);
33537
- }
33538
- const targetIds = await resolveSetupSelection({
33539
- selected: state.projects,
33540
- allSentinel: ALL_PROJECTS6,
33541
- fetchAll: async () => result.projects.map((p) => projectId(p)).filter((id) => id),
33542
- limit: SEMRUSH_SETUP_MAX_PROJECTS
33543
- });
33544
- if (!targetIds.length) {
33545
- sections.push("_No projects selected._", "");
33546
- return sections.join("\n");
34335
+ switch (reportType) {
34336
+ case "domain_overview":
34337
+ sections.push(
34338
+ ...await fetchDomainOverview(rt.params, domain, database)
34339
+ );
34340
+ break;
34341
+ case "organic_search":
34342
+ sections.push(
34343
+ ...await fetchOrganicSearch(rt.params, domain, database)
34344
+ );
34345
+ break;
34346
+ case "paid_search":
34347
+ sections.push(
34348
+ ...await fetchPaidSearch(rt.params, domain, database)
34349
+ );
34350
+ break;
34351
+ case "backlinks":
34352
+ sections.push(...await fetchBacklinks(rt.params, domain));
34353
+ break;
34354
+ }
33547
34355
  }
33548
- sections.push("| Project | Domain | Created |");
33549
- sections.push("|---------|--------|---------|");
33550
- for (const id of targetIds) {
33551
- const p = projectByIdMap.get(id);
33552
- if (!p) {
33553
- sections.push(`| ${id} | - | - |`);
33554
- continue;
34356
+ if (state.projects?.length) {
34357
+ const result = await fetchProjects(rt.params);
34358
+ if (result.ok) {
34359
+ const projectByIdMap = /* @__PURE__ */ new Map();
34360
+ for (const p of result.projects) {
34361
+ const id = projectId(p);
34362
+ if (id) projectByIdMap.set(id, p);
34363
+ }
34364
+ const targetIds = await resolveSetupSelection({
34365
+ selected: state.projects,
34366
+ allSentinel: ALL_PROJECTS6,
34367
+ fetchAll: async () => result.projects.map((p) => projectId(p)).filter((id) => id),
34368
+ limit: SEMRUSH_SETUP_MAX_PROJECTS
34369
+ });
34370
+ if (targetIds.length > 0) {
34371
+ sections.push("### Projects", "");
34372
+ sections.push("| Project | Domain | Created |");
34373
+ sections.push("|---------|--------|---------|");
34374
+ for (const id of targetIds) {
34375
+ const p = projectByIdMap.get(id);
34376
+ if (!p) {
34377
+ sections.push(`| ${id} | - | - |`);
34378
+ continue;
34379
+ }
34380
+ const name = projectName(p).replace(/\|/g, "\\|");
34381
+ const dom = projectDomain(p).replace(/\|/g, "\\|") || "-";
34382
+ const created = projectCreatedAt(p) || "-";
34383
+ sections.push(`| ${name} | ${dom} | ${created} |`);
34384
+ }
34385
+ sections.push("");
34386
+ }
33555
34387
  }
33556
- const name = projectName(p).replace(/\|/g, "\\|");
33557
- const domain = projectDomain(p).replace(/\|/g, "\\|") || "-";
33558
- const created = projectCreatedAt(p) || "-";
33559
- sections.push(`| ${name} | ${domain} | ${created} |`);
33560
34388
  }
33561
- sections.push("");
33562
34389
  return sections.join("\n");
33563
34390
  }
33564
34391
  };
@@ -33819,7 +34646,7 @@ API \u30E6\u30CB\u30C3\u30C8\u6B8B\u91CF\u306E\u78BA\u8A8D\uFF08\u7121\u6599\u30
33819
34646
 
33820
34647
  // ../connectors/src/connectors/google-search-console-oauth/tools/list-sites.ts
33821
34648
  import { z as z84 } from "zod";
33822
- var BASE_URL59 = "https://searchconsole.googleapis.com/webmasters/v3";
34649
+ var BASE_URL60 = "https://searchconsole.googleapis.com/webmasters/v3";
33823
34650
  var REQUEST_TIMEOUT_MS67 = 6e4;
33824
34651
  var cachedToken30 = null;
33825
34652
  async function getProxyToken30(config) {
@@ -33890,7 +34717,7 @@ var listSitesTool = new ConnectorTool({
33890
34717
  `[connector-request] google-search-console-oauth/${connection.name}: listSites`
33891
34718
  );
33892
34719
  try {
33893
- const url = `${BASE_URL59}/sites`;
34720
+ const url = `${BASE_URL60}/sites`;
33894
34721
  const token = await getProxyToken30(config.oauthProxy);
33895
34722
  const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
33896
34723
  const controller = new AbortController();
@@ -34072,7 +34899,7 @@ var googleSearchConsoleOauthSetupFlow = {
34072
34899
  import { z as z85 } from "zod";
34073
34900
  var BASE_HOST10 = "https://searchconsole.googleapis.com";
34074
34901
  var BASE_PATH_SEGMENT10 = "/webmasters/v3";
34075
- var BASE_URL60 = `${BASE_HOST10}${BASE_PATH_SEGMENT10}`;
34902
+ var BASE_URL61 = `${BASE_HOST10}${BASE_PATH_SEGMENT10}`;
34076
34903
  var REQUEST_TIMEOUT_MS68 = 6e4;
34077
34904
  var cachedToken31 = null;
34078
34905
  async function getProxyToken31(config) {
@@ -34157,7 +34984,7 @@ For URL Inspection API requests, use the absolute path '/v1/urlInspection/index:
34157
34984
  resolvedPath,
34158
34985
  BASE_PATH_SEGMENT10
34159
34986
  );
34160
- let url = `${BASE_URL60}${normalizedPath}`;
34987
+ let url = `${BASE_URL61}${normalizedPath}`;
34161
34988
  if (queryParams) {
34162
34989
  const searchParams = new URLSearchParams(queryParams);
34163
34990
  url += `?${searchParams.toString()}`;
@@ -34483,7 +35310,7 @@ function isInternalSchema3(name) {
34483
35310
  if (lower.startsWith("pg_toast_")) return true;
34484
35311
  return false;
34485
35312
  }
34486
- async function fetchTableNames5(params, schema) {
35313
+ async function fetchTableNames4(params, schema) {
34487
35314
  const rows = await runQuery10(
34488
35315
  params,
34489
35316
  `SELECT table_name FROM information_schema.tables
@@ -34516,17 +35343,17 @@ var supabaseSetupFlow = {
34516
35343
  slug: "tables",
34517
35344
  type: "multiSelect",
34518
35345
  question: {
34519
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
34520
- en: "Select target tables (multi-select allowed)"
35346
+ 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",
35347
+ en: "Select target tables and views (multi-select allowed)"
34521
35348
  },
34522
35349
  async fetchOptions(state, rt) {
34523
35350
  if (!state.schema) return [];
34524
- const names = await fetchTableNames5(rt.params, state.schema);
35351
+ const names = await fetchTableNames4(rt.params, state.schema);
34525
35352
  const tableOptions = names.map((value) => ({ value }));
34526
35353
  return [
34527
35354
  {
34528
35355
  value: ALL_TABLES13,
34529
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
35356
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
34530
35357
  },
34531
35358
  ...tableOptions
34532
35359
  ];
@@ -34542,7 +35369,7 @@ var supabaseSetupFlow = {
34542
35369
  const targetTables = await resolveSetupSelection({
34543
35370
  selected: state.tables,
34544
35371
  allSentinel: ALL_TABLES13,
34545
- fetchAll: () => fetchTableNames5(rt.params, schema),
35372
+ fetchAll: () => fetchTableNames4(rt.params, schema),
34546
35373
  limit: SUPABASE_SETUP_MAX_TABLES
34547
35374
  });
34548
35375
  const sections = [
@@ -34777,13 +35604,13 @@ var parameters71 = {
34777
35604
  };
34778
35605
 
34779
35606
  // ../connectors/src/connectors/clickup/utils.ts
34780
- var BASE_URL61 = "https://api.clickup.com/api/v2";
35607
+ var BASE_URL62 = "https://api.clickup.com/api/v2";
34781
35608
  async function apiFetch30(params, path5, init) {
34782
35609
  const token = params[parameters71.apiToken.slug];
34783
35610
  if (!token) {
34784
35611
  throw new Error("clickup: missing required parameter: api-token");
34785
35612
  }
34786
- const url = `${BASE_URL61}${path5.startsWith("/") ? "" : "/"}${path5}`;
35613
+ const url = `${BASE_URL62}${path5.startsWith("/") ? "" : "/"}${path5}`;
34787
35614
  const headers = new Headers(init?.headers);
34788
35615
  headers.set("Authorization", token);
34789
35616
  if (!headers.has("Accept")) headers.set("Accept", "application/json");
@@ -34911,7 +35738,7 @@ var clickupSetupFlow = {
34911
35738
  import { z as z87 } from "zod";
34912
35739
  var BASE_HOST11 = "https://api.clickup.com";
34913
35740
  var BASE_PATH_SEGMENT11 = "/api/v2";
34914
- var BASE_URL62 = `${BASE_HOST11}${BASE_PATH_SEGMENT11}`;
35741
+ var BASE_URL63 = `${BASE_HOST11}${BASE_PATH_SEGMENT11}`;
34915
35742
  var REQUEST_TIMEOUT_MS69 = 6e4;
34916
35743
  var inputSchema87 = z87.object({
34917
35744
  toolUseIntent: z87.string().optional().describe(
@@ -34984,7 +35811,7 @@ Pagination: ClickUp uses zero-indexed \`page\` query parameter on list endpoints
34984
35811
  try {
34985
35812
  const token = parameters71.apiToken.getValue(connection);
34986
35813
  const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT11);
34987
- const url = `${BASE_URL62}${normalizedPath}`;
35814
+ const url = `${BASE_URL63}${normalizedPath}`;
34988
35815
  const controller = new AbortController();
34989
35816
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS69);
34990
35817
  try {
@@ -35314,7 +36141,7 @@ function quoteLiteral4(value) {
35314
36141
  }
35315
36142
  function buildFlow(options) {
35316
36143
  const { connectorName, forceEncrypt } = options;
35317
- async function fetchTableNames7(params, schema) {
36144
+ async function fetchTableNames5(params, schema) {
35318
36145
  const rows = await runSqlServerSetupQuery(
35319
36146
  params,
35320
36147
  `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
@@ -35349,17 +36176,17 @@ function buildFlow(options) {
35349
36176
  slug: "tables",
35350
36177
  type: "multiSelect",
35351
36178
  question: {
35352
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
35353
- en: "Select target tables (multi-select allowed)"
36179
+ 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",
36180
+ en: "Select target tables and views (multi-select allowed)"
35354
36181
  },
35355
36182
  async fetchOptions(state, rt) {
35356
36183
  if (!state.schema) return [];
35357
- const names = await fetchTableNames7(rt.params, state.schema);
36184
+ const names = await fetchTableNames5(rt.params, state.schema);
35358
36185
  const tableOptions = names.map((value) => ({ value }));
35359
36186
  return [
35360
36187
  {
35361
36188
  value: ALL_TABLES14,
35362
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
36189
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
35363
36190
  },
35364
36191
  ...tableOptions
35365
36192
  ];
@@ -35375,7 +36202,7 @@ function buildFlow(options) {
35375
36202
  const targetTables = await resolveSetupSelection({
35376
36203
  selected: state.tables,
35377
36204
  allSentinel: ALL_TABLES14,
35378
- fetchAll: () => fetchTableNames7(rt.params, schema),
36205
+ fetchAll: () => fetchTableNames5(rt.params, schema),
35379
36206
  limit: SQLSERVER_SETUP_MAX_TABLES
35380
36207
  });
35381
36208
  const sections = [
@@ -36370,14 +37197,15 @@ function isInternalOwner(name) {
36370
37197
  function quoteLiteral5(value) {
36371
37198
  return "'" + value.replace(/'/g, "''") + "'";
36372
37199
  }
36373
- async function fetchTableNames6(params, owner) {
37200
+ async function fetchTableAndViewNames2(params, owner) {
36374
37201
  const rows = await runOracleSetupQuery(
36375
37202
  params,
36376
- `SELECT TABLE_NAME FROM ALL_TABLES
36377
- WHERE OWNER = ${quoteLiteral5(owner)}
36378
- ORDER BY TABLE_NAME`
37203
+ `SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = ${quoteLiteral5(owner)}
37204
+ UNION
37205
+ SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER = ${quoteLiteral5(owner)}
37206
+ ORDER BY 1`
36379
37207
  );
36380
- return rows.map((r) => String(r["TABLE_NAME"] ?? "")).filter((name) => name);
37208
+ return rows.map((r) => String(r["TABLE_NAME"] ?? r["VIEW_NAME"] ?? "")).filter((name) => name);
36381
37209
  }
36382
37210
  var oracleSetupFlow = {
36383
37211
  initialState: () => ({}),
@@ -36402,17 +37230,17 @@ var oracleSetupFlow = {
36402
37230
  slug: "tables",
36403
37231
  type: "multiSelect",
36404
37232
  question: {
36405
- ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
36406
- en: "Select target tables (multi-select allowed)"
37233
+ 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",
37234
+ en: "Select target tables and views (multi-select allowed)"
36407
37235
  },
36408
37236
  async fetchOptions(state, rt) {
36409
37237
  if (!state.owner) return [];
36410
- const names = await fetchTableNames6(rt.params, state.owner);
37238
+ const names = await fetchTableAndViewNames2(rt.params, state.owner);
36411
37239
  const tableOptions = names.map((value) => ({ value }));
36412
37240
  return [
36413
37241
  {
36414
37242
  value: ALL_TABLES15,
36415
- label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
37243
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
36416
37244
  },
36417
37245
  ...tableOptions
36418
37246
  ];
@@ -36428,9 +37256,22 @@ var oracleSetupFlow = {
36428
37256
  const targetTables = await resolveSetupSelection({
36429
37257
  selected: state.tables,
36430
37258
  allSentinel: ALL_TABLES15,
36431
- fetchAll: () => fetchTableNames6(rt.params, owner),
37259
+ fetchAll: () => fetchTableAndViewNames2(rt.params, owner),
36432
37260
  limit: ORACLE_SETUP_MAX_TABLES
36433
37261
  });
37262
+ const typeRows = targetTables.length > 0 ? await runOracleSetupQuery(
37263
+ rt.params,
37264
+ `SELECT OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS
37265
+ WHERE OWNER = ${quoteLiteral5(owner)}
37266
+ AND OBJECT_NAME IN (${targetTables.map(quoteLiteral5).join(", ")})
37267
+ AND OBJECT_TYPE IN ('TABLE', 'VIEW')`
37268
+ ) : [];
37269
+ const typeMap = new Map(
37270
+ typeRows.map((r) => [
37271
+ String(r["OBJECT_NAME"] ?? ""),
37272
+ String(r["OBJECT_TYPE"] ?? "TABLE")
37273
+ ])
37274
+ );
36434
37275
  const sections = [
36435
37276
  "## Oracle Database",
36436
37277
  "",
@@ -36438,6 +37279,7 @@ var oracleSetupFlow = {
36438
37279
  ""
36439
37280
  ];
36440
37281
  for (const table of targetTables) {
37282
+ const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
36441
37283
  const cols = await runOracleSetupQuery(
36442
37284
  rt.params,
36443
37285
  `SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
@@ -36446,7 +37288,7 @@ var oracleSetupFlow = {
36446
37288
  AND TABLE_NAME = ${quoteLiteral5(table)}
36447
37289
  ORDER BY COLUMN_ID`
36448
37290
  );
36449
- sections.push(`#### Table: ${table}`, "");
37291
+ sections.push(`#### ${heading}: ${table}`, "");
36450
37292
  sections.push("| Column | Type | Nullable | Default |");
36451
37293
  sections.push("|--------|------|----------|---------|");
36452
37294
  for (const c of cols) {
@@ -38751,7 +39593,7 @@ export default async function handler(c: Context) {
38751
39593
  import { z as z97 } from "zod";
38752
39594
  var BASE_HOST12 = "https://api.powerbi.com";
38753
39595
  var BASE_PATH_SEGMENT18 = "/v1.0/myorg";
38754
- var BASE_URL63 = `${BASE_HOST12}${BASE_PATH_SEGMENT18}`;
39596
+ var BASE_URL64 = `${BASE_HOST12}${BASE_PATH_SEGMENT18}`;
38755
39597
  var REQUEST_TIMEOUT_MS74 = 6e4;
38756
39598
  var cachedToken32 = null;
38757
39599
  async function getProxyToken32(config) {
@@ -38833,7 +39675,7 @@ The signed-in user must have access to the workspace; unlike Service Principals,
38833
39675
  );
38834
39676
  try {
38835
39677
  const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT18);
38836
- let url = `${BASE_URL63}${normalizedPath}`;
39678
+ let url = `${BASE_URL64}${normalizedPath}`;
38837
39679
  if (queryParams) {
38838
39680
  const searchParams = new URLSearchParams(queryParams);
38839
39681
  url += `?${searchParams.toString()}`;
@@ -38916,14 +39758,18 @@ var powerbiOauthOnboarding = new ConnectorOnboarding({
38916
39758
  var parameters80 = {};
38917
39759
 
38918
39760
  // ../connectors/src/connectors/powerbi-oauth/utils.ts
38919
- var BASE_URL64 = "https://api.powerbi.com/v1.0/myorg";
39761
+ var BASE_URL65 = "https://api.powerbi.com/v1.0/myorg";
38920
39762
  function apiFetch35(proxyFetch, path5, init) {
38921
- const url = `${BASE_URL64}${path5.startsWith("/") ? "" : "/"}${path5}`;
39763
+ const url = `${BASE_URL65}${path5.startsWith("/") ? "" : "/"}${path5}`;
38922
39764
  return proxyFetch(url, init);
38923
39765
  }
38924
39766
 
38925
39767
  // ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
38926
39768
  var ALL_WORKSPACES = "__ALL_WORKSPACES__";
39769
+ var MY_WORKSPACE = "__MY_WORKSPACE__";
39770
+ var ALL_DATASETS = "__ALL_DATASETS__";
39771
+ var ALL_REPORTS = "__ALL_REPORTS__";
39772
+ var ALL_DASHBOARDS = "__ALL_DASHBOARDS__";
38927
39773
  var POWERBI_SETUP_MAX_WORKSPACES = 10;
38928
39774
  var RESOURCE_DISPLAY_LIMIT = 25;
38929
39775
  var RESOURCE_DATASETS = "datasets";
@@ -38939,14 +39785,12 @@ async function listGroups(proxyFetch) {
38939
39785
  return data.value ?? [];
38940
39786
  }
38941
39787
  async function listResource(proxyFetch, groupId, resource) {
38942
- const res = await apiFetch35(
38943
- proxyFetch,
38944
- `/groups/${encodeURIComponent(groupId)}/${resource}`
38945
- );
39788
+ const path5 = groupId === MY_WORKSPACE ? `/${resource}` : `/groups/${encodeURIComponent(groupId)}/${resource}`;
39789
+ const res = await apiFetch35(proxyFetch, path5);
38946
39790
  if (!res.ok) {
38947
39791
  const body = await res.text().catch(() => res.statusText);
38948
39792
  throw new Error(
38949
- `powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
39793
+ `powerbi: list ${resource} for ${groupId === MY_WORKSPACE ? "My workspace" : `group ${groupId}`} failed (${res.status}): ${body}`
38950
39794
  );
38951
39795
  }
38952
39796
  const data = await res.json();
@@ -38955,6 +39799,99 @@ async function listResource(proxyFetch, groupId, resource) {
38955
39799
  function resourceLabel(r) {
38956
39800
  return r.name ?? r.displayName ?? r.id ?? "(unknown)";
38957
39801
  }
39802
+ var INTERNAL_TABLE_PREFIXES = [
39803
+ "DateTableTemplate_",
39804
+ "LocalDateTable_"
39805
+ ];
39806
+ function isInternalColumn(name) {
39807
+ return /^RowNumber-[0-9A-Fa-f-]+$/.test(name);
39808
+ }
39809
+ async function fetchDatasetSchema(proxyFetch, wsId, datasetId) {
39810
+ const pathPrefix = wsId === MY_WORKSPACE ? "" : `/groups/${encodeURIComponent(wsId)}`;
39811
+ const daxQuery = 'EVALUATE SELECTCOLUMNS(COLUMNSTATISTICS(), "T", [Table Name], "C", [Column Name])';
39812
+ const res = await apiFetch35(
39813
+ proxyFetch,
39814
+ `${pathPrefix}/datasets/${encodeURIComponent(datasetId)}/executeQueries`,
39815
+ {
39816
+ method: "POST",
39817
+ headers: { "Content-Type": "application/json" },
39818
+ body: JSON.stringify({
39819
+ queries: [{ query: daxQuery }],
39820
+ serializerSettings: { includeNulls: true }
39821
+ })
39822
+ }
39823
+ );
39824
+ if (!res.ok) return /* @__PURE__ */ new Map();
39825
+ const data = await res.json();
39826
+ const rows = data.results?.[0]?.tables?.[0]?.rows ?? [];
39827
+ const schema = /* @__PURE__ */ new Map();
39828
+ for (const row of rows) {
39829
+ const table = row["[T]"] ?? "";
39830
+ const column = row["[C]"] ?? "";
39831
+ if (!table || !column) continue;
39832
+ if (INTERNAL_TABLE_PREFIXES.some((p) => table.startsWith(p))) continue;
39833
+ if (isInternalColumn(column)) continue;
39834
+ if (!schema.has(table)) schema.set(table, []);
39835
+ schema.get(table).push(column);
39836
+ }
39837
+ return schema;
39838
+ }
39839
+ function workspaceName(wsId, groupById, language) {
39840
+ if (wsId === MY_WORKSPACE) {
39841
+ return language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace";
39842
+ }
39843
+ return groupById.get(wsId)?.name ?? wsId;
39844
+ }
39845
+ async function resolveWorkspaceIds(selected, proxyFetch) {
39846
+ return resolveSetupSelection({
39847
+ selected,
39848
+ allSentinel: ALL_WORKSPACES,
39849
+ fetchAll: async () => {
39850
+ const groups = await listGroups(proxyFetch);
39851
+ return [MY_WORKSPACE, ...groups.map((g) => g.id).filter(Boolean)];
39852
+ },
39853
+ limit: POWERBI_SETUP_MAX_WORKSPACES
39854
+ });
39855
+ }
39856
+ function compoundKey(wsId, objectId) {
39857
+ return `${wsId}:${objectId}`;
39858
+ }
39859
+ function parseCompoundKey(key) {
39860
+ const idx = key.indexOf(":");
39861
+ if (idx < 0) return { wsId: "", objectId: key };
39862
+ return { wsId: key.slice(0, idx), objectId: key.slice(idx + 1) };
39863
+ }
39864
+ async function fetchObjectOptions(state, resource, allSentinel, allLabelJa, allLabelEn, rt) {
39865
+ if (!state.workspaces?.length || !state.resources?.includes(resource))
39866
+ return [];
39867
+ const wsIds = await resolveWorkspaceIds(
39868
+ state.workspaces,
39869
+ rt.config.proxyFetch
39870
+ );
39871
+ const allGroups = await listGroups(rt.config.proxyFetch);
39872
+ const groupById = new Map(allGroups.map((g) => [g.id, g]));
39873
+ const multiWorkspace = wsIds.length > 1;
39874
+ const options = [];
39875
+ for (const wsId of wsIds) {
39876
+ const wsLabel = workspaceName(wsId, groupById, rt.language);
39877
+ const items = await listResource(rt.config.proxyFetch, wsId, resource);
39878
+ for (const item of items) {
39879
+ if (!item.id) continue;
39880
+ options.push({
39881
+ value: compoundKey(wsId, item.id),
39882
+ label: multiWorkspace ? `${wsLabel} / ${resourceLabel(item)}` : resourceLabel(item)
39883
+ });
39884
+ }
39885
+ }
39886
+ if (options.length === 0) return [];
39887
+ return [
39888
+ {
39889
+ value: allSentinel,
39890
+ label: rt.language === "ja" ? allLabelJa : allLabelEn
39891
+ },
39892
+ ...options
39893
+ ];
39894
+ }
38958
39895
  var powerbiOauthSetupFlow = {
38959
39896
  initialState: () => ({}),
38960
39897
  steps: [
@@ -38973,6 +39910,10 @@ var powerbiOauthSetupFlow = {
38973
39910
  value: ALL_WORKSPACES,
38974
39911
  label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
38975
39912
  },
39913
+ {
39914
+ value: MY_WORKSPACE,
39915
+ label: rt.language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace"
39916
+ },
38976
39917
  ...options
38977
39918
  ];
38978
39919
  },
@@ -38987,16 +39928,82 @@ var powerbiOauthSetupFlow = {
38987
39928
  },
38988
39929
  async fetchOptions(state, rt) {
38989
39930
  if (!state.workspaces?.length) return [];
38990
- const datasetsLabel = rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets";
38991
- const reportsLabel = rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports";
38992
- const dashboardsLabel = rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards";
38993
39931
  return [
38994
- { value: RESOURCE_DATASETS, label: datasetsLabel },
38995
- { value: RESOURCE_REPORTS, label: reportsLabel },
38996
- { value: RESOURCE_DASHBOARDS, label: dashboardsLabel }
39932
+ {
39933
+ value: RESOURCE_DATASETS,
39934
+ label: rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets"
39935
+ },
39936
+ {
39937
+ value: RESOURCE_REPORTS,
39938
+ label: rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports"
39939
+ },
39940
+ {
39941
+ value: RESOURCE_DASHBOARDS,
39942
+ label: rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards"
39943
+ }
38997
39944
  ];
38998
39945
  },
38999
39946
  applyAnswer: (state, answer) => ({ ...state, resources: answer })
39947
+ },
39948
+ {
39949
+ slug: "datasets",
39950
+ type: "multiSelect",
39951
+ question: {
39952
+ 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",
39953
+ en: "Select the datasets you want to use (multi-select allowed)"
39954
+ },
39955
+ async fetchOptions(state, rt) {
39956
+ return fetchObjectOptions(
39957
+ state,
39958
+ RESOURCE_DATASETS,
39959
+ ALL_DATASETS,
39960
+ "\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8",
39961
+ "All datasets",
39962
+ rt
39963
+ );
39964
+ },
39965
+ applyAnswer: (state, answer) => ({ ...state, selectedDatasets: answer })
39966
+ },
39967
+ {
39968
+ slug: "reports",
39969
+ type: "multiSelect",
39970
+ question: {
39971
+ ja: "\u4F7F\u7528\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
39972
+ en: "Select the reports you want to use (multi-select allowed)"
39973
+ },
39974
+ async fetchOptions(state, rt) {
39975
+ return fetchObjectOptions(
39976
+ state,
39977
+ RESOURCE_REPORTS,
39978
+ ALL_REPORTS,
39979
+ "\u3059\u3079\u3066\u306E\u30EC\u30DD\u30FC\u30C8",
39980
+ "All reports",
39981
+ rt
39982
+ );
39983
+ },
39984
+ applyAnswer: (state, answer) => ({ ...state, selectedReports: answer })
39985
+ },
39986
+ {
39987
+ slug: "dashboards",
39988
+ type: "multiSelect",
39989
+ question: {
39990
+ 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",
39991
+ en: "Select the dashboards you want to use (multi-select allowed)"
39992
+ },
39993
+ async fetchOptions(state, rt) {
39994
+ return fetchObjectOptions(
39995
+ state,
39996
+ RESOURCE_DASHBOARDS,
39997
+ ALL_DASHBOARDS,
39998
+ "\u3059\u3079\u3066\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9",
39999
+ "All dashboards",
40000
+ rt
40001
+ );
40002
+ },
40003
+ applyAnswer: (state, answer) => ({
40004
+ ...state,
40005
+ selectedDashboards: answer
40006
+ })
39000
40007
  }
39001
40008
  ],
39002
40009
  async finalize(state, rt) {
@@ -39005,37 +40012,119 @@ var powerbiOauthSetupFlow = {
39005
40012
  }
39006
40013
  const allGroups = await listGroups(rt.config.proxyFetch);
39007
40014
  const groupById = new Map(allGroups.map((g) => [g.id, g]));
39008
- const targetIds = await resolveSetupSelection({
39009
- selected: state.workspaces,
39010
- allSentinel: ALL_WORKSPACES,
39011
- fetchAll: async () => allGroups.map((g) => g.id).filter((id) => id),
39012
- limit: POWERBI_SETUP_MAX_WORKSPACES
39013
- });
40015
+ const wsIds = await resolveWorkspaceIds(
40016
+ state.workspaces,
40017
+ rt.config.proxyFetch
40018
+ );
39014
40019
  const selectedResources = new Set(state.resources);
40020
+ async function resolveObjects(selected, allSentinel, resource) {
40021
+ const byWorkspace = /* @__PURE__ */ new Map();
40022
+ if (!selected || !selectedResources.has(resource)) return byWorkspace;
40023
+ if (selected.includes(allSentinel)) {
40024
+ for (const wsId of wsIds) {
40025
+ const items = await listResource(
40026
+ rt.config.proxyFetch,
40027
+ wsId,
40028
+ resource
40029
+ );
40030
+ const ids = items.map((i) => i.id).filter((id) => !!id);
40031
+ if (ids.length > 0) byWorkspace.set(wsId, new Set(ids));
40032
+ }
40033
+ } else {
40034
+ for (const key of selected) {
40035
+ if (key === allSentinel) continue;
40036
+ const { wsId, objectId } = parseCompoundKey(key);
40037
+ if (!byWorkspace.has(wsId)) byWorkspace.set(wsId, /* @__PURE__ */ new Set());
40038
+ byWorkspace.get(wsId).add(objectId);
40039
+ }
40040
+ }
40041
+ return byWorkspace;
40042
+ }
40043
+ const datasetsByWs = await resolveObjects(
40044
+ state.selectedDatasets,
40045
+ ALL_DATASETS,
40046
+ RESOURCE_DATASETS
40047
+ );
40048
+ const reportsByWs = await resolveObjects(
40049
+ state.selectedReports,
40050
+ ALL_REPORTS,
40051
+ RESOURCE_REPORTS
40052
+ );
40053
+ const dashboardsByWs = await resolveObjects(
40054
+ state.selectedDashboards,
40055
+ ALL_DASHBOARDS,
40056
+ RESOURCE_DASHBOARDS
40057
+ );
40058
+ const allWsIds = /* @__PURE__ */ new Set([
40059
+ ...datasetsByWs.keys(),
40060
+ ...reportsByWs.keys(),
40061
+ ...dashboardsByWs.keys()
40062
+ ]);
39015
40063
  const sections = ["## Power BI", ""];
39016
- if (!targetIds.length) {
39017
- sections.push("_No workspaces selected._", "");
40064
+ if (allWsIds.size === 0) {
40065
+ sections.push("_No resources selected._", "");
39018
40066
  return sections.join("\n");
39019
40067
  }
39020
- for (const id of targetIds) {
39021
- const group = groupById.get(id);
39022
- const name = group?.name ?? id;
39023
- sections.push(`### Workspace: ${name}`, "", `- id: \`${id}\``);
39024
- for (const resource of [
39025
- RESOURCE_DATASETS,
39026
- RESOURCE_REPORTS,
39027
- RESOURCE_DASHBOARDS
40068
+ for (const wsId of wsIds) {
40069
+ if (!allWsIds.has(wsId)) continue;
40070
+ const name = workspaceName(wsId, groupById, rt.language);
40071
+ sections.push(`### Workspace: ${name}`, "");
40072
+ if (wsId !== MY_WORKSPACE) {
40073
+ sections.push(`- id: \`${wsId}\``);
40074
+ }
40075
+ const datasetIds = datasetsByWs.get(wsId);
40076
+ if (datasetIds?.size) {
40077
+ const items = await listResource(
40078
+ rt.config.proxyFetch,
40079
+ wsId,
40080
+ RESOURCE_DATASETS
40081
+ );
40082
+ const filtered = items.filter(
40083
+ (item) => item.id && datasetIds.has(item.id)
40084
+ );
40085
+ for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
40086
+ sections.push(`#### Dataset: ${resourceLabel(item)}`, "");
40087
+ const schema = await fetchDatasetSchema(
40088
+ rt.config.proxyFetch,
40089
+ wsId,
40090
+ item.id
40091
+ );
40092
+ if (schema.size > 0) {
40093
+ for (const [table, columns] of schema) {
40094
+ sections.push(`##### Table: ${table}`, "");
40095
+ sections.push("| Column |");
40096
+ sections.push("|--------|");
40097
+ for (const col of columns) {
40098
+ sections.push(`| ${col} |`);
40099
+ }
40100
+ sections.push("");
40101
+ }
40102
+ } else {
40103
+ sections.push("_Schema not available._", "");
40104
+ }
40105
+ }
40106
+ }
40107
+ for (const [resource, selectedByWs, heading] of [
40108
+ [RESOURCE_REPORTS, reportsByWs, "Reports"],
40109
+ [RESOURCE_DASHBOARDS, dashboardsByWs, "Dashboards"]
39028
40110
  ]) {
39029
- if (!selectedResources.has(resource)) continue;
39030
- const items = await listResource(rt.config.proxyFetch, id, resource);
39031
- const heading = resource === RESOURCE_DATASETS ? "Datasets" : resource === RESOURCE_REPORTS ? "Reports" : "Dashboards";
39032
- sections.push(`- ${heading} (${items.length}):`);
39033
- for (const item of items.slice(0, RESOURCE_DISPLAY_LIMIT)) {
40111
+ const selectedIds = selectedByWs.get(wsId);
40112
+ if (!selectedIds?.size) continue;
40113
+ const items = await listResource(
40114
+ rt.config.proxyFetch,
40115
+ wsId,
40116
+ resource
40117
+ );
40118
+ const filtered = items.filter(
40119
+ (item) => item.id && selectedIds.has(item.id)
40120
+ );
40121
+ sections.push(`- ${heading} (${filtered.length}):`);
40122
+ for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
39034
40123
  sections.push(` - ${resourceLabel(item)}`);
39035
40124
  }
39036
- if (items.length > RESOURCE_DISPLAY_LIMIT) {
40125
+ if (filtered.length > RESOURCE_DISPLAY_LIMIT) {
39037
40126
  sections.push(
39038
- ` - \u2026and ${items.length - RESOURCE_DISPLAY_LIMIT} more`
40127
+ ` - \u2026and ${filtered.length - RESOURCE_DISPLAY_LIMIT} more`
39039
40128
  );
39040
40129
  }
39041
40130
  }
@@ -39306,7 +40395,11 @@ async function tableauProxyApiFetch(proxyFetch, params, path5, init) {
39306
40395
 
39307
40396
  // ../connectors/src/connectors/tableau/setup-flow.ts
39308
40397
  var ALL_PROJECTS7 = "__ALL_PROJECTS__";
40398
+ var ALL_WORKBOOKS = "__ALL_WORKBOOKS__";
39309
40399
  var TABLEAU_SETUP_MAX_PROJECTS = 10;
40400
+ var MAX_WORKBOOKS_DETAIL = 10;
40401
+ var MAX_VIEWS_PER_WORKBOOK = 5;
40402
+ var MAX_SAMPLE_ROWS = 5;
39310
40403
  var PAGE_SIZE2 = 100;
39311
40404
  async function listAllProjects3(rt) {
39312
40405
  const all = [];
@@ -39355,6 +40448,57 @@ async function listProjectResources(rt, resource) {
39355
40448
  }
39356
40449
  return all;
39357
40450
  }
40451
+ async function listViewsForWorkbook(rt, workbookId) {
40452
+ const res = await tableauProxyApiFetch(
40453
+ rt.config.proxyFetch,
40454
+ rt.params,
40455
+ `/sites/{siteId}/workbooks/${encodeURIComponent(workbookId)}/views`
40456
+ );
40457
+ if (!res.ok) return [];
40458
+ const data = await res.json();
40459
+ return data.views?.view ?? [];
40460
+ }
40461
+ async function fetchViewDataSample(rt, viewId) {
40462
+ try {
40463
+ const res = await tableauProxyApiFetch(
40464
+ rt.config.proxyFetch,
40465
+ rt.params,
40466
+ `/sites/{siteId}/views/${encodeURIComponent(viewId)}/data`
40467
+ );
40468
+ if (!res.ok) return null;
40469
+ const csv = await res.text();
40470
+ const lines = csv.trim().split("\n").filter(Boolean);
40471
+ if (lines.length === 0) return null;
40472
+ const columns = parseCsvLine(lines[0]);
40473
+ const rows = lines.slice(1, 1 + MAX_SAMPLE_ROWS).map(parseCsvLine);
40474
+ return { columns, rows };
40475
+ } catch {
40476
+ return null;
40477
+ }
40478
+ }
40479
+ function parseCsvLine(line) {
40480
+ const result = [];
40481
+ let current = "";
40482
+ let inQuotes = false;
40483
+ for (let i = 0; i < line.length; i++) {
40484
+ const ch = line[i];
40485
+ if (ch === '"') {
40486
+ if (inQuotes && line[i + 1] === '"') {
40487
+ current += '"';
40488
+ i++;
40489
+ } else {
40490
+ inQuotes = !inQuotes;
40491
+ }
40492
+ } else if (ch === "," && !inQuotes) {
40493
+ result.push(current.trim());
40494
+ current = "";
40495
+ } else {
40496
+ current += ch;
40497
+ }
40498
+ }
40499
+ result.push(current.trim());
40500
+ return result;
40501
+ }
39358
40502
  var tableauSetupFlow = {
39359
40503
  initialState: () => ({}),
39360
40504
  steps: [
@@ -39377,6 +40521,39 @@ var tableauSetupFlow = {
39377
40521
  ];
39378
40522
  },
39379
40523
  applyAnswer: (state, answer) => ({ ...state, projects: answer })
40524
+ },
40525
+ {
40526
+ slug: "workbooks",
40527
+ type: "multiSelect",
40528
+ question: {
40529
+ 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",
40530
+ en: "Select the workbooks to analyze (multi-select allowed)"
40531
+ },
40532
+ async fetchOptions(state, rt) {
40533
+ if (!state.projects?.length) return [];
40534
+ const allProjects = await listAllProjects3(rt);
40535
+ const targetIds = await resolveSetupSelection({
40536
+ selected: state.projects,
40537
+ allSentinel: ALL_PROJECTS7,
40538
+ fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
40539
+ limit: TABLEAU_SETUP_MAX_PROJECTS
40540
+ });
40541
+ const targetSet = new Set(targetIds);
40542
+ const workbooks = await listProjectResources(rt, "workbooks");
40543
+ const options = workbooks.filter((wb) => wb.id && wb.project?.id && targetSet.has(wb.project.id)).map((wb) => ({
40544
+ value: wb.id,
40545
+ label: wb.name ?? wb.id ?? "(unknown)"
40546
+ }));
40547
+ if (options.length === 0) return [];
40548
+ return [
40549
+ {
40550
+ value: ALL_WORKBOOKS,
40551
+ label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30D6\u30C3\u30AF" : "All workbooks"
40552
+ },
40553
+ ...options
40554
+ ];
40555
+ },
40556
+ applyAnswer: (state, answer) => ({ ...state, workbooks: answer })
39380
40557
  }
39381
40558
  ],
39382
40559
  async finalize(state, rt) {
@@ -39385,25 +40562,33 @@ var tableauSetupFlow = {
39385
40562
  }
39386
40563
  const allProjects = await listAllProjects3(rt);
39387
40564
  const projectById = new Map(allProjects.map((p) => [p.id, p]));
39388
- const targetIds = await resolveSetupSelection({
40565
+ const targetProjectIds = await resolveSetupSelection({
39389
40566
  selected: state.projects,
39390
40567
  allSentinel: ALL_PROJECTS7,
39391
40568
  fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
39392
40569
  limit: TABLEAU_SETUP_MAX_PROJECTS
39393
40570
  });
39394
40571
  const sections = ["## Tableau", ""];
39395
- if (!targetIds.length) {
40572
+ if (!targetProjectIds.length) {
39396
40573
  sections.push("_No projects selected._", "");
39397
40574
  return sections.join("\n");
39398
40575
  }
39399
- const [workbooks, datasources] = await Promise.all([
40576
+ const [allWorkbooks, datasources] = await Promise.all([
39400
40577
  listProjectResources(rt, "workbooks"),
39401
40578
  listProjectResources(rt, "datasources")
39402
40579
  ]);
40580
+ const projectIdSet = new Set(targetProjectIds);
40581
+ const targetWorkbooks = await resolveSetupSelection({
40582
+ selected: state.workbooks ?? [],
40583
+ allSentinel: ALL_WORKBOOKS,
40584
+ fetchAll: async () => allWorkbooks.filter((wb) => wb.id && wb.project?.id && projectIdSet.has(wb.project.id)).map((wb) => wb.id).filter(Boolean),
40585
+ limit: MAX_WORKBOOKS_DETAIL
40586
+ });
40587
+ const targetWorkbookSet = new Set(targetWorkbooks);
39403
40588
  const workbooksByProject = /* @__PURE__ */ new Map();
39404
- for (const wb of workbooks) {
40589
+ for (const wb of allWorkbooks) {
39405
40590
  const pid = wb.project?.id;
39406
- if (!pid) continue;
40591
+ if (!pid || !projectIdSet.has(pid)) continue;
39407
40592
  const bucket = workbooksByProject.get(pid) ?? [];
39408
40593
  bucket.push(wb);
39409
40594
  workbooksByProject.set(pid, bucket);
@@ -39411,32 +40596,78 @@ var tableauSetupFlow = {
39411
40596
  const datasourcesByProject = /* @__PURE__ */ new Map();
39412
40597
  for (const ds of datasources) {
39413
40598
  const pid = ds.project?.id;
39414
- if (!pid) continue;
40599
+ if (!pid || !projectIdSet.has(pid)) continue;
39415
40600
  const bucket = datasourcesByProject.get(pid) ?? [];
39416
40601
  bucket.push(ds);
39417
40602
  datasourcesByProject.set(pid, bucket);
39418
40603
  }
39419
- for (const id of targetIds) {
39420
- const project = projectById.get(id);
39421
- const name = project?.name ?? id;
39422
- sections.push(`### Project: ${name}`, "", `- id: \`${id}\``);
39423
- const projectWorkbooks = workbooksByProject.get(id) ?? [];
39424
- sections.push(`- Workbooks (${projectWorkbooks.length}):`);
39425
- for (const wb of projectWorkbooks.slice(0, 25)) {
39426
- sections.push(` - ${wb.name ?? wb.id ?? "(unknown)"}`);
39427
- }
39428
- if (projectWorkbooks.length > 25) {
39429
- sections.push(` - \u2026and ${projectWorkbooks.length - 25} more`);
40604
+ const allDiscoveredColumns = [];
40605
+ for (const pid of targetProjectIds) {
40606
+ const project = projectById.get(pid);
40607
+ sections.push(`### Project: ${project?.name ?? pid}`, "");
40608
+ const projectWorkbooks = workbooksByProject.get(pid) ?? [];
40609
+ for (const wb of projectWorkbooks) {
40610
+ if (!wb.id) continue;
40611
+ const isDetailed = targetWorkbookSet.has(wb.id);
40612
+ sections.push(`#### Workbook: ${wb.name ?? wb.id}`, "");
40613
+ if (!isDetailed) continue;
40614
+ const views = await listViewsForWorkbook(rt, wb.id);
40615
+ if (views.length === 0) {
40616
+ sections.push("_No views found._", "");
40617
+ continue;
40618
+ }
40619
+ for (const view of views.slice(0, MAX_VIEWS_PER_WORKBOOK)) {
40620
+ if (!view.id) continue;
40621
+ sections.push(`##### View: ${view.name ?? view.id}`, "");
40622
+ const sample = await fetchViewDataSample(rt, view.id);
40623
+ if (!sample || sample.columns.length === 0) {
40624
+ sections.push("_Data not available._", "");
40625
+ continue;
40626
+ }
40627
+ allDiscoveredColumns.push(...sample.columns);
40628
+ sections.push(`| ${sample.columns.join(" | ")} |`);
40629
+ sections.push(`|${sample.columns.map(() => "---").join("|")}|`);
40630
+ for (const row of sample.rows) {
40631
+ const cells = row.map((c) => c.replace(/\|/g, "\\|"));
40632
+ sections.push(`| ${cells.join(" | ")} |`);
40633
+ }
40634
+ sections.push("");
40635
+ }
39430
40636
  }
39431
- const projectDatasources = datasourcesByProject.get(id) ?? [];
39432
- sections.push(`- Datasources (${projectDatasources.length}):`);
39433
- for (const ds of projectDatasources.slice(0, 25)) {
39434
- sections.push(` - ${ds.name ?? ds.id ?? "(unknown)"}`);
40637
+ const projectDatasources = datasourcesByProject.get(pid) ?? [];
40638
+ if (projectDatasources.length > 0) {
40639
+ sections.push(`#### Datasources (${projectDatasources.length})`, "");
40640
+ for (const ds of projectDatasources.slice(0, 25)) {
40641
+ sections.push(`- ${ds.name ?? ds.id ?? "(unknown)"}`);
40642
+ }
40643
+ sections.push("");
39435
40644
  }
39436
- if (projectDatasources.length > 25) {
39437
- sections.push(` - \u2026and ${projectDatasources.length - 25} more`);
40645
+ }
40646
+ if (allDiscoveredColumns.length > 0) {
40647
+ const unique = [...new Set(allDiscoveredColumns.map((c) => c.toLowerCase()))];
40648
+ const themes = [];
40649
+ const hasPattern = (keywords) => unique.some((c) => keywords.some((k) => c.includes(k)));
40650
+ if (hasPattern(["revenue", "sales", "amount", "price", "cost", "profit", "\u58F2\u4E0A", "\u91D1\u984D", "\u5229\u76CA"]))
40651
+ themes.push("Revenue & profitability analysis (trends, breakdown by segment)");
40652
+ if (hasPattern(["date", "month", "year", "quarter", "day", "\u65E5\u4ED8", "\u6708", "\u5E74", "\u671F"]))
40653
+ themes.push("Time-series trend analysis (YoY, MoM comparisons)");
40654
+ if (hasPattern(["region", "country", "city", "state", "\u5730\u57DF", "\u56FD", "\u90FD\u5E02", "\u5E02"]))
40655
+ themes.push("Geographic/regional performance comparison");
40656
+ if (hasPattern(["product", "category", "item", "sku", "\u5546\u54C1", "\u30AB\u30C6\u30B4\u30EA"]))
40657
+ themes.push("Product/category mix analysis");
40658
+ if (hasPattern(["customer", "user", "account", "\u9867\u5BA2", "\u30E6\u30FC\u30B6\u30FC"]))
40659
+ themes.push("Customer segmentation and behavior analysis");
40660
+ if (hasPattern(["quantity", "count", "volume", "\u6570\u91CF", "\u4EF6\u6570"]))
40661
+ themes.push("Volume and demand pattern analysis");
40662
+ if (hasPattern(["rate", "ratio", "percentage", "%", "\u7387"]))
40663
+ themes.push("KPI ratio tracking and benchmarking");
40664
+ if (themes.length > 0) {
40665
+ sections.push("### Suggested Analysis Themes", "");
40666
+ for (const theme of themes) {
40667
+ sections.push(`- ${theme}`);
40668
+ }
40669
+ sections.push("");
39438
40670
  }
39439
- sections.push("");
39440
40671
  }
39441
40672
  return sections.join("\n");
39442
40673
  }
@@ -39446,27 +40677,36 @@ var tableauSetupFlow = {
39446
40677
  import { z as z98 } from "zod";
39447
40678
  var DEFAULT_API_VERSION2 = "3.28";
39448
40679
  var REQUEST_TIMEOUT_MS75 = 6e4;
39449
- async function fetchTableauSession(connectionId) {
39450
- const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
39451
- const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
39452
- if (!token || !sandboxId) {
39453
- throw new Error(
39454
- "Tableau session manager is not configured. Missing INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL or INTERNAL_SQUADBASE_SANDBOX_ID."
39455
- );
40680
+ var cachedToken33 = null;
40681
+ async function getProxyToken33(config) {
40682
+ if (cachedToken33 && cachedToken33.expiresAt > Date.now() + 6e4) {
40683
+ return cachedToken33.token;
39456
40684
  }
39457
- const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
39458
- const url = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
40685
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
39459
40686
  const res = await fetch(url, {
39460
40687
  method: "POST",
39461
- headers: { Authorization: `Bearer ${token}` }
40688
+ headers: {
40689
+ "Content-Type": "application/json",
40690
+ "x-api-key": config.appApiKey,
40691
+ "project-id": config.projectId
40692
+ },
40693
+ body: JSON.stringify({
40694
+ sandboxId: config.sandboxId,
40695
+ issuedBy: "coding-agent"
40696
+ })
39462
40697
  });
39463
40698
  if (!res.ok) {
39464
- const errBody = await res.text().catch(() => res.statusText);
40699
+ const errorText = await res.text().catch(() => res.statusText);
39465
40700
  throw new Error(
39466
- `Failed to fetch Tableau session from backend-api (HTTP ${res.status}): ${errBody}`
40701
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
39467
40702
  );
39468
40703
  }
39469
- return await res.json();
40704
+ const data = await res.json();
40705
+ cachedToken33 = {
40706
+ token: data.token,
40707
+ expiresAt: new Date(data.expiresAt).getTime()
40708
+ };
40709
+ return data.token;
39470
40710
  }
39471
40711
  function buildBaseUrl7(serverUrl, apiVersion) {
39472
40712
  return `${serverUrl.replace(/\/$/, "")}/api/${apiVersion}`;
@@ -39508,7 +40748,7 @@ All paths are relative to {serverUrl}/api/{apiVersion}. Use the literal placehol
39508
40748
  Accept and Content-Type headers default to application/json so list responses come back as JSON instead of Tableau's default XML.`,
39509
40749
  inputSchema: inputSchema98,
39510
40750
  outputSchema: outputSchema98,
39511
- async execute({ connectionId, method, path: path5, queryParams, body }, connections) {
40751
+ async execute({ connectionId, method, path: path5, queryParams, body }, connections, config) {
39512
40752
  const connection = connections.find((c) => c.id === connectionId);
39513
40753
  if (!connection) {
39514
40754
  return {
@@ -39523,50 +40763,42 @@ Accept and Content-Type headers default to application/json so list responses co
39523
40763
  const serverUrl = parameters81.serverUrl.getValue(connection);
39524
40764
  const apiVersion = parameters81.apiVersion.tryGetValue(connection) || DEFAULT_API_VERSION2;
39525
40765
  const trimmedPath = path5.trim().replace(/^([^/])/, "/$1");
39526
- const queryString = queryParams ? `?${new URLSearchParams(queryParams).toString()}` : "";
39527
40766
  const baseUrl = buildBaseUrl7(serverUrl, apiVersion);
40767
+ let url = `${baseUrl}${trimmedPath}`;
40768
+ if (queryParams) {
40769
+ url += `?${new URLSearchParams(queryParams).toString()}`;
40770
+ }
40771
+ const token = await getProxyToken33(config.oauthProxy);
40772
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
39528
40773
  const controller = new AbortController();
39529
40774
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS75);
39530
40775
  try {
39531
- let attempt = 0;
39532
- while (true) {
39533
- const session = await fetchTableauSession(connectionId);
39534
- const resolvedPath = trimmedPath.replace(
39535
- /\{siteId\}/g,
39536
- session.siteId
39537
- );
39538
- const url = `${baseUrl}${resolvedPath}${queryString}`;
39539
- const init = {
40776
+ const response = await fetch(proxyUrl, {
40777
+ method: "POST",
40778
+ headers: {
40779
+ "Content-Type": "application/json",
40780
+ Authorization: `Bearer ${token}`
40781
+ },
40782
+ body: JSON.stringify({
40783
+ url,
39540
40784
  method,
39541
- headers: {
39542
- "X-Tableau-Auth": session.authToken,
39543
- Accept: "application/json",
39544
- "Content-Type": "application/json"
39545
- },
39546
- signal: controller.signal
39547
- };
39548
- if (body !== void 0) {
39549
- init.body = JSON.stringify(body);
39550
- }
39551
- const response = await fetch(url, init);
39552
- const text = await response.text();
39553
- const data = text ? (() => {
39554
- try {
39555
- return JSON.parse(text);
39556
- } catch {
39557
- return text;
39558
- }
39559
- })() : null;
39560
- if (response.status === 401 && attempt === 0) {
39561
- attempt++;
39562
- continue;
39563
- }
39564
- if (!response.ok) {
39565
- const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
39566
- return { success: false, error: errorMessage };
40785
+ ...body !== void 0 ? { body } : {}
40786
+ }),
40787
+ signal: controller.signal
40788
+ });
40789
+ const text = await response.text();
40790
+ const data = text ? (() => {
40791
+ try {
40792
+ return JSON.parse(text);
40793
+ } catch {
40794
+ return text;
39567
40795
  }
39568
- return { success: true, status: response.status, data };
40796
+ })() : null;
40797
+ if (!response.ok) {
40798
+ const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
40799
+ return { success: false, error: errorMessage };
39569
40800
  }
40801
+ return { success: true, status: response.status, data };
39570
40802
  } finally {
39571
40803
  clearTimeout(timeout);
39572
40804
  }
@@ -39758,12 +40990,12 @@ export default async function handler(c: Context) {
39758
40990
  import { z as z99 } from "zod";
39759
40991
  var BASE_HOST13 = "https://graph.microsoft.com";
39760
40992
  var BASE_PATH_SEGMENT19 = "/v1.0";
39761
- var BASE_URL65 = `${BASE_HOST13}${BASE_PATH_SEGMENT19}`;
40993
+ var BASE_URL66 = `${BASE_HOST13}${BASE_PATH_SEGMENT19}`;
39762
40994
  var REQUEST_TIMEOUT_MS76 = 6e4;
39763
- var cachedToken33 = null;
39764
- async function getProxyToken33(config) {
39765
- if (cachedToken33 && cachedToken33.expiresAt > Date.now() + 6e4) {
39766
- return cachedToken33.token;
40995
+ var cachedToken34 = null;
40996
+ async function getProxyToken34(config) {
40997
+ if (cachedToken34 && cachedToken34.expiresAt > Date.now() + 6e4) {
40998
+ return cachedToken34.token;
39767
40999
  }
39768
41000
  const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
39769
41001
  const res = await fetch(url, {
@@ -39785,7 +41017,7 @@ async function getProxyToken33(config) {
39785
41017
  );
39786
41018
  }
39787
41019
  const data = await res.json();
39788
- cachedToken33 = {
41020
+ cachedToken34 = {
39789
41021
  token: data.token,
39790
41022
  expiresAt: new Date(data.expiresAt).getTime()
39791
41023
  };
@@ -39837,12 +41069,12 @@ For full-text search use the \`$search\` query parameter (must be wrapped in dou
39837
41069
  );
39838
41070
  try {
39839
41071
  const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT19);
39840
- let url = `${BASE_URL65}${normalizedPath}`;
41072
+ let url = `${BASE_URL66}${normalizedPath}`;
39841
41073
  if (queryParams) {
39842
41074
  const searchParams = new URLSearchParams(queryParams);
39843
41075
  url += `?${searchParams.toString()}`;
39844
41076
  }
39845
- const token = await getProxyToken33(config.oauthProxy);
41077
+ const token = await getProxyToken34(config.oauthProxy);
39846
41078
  const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
39847
41079
  const controller = new AbortController();
39848
41080
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS76);