@squadbase/vite-server 0.1.17-dev.24af54e → 0.1.17-dev.7408ec4
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.
- package/dist/cli/index.js +1682 -425
- package/dist/connectors/airtable-oauth.js +22 -3
- package/dist/connectors/airtable.js +22 -3
- package/dist/connectors/amplitude.js +22 -3
- package/dist/connectors/asana.js +22 -3
- package/dist/connectors/attio.js +22 -3
- package/dist/connectors/aws-billing.js +22 -3
- package/dist/connectors/azure-sql.js +25 -6
- package/dist/connectors/backlog-api-key.js +22 -3
- package/dist/connectors/clickup.js +22 -3
- package/dist/connectors/cosmosdb.js +22 -3
- package/dist/connectors/customerio.js +23 -4
- package/dist/connectors/dbt.js +22 -3
- package/dist/connectors/freshdesk.js +22 -3
- package/dist/connectors/freshsales.js +22 -3
- package/dist/connectors/freshservice.js +22 -3
- package/dist/connectors/gamma.js +24 -5
- package/dist/connectors/github.js +22 -3
- package/dist/connectors/gmail-oauth.js +22 -3
- package/dist/connectors/gmail.js +22 -3
- package/dist/connectors/google-ads.js +22 -3
- package/dist/connectors/google-analytics-oauth.js +22 -3
- package/dist/connectors/google-analytics.js +222 -68
- package/dist/connectors/google-audit-log.js +22 -3
- package/dist/connectors/google-calendar-oauth.js +22 -3
- package/dist/connectors/google-calendar.js +22 -3
- package/dist/connectors/google-docs.js +22 -3
- package/dist/connectors/google-drive.js +22 -3
- package/dist/connectors/google-search-console-oauth.js +22 -3
- package/dist/connectors/google-sheets.js +22 -3
- package/dist/connectors/google-slides.js +22 -3
- package/dist/connectors/grafana.js +22 -3
- package/dist/connectors/hubspot-oauth.js +22 -3
- package/dist/connectors/hubspot.js +22 -3
- package/dist/connectors/influxdb.js +22 -3
- package/dist/connectors/intercom-oauth.js +22 -3
- package/dist/connectors/intercom.js +22 -3
- package/dist/connectors/jdbc.js +22 -3
- package/dist/connectors/jira-api-key.js +22 -3
- package/dist/connectors/kintone-api-token.js +22 -3
- package/dist/connectors/kintone.js +22 -3
- package/dist/connectors/linear.js +22 -3
- package/dist/connectors/linkedin-ads.js +22 -3
- package/dist/connectors/mailchimp-oauth.js +22 -3
- package/dist/connectors/mailchimp.js +22 -3
- package/dist/connectors/meta-ads-oauth.js +22 -3
- package/dist/connectors/meta-ads.js +22 -3
- package/dist/connectors/mixpanel.js +22 -3
- package/dist/connectors/monday.js +22 -3
- package/dist/connectors/mongodb.js +22 -3
- package/dist/connectors/notion-oauth.js +22 -3
- package/dist/connectors/notion.js +22 -3
- package/dist/connectors/oracle.js +48 -14
- package/dist/connectors/outlook-oauth.js +22 -3
- package/dist/connectors/powerbi-oauth.js +303 -37
- package/dist/connectors/salesforce.js +22 -3
- package/dist/connectors/semrush.js +360 -46
- package/dist/connectors/sentry.js +22 -3
- package/dist/connectors/shopify-oauth.js +22 -3
- package/dist/connectors/shopify.js +22 -3
- package/dist/connectors/sqlserver.js +25 -6
- package/dist/connectors/stripe-api-key.js +22 -3
- package/dist/connectors/stripe-oauth.js +22 -3
- package/dist/connectors/supabase.js +25 -6
- package/dist/connectors/tableau.js +240 -78
- package/dist/connectors/tiktok-ads.js +22 -3
- package/dist/connectors/wix-store.js +22 -3
- package/dist/connectors/zendesk-oauth.js +22 -3
- package/dist/connectors/zendesk.js +22 -3
- package/dist/index.js +1682 -425
- package/dist/main.js +1682 -425
- package/dist/vite-plugin.js +1682 -425
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -856,19 +856,28 @@ 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") {
|
|
867
872
|
return {
|
|
868
873
|
type: "nextQuestion",
|
|
869
874
|
questionSlug: step.slug,
|
|
870
875
|
question: step.question[ctx.language],
|
|
871
|
-
questionType: "text"
|
|
876
|
+
questionType: "text",
|
|
877
|
+
allowFreeText: resolvedAllowFreeText,
|
|
878
|
+
...pendingParameterUpdates.length > 0 && {
|
|
879
|
+
parameterUpdates: pendingParameterUpdates
|
|
880
|
+
}
|
|
872
881
|
};
|
|
873
882
|
}
|
|
874
883
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -880,11 +889,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
880
889
|
questionSlug: step.slug,
|
|
881
890
|
question: step.question[ctx.language],
|
|
882
891
|
questionType: step.type,
|
|
883
|
-
options
|
|
892
|
+
options,
|
|
893
|
+
allowFreeText: resolvedAllowFreeText,
|
|
894
|
+
...pendingParameterUpdates.length > 0 && {
|
|
895
|
+
parameterUpdates: pendingParameterUpdates
|
|
896
|
+
}
|
|
884
897
|
};
|
|
885
898
|
}
|
|
886
899
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
887
|
-
return {
|
|
900
|
+
return {
|
|
901
|
+
type: "fulfilled",
|
|
902
|
+
dataInvestigationResult,
|
|
903
|
+
...pendingParameterUpdates.length > 0 && {
|
|
904
|
+
parameterUpdates: pendingParameterUpdates
|
|
905
|
+
}
|
|
906
|
+
};
|
|
888
907
|
}
|
|
889
908
|
async function resolveSetupSelection(params) {
|
|
890
909
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -1063,7 +1082,46 @@ var INTERNAL_SCHEMAS = /* @__PURE__ */ new Set([
|
|
|
1063
1082
|
"READER_ACCOUNT_USAGE",
|
|
1064
1083
|
"DATA_SHARING_USAGE"
|
|
1065
1084
|
]);
|
|
1085
|
+
var OBJECT_TYPE_LABELS = {
|
|
1086
|
+
table: { ja: "\u30C6\u30FC\u30D6\u30EB", en: "Table" },
|
|
1087
|
+
view: { ja: "\u30D3\u30E5\u30FC", en: "View" },
|
|
1088
|
+
stream: { ja: "\u30B9\u30C8\u30EA\u30FC\u30E0", en: "Stream" },
|
|
1089
|
+
dynamic_table: { ja: "\u30C0\u30A4\u30CA\u30DF\u30C3\u30AF\u30C6\u30FC\u30D6\u30EB", en: "Dynamic Table" },
|
|
1090
|
+
pipe: { ja: "\u30D1\u30A4\u30D7", en: "Pipe" },
|
|
1091
|
+
task: { ja: "\u30BF\u30B9\u30AF", en: "Task" }
|
|
1092
|
+
};
|
|
1093
|
+
var HEADING_LABELS = {
|
|
1094
|
+
table: "Table",
|
|
1095
|
+
view: "View",
|
|
1096
|
+
stream: "Stream",
|
|
1097
|
+
dynamic_table: "Dynamic Table",
|
|
1098
|
+
pipe: "Pipe",
|
|
1099
|
+
task: "Task"
|
|
1100
|
+
};
|
|
1066
1101
|
function createSnowflakeSetupFlow(runQuery11) {
|
|
1102
|
+
const objectTypes = /* @__PURE__ */ new Map();
|
|
1103
|
+
async function fetchAllObjects(params, db, schema) {
|
|
1104
|
+
objectTypes.clear();
|
|
1105
|
+
const typeQueries = [
|
|
1106
|
+
["table", `SHOW TABLES IN SCHEMA "${db}"."${schema}"`],
|
|
1107
|
+
["view", `SHOW VIEWS IN SCHEMA "${db}"."${schema}"`],
|
|
1108
|
+
["stream", `SHOW STREAMS IN SCHEMA "${db}"."${schema}"`],
|
|
1109
|
+
["dynamic_table", `SHOW DYNAMIC TABLES IN SCHEMA "${db}"."${schema}"`],
|
|
1110
|
+
["pipe", `SHOW PIPES IN SCHEMA "${db}"."${schema}"`],
|
|
1111
|
+
["task", `SHOW TASKS IN SCHEMA "${db}"."${schema}"`]
|
|
1112
|
+
];
|
|
1113
|
+
const results = await Promise.all(
|
|
1114
|
+
typeQueries.map(([, sql]) => runQuery11(params, sql).catch(() => []))
|
|
1115
|
+
);
|
|
1116
|
+
for (let i = 0; i < results.length; i++) {
|
|
1117
|
+
const type = typeQueries[i][0];
|
|
1118
|
+
for (const r of results[i]) {
|
|
1119
|
+
const name = String(r["name"] ?? "");
|
|
1120
|
+
if (name) objectTypes.set(name, type);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
return Array.from(objectTypes.keys());
|
|
1124
|
+
}
|
|
1067
1125
|
return {
|
|
1068
1126
|
initialState: () => ({}),
|
|
1069
1127
|
steps: [
|
|
@@ -1103,22 +1161,27 @@ function createSnowflakeSetupFlow(runQuery11) {
|
|
|
1103
1161
|
slug: "tables",
|
|
1104
1162
|
type: "multiSelect",
|
|
1105
1163
|
question: {
|
|
1106
|
-
ja: "\u5BFE\u8C61\
|
|
1107
|
-
en: "Select target tables
|
|
1164
|
+
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",
|
|
1165
|
+
en: "Select target objects (tables, views, streams, etc. \u2014 multi-select allowed)"
|
|
1108
1166
|
},
|
|
1109
1167
|
async fetchOptions(state, rt) {
|
|
1110
1168
|
if (!state.database || !state.schema) return [];
|
|
1111
|
-
const
|
|
1169
|
+
const allNames = await fetchAllObjects(
|
|
1112
1170
|
rt.params,
|
|
1113
|
-
|
|
1171
|
+
state.database,
|
|
1172
|
+
state.schema
|
|
1114
1173
|
);
|
|
1115
|
-
const
|
|
1174
|
+
const options = allNames.map((name) => {
|
|
1175
|
+
const type = objectTypes.get(name) ?? "table";
|
|
1176
|
+
const typeLabel = OBJECT_TYPE_LABELS[type][rt.language];
|
|
1177
|
+
return { value: name, label: `${name} (${typeLabel})` };
|
|
1178
|
+
});
|
|
1116
1179
|
return [
|
|
1117
1180
|
{
|
|
1118
1181
|
value: ALL_TABLES,
|
|
1119
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\
|
|
1182
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8" : "All objects"
|
|
1120
1183
|
},
|
|
1121
|
-
...
|
|
1184
|
+
...options
|
|
1122
1185
|
];
|
|
1123
1186
|
},
|
|
1124
1187
|
applyAnswer: (state, answer) => ({ ...state, tables: answer })
|
|
@@ -1130,16 +1193,10 @@ function createSnowflakeSetupFlow(runQuery11) {
|
|
|
1130
1193
|
}
|
|
1131
1194
|
const db = state.database;
|
|
1132
1195
|
const schema = state.schema;
|
|
1133
|
-
const
|
|
1196
|
+
const targetObjects = await resolveSetupSelection({
|
|
1134
1197
|
selected: state.tables,
|
|
1135
1198
|
allSentinel: ALL_TABLES,
|
|
1136
|
-
fetchAll:
|
|
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
|
-
},
|
|
1199
|
+
fetchAll: () => fetchAllObjects(rt.params, db, schema),
|
|
1143
1200
|
limit: SNOWFLAKE_SETUP_MAX_TABLES
|
|
1144
1201
|
});
|
|
1145
1202
|
const sections = [
|
|
@@ -1150,24 +1207,66 @@ function createSnowflakeSetupFlow(runQuery11) {
|
|
|
1150
1207
|
`#### Schema: ${schema}`,
|
|
1151
1208
|
""
|
|
1152
1209
|
];
|
|
1153
|
-
for (const
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1210
|
+
for (const name of targetObjects) {
|
|
1211
|
+
const type = objectTypes.get(name) ?? "table";
|
|
1212
|
+
const heading = HEADING_LABELS[type];
|
|
1213
|
+
switch (type) {
|
|
1214
|
+
case "table":
|
|
1215
|
+
case "view":
|
|
1216
|
+
case "dynamic_table":
|
|
1217
|
+
case "stream": {
|
|
1218
|
+
const cols = await runQuery11(
|
|
1219
|
+
rt.params,
|
|
1220
|
+
`DESCRIBE TABLE "${db}"."${schema}"."${name}"`
|
|
1221
|
+
).catch(() => []);
|
|
1222
|
+
sections.push(`##### ${heading}: ${name}`, "");
|
|
1223
|
+
if (cols.length > 0) {
|
|
1224
|
+
sections.push("| Column | Type | Nullable | Default |");
|
|
1225
|
+
sections.push("|--------|------|----------|---------|");
|
|
1226
|
+
for (const c of cols) {
|
|
1227
|
+
const colName = String(c["name"] ?? "");
|
|
1228
|
+
const colType = String(c["type"] ?? "");
|
|
1229
|
+
const nullable = String(c["null?"] ?? "");
|
|
1230
|
+
const defaultValue = c["default"] == null ? "-" : String(c["default"]);
|
|
1231
|
+
sections.push(
|
|
1232
|
+
`| ${colName} | ${colType} | ${nullable} | ${defaultValue} |`
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
sections.push("");
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1239
|
+
case "pipe": {
|
|
1240
|
+
const rows = await runQuery11(
|
|
1241
|
+
rt.params,
|
|
1242
|
+
`SHOW PIPES LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
|
|
1243
|
+
).catch(() => []);
|
|
1244
|
+
sections.push(`##### Pipe: ${name}`, "");
|
|
1245
|
+
if (rows.length > 0) {
|
|
1246
|
+
const definition = String(rows[0]["definition"] ?? "-");
|
|
1247
|
+
sections.push(`Definition: \`${definition}\``, "");
|
|
1248
|
+
}
|
|
1249
|
+
sections.push("");
|
|
1250
|
+
break;
|
|
1251
|
+
}
|
|
1252
|
+
case "task": {
|
|
1253
|
+
const rows = await runQuery11(
|
|
1254
|
+
rt.params,
|
|
1255
|
+
`SHOW TASKS LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
|
|
1256
|
+
).catch(() => []);
|
|
1257
|
+
sections.push(`##### Task: ${name}`, "");
|
|
1258
|
+
if (rows.length > 0) {
|
|
1259
|
+
const schedule = String(rows[0]["schedule"] ?? "-");
|
|
1260
|
+
const taskState = String(rows[0]["state"] ?? "-");
|
|
1261
|
+
const definition = String(rows[0]["definition"] ?? "-");
|
|
1262
|
+
sections.push(`Schedule: ${schedule}`, "");
|
|
1263
|
+
sections.push(`State: ${taskState}`, "");
|
|
1264
|
+
sections.push(`Definition: \`${definition}\``, "");
|
|
1265
|
+
}
|
|
1266
|
+
sections.push("");
|
|
1267
|
+
break;
|
|
1268
|
+
}
|
|
1169
1269
|
}
|
|
1170
|
-
sections.push("");
|
|
1171
1270
|
}
|
|
1172
1271
|
return sections.join("\n");
|
|
1173
1272
|
}
|
|
@@ -1980,8 +2079,8 @@ var postgresqlSetupFlow = {
|
|
|
1980
2079
|
slug: "tables",
|
|
1981
2080
|
type: "multiSelect",
|
|
1982
2081
|
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)"
|
|
2082
|
+
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",
|
|
2083
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
1985
2084
|
},
|
|
1986
2085
|
async fetchOptions(state, rt) {
|
|
1987
2086
|
if (!state.schema) return [];
|
|
@@ -1990,7 +2089,7 @@ var postgresqlSetupFlow = {
|
|
|
1990
2089
|
return [
|
|
1991
2090
|
{
|
|
1992
2091
|
value: ALL_TABLES2,
|
|
1993
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
2092
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
1994
2093
|
},
|
|
1995
2094
|
...tableOptions
|
|
1996
2095
|
];
|
|
@@ -2327,8 +2426,8 @@ var mysqlSetupFlow = {
|
|
|
2327
2426
|
slug: "tables",
|
|
2328
2427
|
type: "multiSelect",
|
|
2329
2428
|
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)"
|
|
2429
|
+
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",
|
|
2430
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
2332
2431
|
},
|
|
2333
2432
|
async fetchOptions(state, rt) {
|
|
2334
2433
|
if (!state.database) return [];
|
|
@@ -2337,7 +2436,7 @@ var mysqlSetupFlow = {
|
|
|
2337
2436
|
return [
|
|
2338
2437
|
{
|
|
2339
2438
|
value: ALL_TABLES3,
|
|
2340
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
2439
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
2341
2440
|
},
|
|
2342
2441
|
...tableOptions
|
|
2343
2442
|
];
|
|
@@ -2788,6 +2887,72 @@ var bigqueryOnboarding = new ConnectorOnboarding({
|
|
|
2788
2887
|
}
|
|
2789
2888
|
});
|
|
2790
2889
|
|
|
2890
|
+
// ../connectors/src/table-grouping.ts
|
|
2891
|
+
var SHARD_GROUP_PREFIX = "__SHARD__";
|
|
2892
|
+
var DEFAULT_MIN_SHARD_GROUP_SIZE = 3;
|
|
2893
|
+
function extractDateShardSuffix(name) {
|
|
2894
|
+
const m = name.match(/^(.+)_(\d{8})$/);
|
|
2895
|
+
if (!m) return null;
|
|
2896
|
+
const [, prefix, suffix] = m;
|
|
2897
|
+
const y = +suffix.slice(0, 4);
|
|
2898
|
+
const mo = +suffix.slice(4, 6);
|
|
2899
|
+
const d = +suffix.slice(6, 8);
|
|
2900
|
+
if (y < 2e3 || y > 2099 || mo < 1 || mo > 12 || d < 1 || d > 31) {
|
|
2901
|
+
return null;
|
|
2902
|
+
}
|
|
2903
|
+
return { prefix, suffix };
|
|
2904
|
+
}
|
|
2905
|
+
function detectDateShardCandidates(tableNames, minCount = DEFAULT_MIN_SHARD_GROUP_SIZE) {
|
|
2906
|
+
const prefixMap = /* @__PURE__ */ new Map();
|
|
2907
|
+
const nonSharded = [];
|
|
2908
|
+
for (const name of tableNames) {
|
|
2909
|
+
const parsed = extractDateShardSuffix(name);
|
|
2910
|
+
if (parsed) {
|
|
2911
|
+
const existing = prefixMap.get(parsed.prefix);
|
|
2912
|
+
if (existing) {
|
|
2913
|
+
existing.push(name);
|
|
2914
|
+
} else {
|
|
2915
|
+
prefixMap.set(parsed.prefix, [name]);
|
|
2916
|
+
}
|
|
2917
|
+
} else {
|
|
2918
|
+
nonSharded.push(name);
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
const candidates = [];
|
|
2922
|
+
const singles = [...nonSharded];
|
|
2923
|
+
for (const [prefix, members] of prefixMap) {
|
|
2924
|
+
if (members.length >= minCount) {
|
|
2925
|
+
candidates.push({ prefix, count: members.length, members });
|
|
2926
|
+
} else {
|
|
2927
|
+
singles.push(...members);
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
return { singles, candidates };
|
|
2931
|
+
}
|
|
2932
|
+
function schemasMatch(columnsA, columnsB) {
|
|
2933
|
+
if (columnsA.length !== columnsB.length) return false;
|
|
2934
|
+
return columnsA.every(
|
|
2935
|
+
(a, i) => String(a["column_name"] ?? "") === String(columnsB[i]["column_name"] ?? "") && String(a["data_type"] ?? "") === String(columnsB[i]["data_type"] ?? "")
|
|
2936
|
+
);
|
|
2937
|
+
}
|
|
2938
|
+
function isShardGroupValue(value) {
|
|
2939
|
+
return value.startsWith(SHARD_GROUP_PREFIX);
|
|
2940
|
+
}
|
|
2941
|
+
function getShardGroupPrefix(value) {
|
|
2942
|
+
return value.slice(SHARD_GROUP_PREFIX.length);
|
|
2943
|
+
}
|
|
2944
|
+
function shardGroupValue(prefix) {
|
|
2945
|
+
return `${SHARD_GROUP_PREFIX}${prefix}`;
|
|
2946
|
+
}
|
|
2947
|
+
function buildGroupedTableOptions(singles, confirmedGroups, language) {
|
|
2948
|
+
const groupOptions = confirmedGroups.sort((a, b) => a.prefix.localeCompare(b.prefix)).map((g) => ({
|
|
2949
|
+
value: shardGroupValue(g.prefix),
|
|
2950
|
+
label: language === "ja" ? `${g.prefix}_* (\u65E5\u4ED8\u30B7\u30E3\u30FC\u30C9: ${g.count} \u30C6\u30FC\u30D6\u30EB)` : `${g.prefix}_* (date-sharded: ${g.count} tables)`
|
|
2951
|
+
}));
|
|
2952
|
+
const singleOptions = singles.sort().map((name) => ({ value: name }));
|
|
2953
|
+
return [...groupOptions, ...singleOptions];
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2791
2956
|
// ../connectors/src/connectors/bigquery/utils.ts
|
|
2792
2957
|
async function runQuery5(params, sql) {
|
|
2793
2958
|
const { BigQuery } = await import("@google-cloud/bigquery");
|
|
@@ -2818,13 +2983,23 @@ async function listProjects(params) {
|
|
|
2818
2983
|
scopes: ["https://www.googleapis.com/auth/bigquery"]
|
|
2819
2984
|
});
|
|
2820
2985
|
const client = await auth.getClient();
|
|
2821
|
-
const
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2986
|
+
const projects = [];
|
|
2987
|
+
let pageToken;
|
|
2988
|
+
do {
|
|
2989
|
+
const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
|
|
2990
|
+
const res = await client.request({ url });
|
|
2991
|
+
for (const p of res.data.projects ?? []) {
|
|
2992
|
+
const id = p.projectReference?.projectId ?? "";
|
|
2993
|
+
if (id) {
|
|
2994
|
+
projects.push({
|
|
2995
|
+
projectId: id,
|
|
2996
|
+
friendlyName: p.friendlyName ?? id
|
|
2997
|
+
});
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
pageToken = res.data.nextPageToken;
|
|
3001
|
+
} while (pageToken);
|
|
3002
|
+
return projects;
|
|
2828
3003
|
}
|
|
2829
3004
|
async function listDatasets(params, projectId2) {
|
|
2830
3005
|
const { BigQuery } = await import("@google-cloud/bigquery");
|
|
@@ -2862,23 +3037,25 @@ var PUBLIC_DATASETS = [
|
|
|
2862
3037
|
labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
|
|
2863
3038
|
}
|
|
2864
3039
|
];
|
|
3040
|
+
var SAME_AS_BILLING = "__SAME_AS_BILLING__";
|
|
2865
3041
|
function resolveDatasetRef(state) {
|
|
2866
3042
|
const dataset = state.dataset ?? "";
|
|
2867
3043
|
if (dataset.includes(".")) {
|
|
2868
3044
|
const [datasetProject, ...rest] = dataset.split(".");
|
|
2869
3045
|
return { datasetProject, datasetId: rest.join(".") };
|
|
2870
3046
|
}
|
|
2871
|
-
return { datasetProject: state.
|
|
3047
|
+
return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
|
|
2872
3048
|
}
|
|
2873
3049
|
var bigquerySetupFlow = {
|
|
2874
3050
|
initialState: () => ({}),
|
|
2875
3051
|
steps: [
|
|
2876
3052
|
{
|
|
2877
|
-
slug: "
|
|
3053
|
+
slug: "billingProject",
|
|
2878
3054
|
type: "select",
|
|
3055
|
+
allowFreeText: false,
|
|
2879
3056
|
question: {
|
|
2880
|
-
ja: "\
|
|
2881
|
-
en: "Select the
|
|
3057
|
+
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",
|
|
3058
|
+
en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
|
|
2882
3059
|
},
|
|
2883
3060
|
async fetchOptions(_state, rt) {
|
|
2884
3061
|
const projects = await listProjects(rt.params);
|
|
@@ -2887,7 +3064,40 @@ var bigquerySetupFlow = {
|
|
|
2887
3064
|
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
2888
3065
|
}));
|
|
2889
3066
|
},
|
|
2890
|
-
applyAnswer: (state, answer) => ({
|
|
3067
|
+
applyAnswer: (state, answer) => ({
|
|
3068
|
+
...state,
|
|
3069
|
+
billingProject: answer[0]
|
|
3070
|
+
}),
|
|
3071
|
+
toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
|
|
3072
|
+
},
|
|
3073
|
+
{
|
|
3074
|
+
slug: "databaseProject",
|
|
3075
|
+
type: "select",
|
|
3076
|
+
question: {
|
|
3077
|
+
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",
|
|
3078
|
+
en: "Select the GCP project where your data resides"
|
|
3079
|
+
},
|
|
3080
|
+
async fetchOptions(state, rt) {
|
|
3081
|
+
if (!state.billingProject) return [];
|
|
3082
|
+
const sameAsBillingOption = {
|
|
3083
|
+
value: SAME_AS_BILLING,
|
|
3084
|
+
label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
|
|
3085
|
+
};
|
|
3086
|
+
const projects = await listProjects(rt.params);
|
|
3087
|
+
const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
|
|
3088
|
+
value: p.projectId,
|
|
3089
|
+
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
3090
|
+
}));
|
|
3091
|
+
const publicProjectOption = {
|
|
3092
|
+
value: "bigquery-public-data",
|
|
3093
|
+
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)"
|
|
3094
|
+
};
|
|
3095
|
+
return [sameAsBillingOption, ...projectOptions, publicProjectOption];
|
|
3096
|
+
},
|
|
3097
|
+
applyAnswer: (state, answer) => ({
|
|
3098
|
+
...state,
|
|
3099
|
+
databaseProject: answer[0] === SAME_AS_BILLING ? state.billingProject : answer[0]
|
|
3100
|
+
})
|
|
2891
3101
|
},
|
|
2892
3102
|
{
|
|
2893
3103
|
slug: "dataset",
|
|
@@ -2897,8 +3107,8 @@ var bigquerySetupFlow = {
|
|
|
2897
3107
|
en: "Select the dataset to use for setup"
|
|
2898
3108
|
},
|
|
2899
3109
|
async fetchOptions(state, rt) {
|
|
2900
|
-
if (!state.
|
|
2901
|
-
const datasets = await listDatasets(rt.params, state.
|
|
3110
|
+
if (!state.databaseProject) return [];
|
|
3111
|
+
const datasets = await listDatasets(rt.params, state.databaseProject);
|
|
2902
3112
|
const projectDatasetOptions = datasets.map((d) => ({
|
|
2903
3113
|
value: d.datasetId,
|
|
2904
3114
|
label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
|
|
@@ -2915,66 +3125,140 @@ var bigquerySetupFlow = {
|
|
|
2915
3125
|
slug: "tables",
|
|
2916
3126
|
type: "multiSelect",
|
|
2917
3127
|
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)"
|
|
3128
|
+
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",
|
|
3129
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
2920
3130
|
},
|
|
2921
3131
|
async fetchOptions(state, rt) {
|
|
2922
|
-
if (!state.
|
|
3132
|
+
if (!state.billingProject || !state.dataset) return [];
|
|
2923
3133
|
const { datasetProject, datasetId } = resolveDatasetRef(state);
|
|
2924
3134
|
const rows = await runQuery5(
|
|
2925
3135
|
rt.params,
|
|
2926
3136
|
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
2927
3137
|
);
|
|
2928
|
-
const
|
|
3138
|
+
const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3139
|
+
const { singles, candidates } = detectDateShardCandidates(tableNames);
|
|
3140
|
+
const confirmedGroups = [];
|
|
3141
|
+
const rejectedSingles = [];
|
|
3142
|
+
for (const candidate of candidates) {
|
|
3143
|
+
const [first, second] = candidate.members;
|
|
3144
|
+
const colRows = await runQuery5(
|
|
3145
|
+
rt.params,
|
|
3146
|
+
`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`
|
|
3147
|
+
);
|
|
3148
|
+
const colsA = colRows.filter(
|
|
3149
|
+
(r) => String(r["table_name"]) === first
|
|
3150
|
+
);
|
|
3151
|
+
const colsB = colRows.filter(
|
|
3152
|
+
(r) => String(r["table_name"]) === second
|
|
3153
|
+
);
|
|
3154
|
+
if (schemasMatch(colsA, colsB)) {
|
|
3155
|
+
confirmedGroups.push(candidate);
|
|
3156
|
+
} else {
|
|
3157
|
+
rejectedSingles.push(...candidate.members);
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
const allSingles = [...singles, ...rejectedSingles];
|
|
2929
3161
|
return [
|
|
2930
3162
|
{
|
|
2931
3163
|
value: ALL_TABLES4,
|
|
2932
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
3164
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
2933
3165
|
},
|
|
2934
|
-
...
|
|
3166
|
+
...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
|
|
2935
3167
|
];
|
|
2936
3168
|
},
|
|
2937
3169
|
applyAnswer: (state, answer) => ({ ...state, tables: answer })
|
|
2938
3170
|
}
|
|
2939
3171
|
],
|
|
2940
3172
|
async finalize(state, rt) {
|
|
2941
|
-
if (!state.
|
|
3173
|
+
if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
|
|
2942
3174
|
throw new Error("BigQuery setup: incomplete state on finalize");
|
|
2943
3175
|
}
|
|
2944
3176
|
const { datasetProject, datasetId } = resolveDatasetRef(state);
|
|
2945
|
-
const
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
3177
|
+
const fetchAllTableNames = async () => {
|
|
3178
|
+
const rows = await runQuery5(
|
|
3179
|
+
rt.params,
|
|
3180
|
+
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
3181
|
+
);
|
|
3182
|
+
return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3183
|
+
};
|
|
3184
|
+
let entries;
|
|
3185
|
+
if (state.tables.includes(ALL_TABLES4)) {
|
|
3186
|
+
const allNames = await fetchAllTableNames();
|
|
3187
|
+
const { singles, candidates } = detectDateShardCandidates(allNames);
|
|
3188
|
+
entries = [
|
|
3189
|
+
...candidates.map(
|
|
3190
|
+
(g) => ({
|
|
3191
|
+
type: "shardGroup",
|
|
3192
|
+
prefix: g.prefix,
|
|
3193
|
+
count: g.count,
|
|
3194
|
+
representative: g.members[0]
|
|
3195
|
+
})
|
|
3196
|
+
),
|
|
3197
|
+
...singles.map((name) => ({ type: "table", name }))
|
|
3198
|
+
];
|
|
3199
|
+
} else {
|
|
3200
|
+
const shardSelections = state.tables.filter(isShardGroupValue);
|
|
3201
|
+
const tableSelections = state.tables.filter(
|
|
3202
|
+
(v) => !isShardGroupValue(v)
|
|
3203
|
+
);
|
|
3204
|
+
entries = tableSelections.map(
|
|
3205
|
+
(name) => ({ type: "table", name })
|
|
3206
|
+
);
|
|
3207
|
+
if (shardSelections.length > 0) {
|
|
3208
|
+
const allNames = await fetchAllTableNames();
|
|
3209
|
+
for (const value of shardSelections) {
|
|
3210
|
+
const prefix = getShardGroupPrefix(value);
|
|
3211
|
+
const members = allNames.filter((n) => {
|
|
3212
|
+
const parsed = extractDateShardSuffix(n);
|
|
3213
|
+
return parsed != null && parsed.prefix === prefix;
|
|
3214
|
+
});
|
|
3215
|
+
if (members.length > 0) {
|
|
3216
|
+
entries.push({
|
|
3217
|
+
type: "shardGroup",
|
|
3218
|
+
prefix,
|
|
3219
|
+
count: members.length,
|
|
3220
|
+
representative: members[0]
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
entries = entries.slice(0, BIGQUERY_SETUP_MAX_TABLES);
|
|
3227
|
+
const queryColumns = async (tableName) => runQuery5(
|
|
3228
|
+
rt.params,
|
|
3229
|
+
`SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
|
|
3230
|
+
);
|
|
2957
3231
|
const sections = [
|
|
2958
3232
|
"## BigQuery",
|
|
2959
3233
|
"",
|
|
2960
|
-
`### Billing project: ${state.
|
|
3234
|
+
`### Billing project: ${state.billingProject}`,
|
|
3235
|
+
"",
|
|
3236
|
+
`### Database project: ${state.databaseProject}`,
|
|
2961
3237
|
"",
|
|
2962
3238
|
`#### Dataset: ${datasetProject}.${datasetId}`,
|
|
2963
3239
|
""
|
|
2964
3240
|
];
|
|
2965
|
-
for (const
|
|
2966
|
-
const
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
3241
|
+
for (const entry of entries) {
|
|
3242
|
+
const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
|
|
3243
|
+
const cols = await queryColumns(tableName);
|
|
3244
|
+
if (entry.type === "shardGroup") {
|
|
3245
|
+
sections.push(
|
|
3246
|
+
`##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
|
|
3247
|
+
""
|
|
3248
|
+
);
|
|
3249
|
+
sections.push(
|
|
3250
|
+
`_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
|
|
3251
|
+
""
|
|
3252
|
+
);
|
|
3253
|
+
} else {
|
|
3254
|
+
sections.push(`##### Table: ${entry.name}`, "");
|
|
3255
|
+
}
|
|
2971
3256
|
sections.push("| Column | Type | Nullable |");
|
|
2972
3257
|
sections.push("|--------|------|----------|");
|
|
2973
3258
|
for (const c of cols) {
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
sections.push(`| ${name} | ${type} | ${nullable} |`);
|
|
3259
|
+
sections.push(
|
|
3260
|
+
`| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
|
|
3261
|
+
);
|
|
2978
3262
|
}
|
|
2979
3263
|
sections.push("");
|
|
2980
3264
|
}
|
|
@@ -3472,21 +3756,30 @@ async function runQuery6(proxyFetch, projectId2, sql) {
|
|
|
3472
3756
|
return parseQueryResponse(data);
|
|
3473
3757
|
}
|
|
3474
3758
|
async function listProjects2(proxyFetch) {
|
|
3475
|
-
const
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3759
|
+
const projects = [];
|
|
3760
|
+
let pageToken;
|
|
3761
|
+
do {
|
|
3762
|
+
const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
|
|
3763
|
+
const res = await proxyFetch(url, { method: "GET" });
|
|
3764
|
+
if (!res.ok) {
|
|
3765
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
3766
|
+
throw new Error(
|
|
3767
|
+
`BigQuery listProjects failed: HTTP ${res.status} ${errorText}`
|
|
3768
|
+
);
|
|
3769
|
+
}
|
|
3770
|
+
const data = await res.json();
|
|
3771
|
+
for (const p of data.projects ?? []) {
|
|
3772
|
+
const id = p.projectReference?.projectId ?? "";
|
|
3773
|
+
if (id) {
|
|
3774
|
+
projects.push({
|
|
3775
|
+
projectId: id,
|
|
3776
|
+
friendlyName: p.friendlyName ?? id
|
|
3777
|
+
});
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
pageToken = data.nextPageToken;
|
|
3781
|
+
} while (pageToken);
|
|
3782
|
+
return projects;
|
|
3490
3783
|
}
|
|
3491
3784
|
async function listDatasets2(proxyFetch, projectId2) {
|
|
3492
3785
|
const res = await proxyFetch(
|
|
@@ -3526,23 +3819,25 @@ var PUBLIC_DATASETS2 = [
|
|
|
3526
3819
|
labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
|
|
3527
3820
|
}
|
|
3528
3821
|
];
|
|
3822
|
+
var SAME_AS_BILLING2 = "__SAME_AS_BILLING__";
|
|
3529
3823
|
function resolveDatasetRef2(state) {
|
|
3530
3824
|
const dataset = state.dataset ?? "";
|
|
3531
3825
|
if (dataset.includes(".")) {
|
|
3532
3826
|
const [datasetProject, ...rest] = dataset.split(".");
|
|
3533
3827
|
return { datasetProject, datasetId: rest.join(".") };
|
|
3534
3828
|
}
|
|
3535
|
-
return { datasetProject: state.
|
|
3829
|
+
return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
|
|
3536
3830
|
}
|
|
3537
3831
|
var bigqueryOauthSetupFlow = {
|
|
3538
3832
|
initialState: () => ({}),
|
|
3539
3833
|
steps: [
|
|
3540
3834
|
{
|
|
3541
|
-
slug: "
|
|
3835
|
+
slug: "billingProject",
|
|
3542
3836
|
type: "select",
|
|
3837
|
+
allowFreeText: false,
|
|
3543
3838
|
question: {
|
|
3544
|
-
ja: "\
|
|
3545
|
-
en: "Select the
|
|
3839
|
+
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",
|
|
3840
|
+
en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
|
|
3546
3841
|
},
|
|
3547
3842
|
async fetchOptions(_state, rt) {
|
|
3548
3843
|
const projects = await listProjects2(rt.config.proxyFetch);
|
|
@@ -3551,7 +3846,40 @@ var bigqueryOauthSetupFlow = {
|
|
|
3551
3846
|
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
3552
3847
|
}));
|
|
3553
3848
|
},
|
|
3554
|
-
applyAnswer: (state, answer) => ({
|
|
3849
|
+
applyAnswer: (state, answer) => ({
|
|
3850
|
+
...state,
|
|
3851
|
+
billingProject: answer[0]
|
|
3852
|
+
}),
|
|
3853
|
+
toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
|
|
3854
|
+
},
|
|
3855
|
+
{
|
|
3856
|
+
slug: "databaseProject",
|
|
3857
|
+
type: "select",
|
|
3858
|
+
question: {
|
|
3859
|
+
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",
|
|
3860
|
+
en: "Select the GCP project where your data resides"
|
|
3861
|
+
},
|
|
3862
|
+
async fetchOptions(state, rt) {
|
|
3863
|
+
if (!state.billingProject) return [];
|
|
3864
|
+
const sameAsBillingOption = {
|
|
3865
|
+
value: SAME_AS_BILLING2,
|
|
3866
|
+
label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
|
|
3867
|
+
};
|
|
3868
|
+
const projects = await listProjects2(rt.config.proxyFetch);
|
|
3869
|
+
const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
|
|
3870
|
+
value: p.projectId,
|
|
3871
|
+
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
3872
|
+
}));
|
|
3873
|
+
const publicProjectOption = {
|
|
3874
|
+
value: "bigquery-public-data",
|
|
3875
|
+
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)"
|
|
3876
|
+
};
|
|
3877
|
+
return [sameAsBillingOption, ...projectOptions, publicProjectOption];
|
|
3878
|
+
},
|
|
3879
|
+
applyAnswer: (state, answer) => ({
|
|
3880
|
+
...state,
|
|
3881
|
+
databaseProject: answer[0] === SAME_AS_BILLING2 ? state.billingProject : answer[0]
|
|
3882
|
+
})
|
|
3555
3883
|
},
|
|
3556
3884
|
{
|
|
3557
3885
|
slug: "dataset",
|
|
@@ -3561,8 +3889,11 @@ var bigqueryOauthSetupFlow = {
|
|
|
3561
3889
|
en: "Select the dataset to use for setup"
|
|
3562
3890
|
},
|
|
3563
3891
|
async fetchOptions(state, rt) {
|
|
3564
|
-
if (!state.
|
|
3565
|
-
const datasets = await listDatasets2(
|
|
3892
|
+
if (!state.databaseProject) return [];
|
|
3893
|
+
const datasets = await listDatasets2(
|
|
3894
|
+
rt.config.proxyFetch,
|
|
3895
|
+
state.databaseProject
|
|
3896
|
+
);
|
|
3566
3897
|
const projectDatasetOptions = datasets.map((d) => ({
|
|
3567
3898
|
value: d.datasetId,
|
|
3568
3899
|
label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
|
|
@@ -3579,70 +3910,145 @@ var bigqueryOauthSetupFlow = {
|
|
|
3579
3910
|
slug: "tables",
|
|
3580
3911
|
type: "multiSelect",
|
|
3581
3912
|
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)"
|
|
3913
|
+
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",
|
|
3914
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
3584
3915
|
},
|
|
3585
3916
|
async fetchOptions(state, rt) {
|
|
3586
|
-
if (!state.
|
|
3917
|
+
if (!state.billingProject || !state.dataset) return [];
|
|
3587
3918
|
const { datasetProject, datasetId } = resolveDatasetRef2(state);
|
|
3588
3919
|
const rows = await runQuery6(
|
|
3589
3920
|
rt.config.proxyFetch,
|
|
3590
|
-
state.
|
|
3921
|
+
state.billingProject,
|
|
3591
3922
|
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
3592
3923
|
);
|
|
3593
|
-
const
|
|
3924
|
+
const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3925
|
+
const { singles, candidates } = detectDateShardCandidates(tableNames);
|
|
3926
|
+
const confirmedGroups = [];
|
|
3927
|
+
const rejectedSingles = [];
|
|
3928
|
+
for (const candidate of candidates) {
|
|
3929
|
+
const [first, second] = candidate.members;
|
|
3930
|
+
const colRows = await runQuery6(
|
|
3931
|
+
rt.config.proxyFetch,
|
|
3932
|
+
state.billingProject,
|
|
3933
|
+
`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`
|
|
3934
|
+
);
|
|
3935
|
+
const colsA = colRows.filter(
|
|
3936
|
+
(r) => String(r["table_name"]) === first
|
|
3937
|
+
);
|
|
3938
|
+
const colsB = colRows.filter(
|
|
3939
|
+
(r) => String(r["table_name"]) === second
|
|
3940
|
+
);
|
|
3941
|
+
if (schemasMatch(colsA, colsB)) {
|
|
3942
|
+
confirmedGroups.push(candidate);
|
|
3943
|
+
} else {
|
|
3944
|
+
rejectedSingles.push(...candidate.members);
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
const allSingles = [...singles, ...rejectedSingles];
|
|
3594
3948
|
return [
|
|
3595
3949
|
{
|
|
3596
3950
|
value: ALL_TABLES5,
|
|
3597
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
3951
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
3598
3952
|
},
|
|
3599
|
-
...
|
|
3953
|
+
...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
|
|
3600
3954
|
];
|
|
3601
3955
|
},
|
|
3602
3956
|
applyAnswer: (state, answer) => ({ ...state, tables: answer })
|
|
3603
3957
|
}
|
|
3604
3958
|
],
|
|
3605
3959
|
async finalize(state, rt) {
|
|
3606
|
-
if (!state.
|
|
3960
|
+
if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
|
|
3607
3961
|
throw new Error("BigQuery OAuth setup: incomplete state on finalize");
|
|
3608
3962
|
}
|
|
3609
|
-
const billingProject = state.
|
|
3963
|
+
const billingProject = state.billingProject;
|
|
3610
3964
|
const { datasetProject, datasetId } = resolveDatasetRef2(state);
|
|
3611
|
-
const
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3965
|
+
const fetchAllTableNames = async () => {
|
|
3966
|
+
const rows = await runQuery6(
|
|
3967
|
+
rt.config.proxyFetch,
|
|
3968
|
+
billingProject,
|
|
3969
|
+
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
3970
|
+
);
|
|
3971
|
+
return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3972
|
+
};
|
|
3973
|
+
let entries;
|
|
3974
|
+
if (state.tables.includes(ALL_TABLES5)) {
|
|
3975
|
+
const allNames = await fetchAllTableNames();
|
|
3976
|
+
const { singles, candidates } = detectDateShardCandidates(allNames);
|
|
3977
|
+
entries = [
|
|
3978
|
+
...candidates.map(
|
|
3979
|
+
(g) => ({
|
|
3980
|
+
type: "shardGroup",
|
|
3981
|
+
prefix: g.prefix,
|
|
3982
|
+
count: g.count,
|
|
3983
|
+
representative: g.members[0]
|
|
3984
|
+
})
|
|
3985
|
+
),
|
|
3986
|
+
...singles.map((name) => ({ type: "table", name }))
|
|
3987
|
+
];
|
|
3988
|
+
} else {
|
|
3989
|
+
const shardSelections = state.tables.filter(isShardGroupValue);
|
|
3990
|
+
const tableSelections = state.tables.filter(
|
|
3991
|
+
(v) => !isShardGroupValue(v)
|
|
3992
|
+
);
|
|
3993
|
+
entries = tableSelections.map(
|
|
3994
|
+
(name) => ({ type: "table", name })
|
|
3995
|
+
);
|
|
3996
|
+
if (shardSelections.length > 0) {
|
|
3997
|
+
const allNames = await fetchAllTableNames();
|
|
3998
|
+
for (const value of shardSelections) {
|
|
3999
|
+
const prefix = getShardGroupPrefix(value);
|
|
4000
|
+
const members = allNames.filter((n) => {
|
|
4001
|
+
const parsed = extractDateShardSuffix(n);
|
|
4002
|
+
return parsed != null && parsed.prefix === prefix;
|
|
4003
|
+
});
|
|
4004
|
+
if (members.length > 0) {
|
|
4005
|
+
entries.push({
|
|
4006
|
+
type: "shardGroup",
|
|
4007
|
+
prefix,
|
|
4008
|
+
count: members.length,
|
|
4009
|
+
representative: members[0]
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
entries = entries.slice(0, BIGQUERY_OAUTH_SETUP_MAX_TABLES);
|
|
4016
|
+
const queryColumns = async (tableName) => runQuery6(
|
|
4017
|
+
rt.config.proxyFetch,
|
|
4018
|
+
billingProject,
|
|
4019
|
+
`SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
|
|
4020
|
+
);
|
|
3624
4021
|
const sections = [
|
|
3625
4022
|
"## BigQuery (OAuth)",
|
|
3626
4023
|
"",
|
|
3627
4024
|
`### Billing project: ${billingProject}`,
|
|
3628
4025
|
"",
|
|
4026
|
+
`### Database project: ${state.databaseProject}`,
|
|
4027
|
+
"",
|
|
3629
4028
|
`#### Dataset: ${datasetProject}.${datasetId}`,
|
|
3630
4029
|
""
|
|
3631
4030
|
];
|
|
3632
|
-
for (const
|
|
3633
|
-
const
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
4031
|
+
for (const entry of entries) {
|
|
4032
|
+
const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
|
|
4033
|
+
const cols = await queryColumns(tableName);
|
|
4034
|
+
if (entry.type === "shardGroup") {
|
|
4035
|
+
sections.push(
|
|
4036
|
+
`##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
|
|
4037
|
+
""
|
|
4038
|
+
);
|
|
4039
|
+
sections.push(
|
|
4040
|
+
`_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
|
|
4041
|
+
""
|
|
4042
|
+
);
|
|
4043
|
+
} else {
|
|
4044
|
+
sections.push(`##### Table: ${entry.name}`, "");
|
|
4045
|
+
}
|
|
3639
4046
|
sections.push("| Column | Type | Nullable |");
|
|
3640
4047
|
sections.push("|--------|------|----------|");
|
|
3641
4048
|
for (const c of cols) {
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
sections.push(`| ${name} | ${type} | ${nullable} |`);
|
|
4049
|
+
sections.push(
|
|
4050
|
+
`| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
|
|
4051
|
+
);
|
|
3646
4052
|
}
|
|
3647
4053
|
sections.push("");
|
|
3648
4054
|
}
|
|
@@ -5351,14 +5757,15 @@ function isInternalSchema2(name) {
|
|
|
5351
5757
|
function quoteLiteral(value) {
|
|
5352
5758
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
5353
5759
|
}
|
|
5354
|
-
async function
|
|
5760
|
+
async function fetchTableAndViewNames(params, schema) {
|
|
5355
5761
|
const rows = await runQuery7(
|
|
5356
5762
|
params,
|
|
5357
|
-
`SELECT
|
|
5358
|
-
WHERE
|
|
5359
|
-
|
|
5763
|
+
`SELECT table_name FROM information_schema.tables
|
|
5764
|
+
WHERE table_schema = ${quoteLiteral(schema)}
|
|
5765
|
+
AND table_type IN ('BASE TABLE', 'VIEW')
|
|
5766
|
+
ORDER BY table_name`
|
|
5360
5767
|
);
|
|
5361
|
-
return rows.map((r) => String(r["
|
|
5768
|
+
return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
5362
5769
|
}
|
|
5363
5770
|
var redshiftSetupFlow = {
|
|
5364
5771
|
initialState: () => ({}),
|
|
@@ -5373,9 +5780,11 @@ var redshiftSetupFlow = {
|
|
|
5373
5780
|
async fetchOptions(_state, rt) {
|
|
5374
5781
|
const rows = await runQuery7(
|
|
5375
5782
|
rt.params,
|
|
5376
|
-
`SELECT DISTINCT
|
|
5783
|
+
`SELECT DISTINCT table_schema FROM information_schema.tables
|
|
5784
|
+
WHERE table_type IN ('BASE TABLE', 'VIEW')
|
|
5785
|
+
ORDER BY table_schema`
|
|
5377
5786
|
);
|
|
5378
|
-
return rows.map((r) => String(r["
|
|
5787
|
+
return rows.map((r) => String(r["table_schema"] ?? "")).filter((name) => name && !isInternalSchema2(name)).map((value) => ({ value }));
|
|
5379
5788
|
},
|
|
5380
5789
|
applyAnswer: (state, answer) => ({ ...state, schema: answer[0] })
|
|
5381
5790
|
},
|
|
@@ -5383,17 +5792,17 @@ var redshiftSetupFlow = {
|
|
|
5383
5792
|
slug: "tables",
|
|
5384
5793
|
type: "multiSelect",
|
|
5385
5794
|
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)"
|
|
5795
|
+
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",
|
|
5796
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
5388
5797
|
},
|
|
5389
5798
|
async fetchOptions(state, rt) {
|
|
5390
5799
|
if (!state.schema) return [];
|
|
5391
|
-
const names = await
|
|
5800
|
+
const names = await fetchTableAndViewNames(rt.params, state.schema);
|
|
5392
5801
|
const tableOptions = names.map((value) => ({ value }));
|
|
5393
5802
|
return [
|
|
5394
5803
|
{
|
|
5395
5804
|
value: ALL_TABLES7,
|
|
5396
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
5805
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
5397
5806
|
},
|
|
5398
5807
|
...tableOptions
|
|
5399
5808
|
];
|
|
@@ -5409,9 +5818,21 @@ var redshiftSetupFlow = {
|
|
|
5409
5818
|
const targetTables = await resolveSetupSelection({
|
|
5410
5819
|
selected: state.tables,
|
|
5411
5820
|
allSentinel: ALL_TABLES7,
|
|
5412
|
-
fetchAll: () =>
|
|
5821
|
+
fetchAll: () => fetchTableAndViewNames(rt.params, schema),
|
|
5413
5822
|
limit: REDSHIFT_SETUP_MAX_TABLES
|
|
5414
5823
|
});
|
|
5824
|
+
const typeRows = targetTables.length > 0 ? await runQuery7(
|
|
5825
|
+
rt.params,
|
|
5826
|
+
`SELECT table_name, table_type FROM information_schema.tables
|
|
5827
|
+
WHERE table_schema = ${quoteLiteral(schema)}
|
|
5828
|
+
AND table_name IN (${targetTables.map(quoteLiteral).join(", ")})`
|
|
5829
|
+
) : [];
|
|
5830
|
+
const typeMap = new Map(
|
|
5831
|
+
typeRows.map((r) => [
|
|
5832
|
+
String(r["table_name"] ?? ""),
|
|
5833
|
+
String(r["table_type"] ?? "BASE TABLE")
|
|
5834
|
+
])
|
|
5835
|
+
);
|
|
5415
5836
|
const sections = [
|
|
5416
5837
|
"## Redshift",
|
|
5417
5838
|
"",
|
|
@@ -5419,6 +5840,7 @@ var redshiftSetupFlow = {
|
|
|
5419
5840
|
""
|
|
5420
5841
|
];
|
|
5421
5842
|
for (const table of targetTables) {
|
|
5843
|
+
const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
|
|
5422
5844
|
const cols = await runQuery7(
|
|
5423
5845
|
rt.params,
|
|
5424
5846
|
`SELECT column_name, data_type, is_nullable, column_default
|
|
@@ -5427,7 +5849,7 @@ var redshiftSetupFlow = {
|
|
|
5427
5849
|
AND table_name = ${quoteLiteral(table)}
|
|
5428
5850
|
ORDER BY ordinal_position`
|
|
5429
5851
|
);
|
|
5430
|
-
sections.push(`####
|
|
5852
|
+
sections.push(`#### ${heading}: ${table}`, "");
|
|
5431
5853
|
sections.push("| Column | Type | Nullable | Default |");
|
|
5432
5854
|
sections.push("|--------|------|----------|---------|");
|
|
5433
5855
|
for (const c of cols) {
|
|
@@ -5855,8 +6277,8 @@ var databricksSetupFlow = {
|
|
|
5855
6277
|
slug: "tables",
|
|
5856
6278
|
type: "multiSelect",
|
|
5857
6279
|
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)"
|
|
6280
|
+
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",
|
|
6281
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
5860
6282
|
},
|
|
5861
6283
|
async fetchOptions(state, rt) {
|
|
5862
6284
|
if (!state.catalog || !state.schema) return [];
|
|
@@ -5868,7 +6290,7 @@ var databricksSetupFlow = {
|
|
|
5868
6290
|
return [
|
|
5869
6291
|
{
|
|
5870
6292
|
value: ALL_TABLES8,
|
|
5871
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
6293
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
5872
6294
|
},
|
|
5873
6295
|
...tableOptions
|
|
5874
6296
|
];
|
|
@@ -7248,11 +7670,11 @@ var parameters13 = {
|
|
|
7248
7670
|
propertyId: new ParameterDefinition({
|
|
7249
7671
|
slug: "property-id",
|
|
7250
7672
|
name: "Google Analytics Property ID",
|
|
7251
|
-
description: "The Google Analytics 4 property ID (e.g., 123456789).",
|
|
7673
|
+
description: "The Google Analytics 4 property ID (e.g., 123456789). Automatically set during the setup flow.",
|
|
7252
7674
|
envVarBaseKey: "GA_PROPERTY_ID",
|
|
7253
7675
|
type: "text",
|
|
7254
7676
|
secret: false,
|
|
7255
|
-
required:
|
|
7677
|
+
required: false
|
|
7256
7678
|
})
|
|
7257
7679
|
};
|
|
7258
7680
|
|
|
@@ -7260,6 +7682,7 @@ var parameters13 = {
|
|
|
7260
7682
|
import * as crypto2 from "crypto";
|
|
7261
7683
|
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
7262
7684
|
var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta";
|
|
7685
|
+
var DATA_BASE_URL = "https://analyticsdata.googleapis.com/v1beta";
|
|
7263
7686
|
var SCOPE = "https://www.googleapis.com/auth/analytics.readonly";
|
|
7264
7687
|
function base64url(input) {
|
|
7265
7688
|
const buf = typeof input === "string" ? Buffer.from(input) : input;
|
|
@@ -7341,10 +7764,25 @@ async function adminFetch(params, path5, init) {
|
|
|
7341
7764
|
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
7342
7765
|
return fetch(url, { ...init, headers });
|
|
7343
7766
|
}
|
|
7767
|
+
async function dataFetch(params, path5, init) {
|
|
7768
|
+
const keyJsonBase64 = params[parameters13.serviceAccountKeyJsonBase64.slug];
|
|
7769
|
+
if (!keyJsonBase64) {
|
|
7770
|
+
throw new Error(
|
|
7771
|
+
"google-analytics: missing required parameter: service-account-key-json-base64"
|
|
7772
|
+
);
|
|
7773
|
+
}
|
|
7774
|
+
const serviceAccountKey = decodeServiceAccount(keyJsonBase64);
|
|
7775
|
+
const accessToken = await getAccessToken(serviceAccountKey);
|
|
7776
|
+
const url = `${DATA_BASE_URL}${path5.startsWith("/") ? "" : "/"}${path5}`;
|
|
7777
|
+
const headers = new Headers(init?.headers);
|
|
7778
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
7779
|
+
return fetch(url, { ...init, headers });
|
|
7780
|
+
}
|
|
7344
7781
|
|
|
7345
7782
|
// ../connectors/src/connectors/google-analytics/setup-flow.ts
|
|
7346
7783
|
var ALL_PROPERTIES = "__ALL_PROPERTIES__";
|
|
7347
7784
|
var GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES = 20;
|
|
7785
|
+
var METADATA_DISPLAY_LIMIT = 30;
|
|
7348
7786
|
async function listAccountSummaries(params) {
|
|
7349
7787
|
const summaries = [];
|
|
7350
7788
|
let pageToken;
|
|
@@ -7371,6 +7809,48 @@ async function getProperty(params, propertyId) {
|
|
|
7371
7809
|
if (!res.ok) return null;
|
|
7372
7810
|
return await res.json();
|
|
7373
7811
|
}
|
|
7812
|
+
async function getMetadata(params, propertyId) {
|
|
7813
|
+
try {
|
|
7814
|
+
const res = await dataFetch(
|
|
7815
|
+
params,
|
|
7816
|
+
`/properties/${propertyId}/metadata`
|
|
7817
|
+
);
|
|
7818
|
+
if (!res.ok) return { dimensions: [], metrics: [] };
|
|
7819
|
+
const data = await res.json();
|
|
7820
|
+
return {
|
|
7821
|
+
dimensions: data.dimensions ?? [],
|
|
7822
|
+
metrics: data.metrics ?? []
|
|
7823
|
+
};
|
|
7824
|
+
} catch {
|
|
7825
|
+
return { dimensions: [], metrics: [] };
|
|
7826
|
+
}
|
|
7827
|
+
}
|
|
7828
|
+
function appendMetadataSection(sections, dimensions, metrics) {
|
|
7829
|
+
if (dimensions.length > 0) {
|
|
7830
|
+
sections.push(`#### Dimensions (${dimensions.length})`, "");
|
|
7831
|
+
for (const d of dimensions.slice(0, METADATA_DISPLAY_LIMIT)) {
|
|
7832
|
+
sections.push(`- ${d.apiName ?? d.uiName ?? "(unknown)"}`);
|
|
7833
|
+
}
|
|
7834
|
+
if (dimensions.length > METADATA_DISPLAY_LIMIT) {
|
|
7835
|
+
sections.push(
|
|
7836
|
+
`- \u2026and ${dimensions.length - METADATA_DISPLAY_LIMIT} more`
|
|
7837
|
+
);
|
|
7838
|
+
}
|
|
7839
|
+
sections.push("");
|
|
7840
|
+
}
|
|
7841
|
+
if (metrics.length > 0) {
|
|
7842
|
+
sections.push(`#### Metrics (${metrics.length})`, "");
|
|
7843
|
+
for (const m of metrics.slice(0, METADATA_DISPLAY_LIMIT)) {
|
|
7844
|
+
sections.push(`- ${m.apiName ?? m.uiName ?? "(unknown)"}`);
|
|
7845
|
+
}
|
|
7846
|
+
if (metrics.length > METADATA_DISPLAY_LIMIT) {
|
|
7847
|
+
sections.push(
|
|
7848
|
+
`- \u2026and ${metrics.length - METADATA_DISPLAY_LIMIT} more`
|
|
7849
|
+
);
|
|
7850
|
+
}
|
|
7851
|
+
sections.push("");
|
|
7852
|
+
}
|
|
7853
|
+
}
|
|
7374
7854
|
var googleAnalyticsSetupFlow = {
|
|
7375
7855
|
initialState: () => ({}),
|
|
7376
7856
|
steps: [
|
|
@@ -7382,15 +7862,19 @@ var googleAnalyticsSetupFlow = {
|
|
|
7382
7862
|
en: "Select a Google Analytics account"
|
|
7383
7863
|
},
|
|
7384
7864
|
async fetchOptions(_state, rt) {
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7865
|
+
try {
|
|
7866
|
+
const summaries = await listAccountSummaries(rt.params);
|
|
7867
|
+
return summaries.map((s) => {
|
|
7868
|
+
const accountResource = s.account ?? s.name ?? "";
|
|
7869
|
+
if (!accountResource) return null;
|
|
7870
|
+
return {
|
|
7871
|
+
value: accountResource,
|
|
7872
|
+
label: s.displayName ?? accountResource
|
|
7873
|
+
};
|
|
7874
|
+
}).filter((v) => v != null);
|
|
7875
|
+
} catch {
|
|
7876
|
+
return [];
|
|
7877
|
+
}
|
|
7394
7878
|
},
|
|
7395
7879
|
applyAnswer: (state, answer) => ({ ...state, account: answer[0] })
|
|
7396
7880
|
},
|
|
@@ -7403,68 +7887,134 @@ var googleAnalyticsSetupFlow = {
|
|
|
7403
7887
|
},
|
|
7404
7888
|
async fetchOptions(state, rt) {
|
|
7405
7889
|
if (!state.account) return [];
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
const
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7890
|
+
try {
|
|
7891
|
+
const summaries = await listAccountSummaries(rt.params);
|
|
7892
|
+
const account = summaries.find(
|
|
7893
|
+
(s) => (s.account ?? s.name) === state.account
|
|
7894
|
+
);
|
|
7895
|
+
const props = (account?.propertySummaries ?? []).map((p) => {
|
|
7896
|
+
const id = propertyIdFromResource(p.property);
|
|
7897
|
+
if (!id) return null;
|
|
7898
|
+
return {
|
|
7899
|
+
value: id,
|
|
7900
|
+
label: p.displayName ? `${p.displayName} (${id})` : id
|
|
7901
|
+
};
|
|
7902
|
+
}).filter((v) => v != null);
|
|
7903
|
+
if (props.length === 0) return [];
|
|
7904
|
+
return [
|
|
7905
|
+
{
|
|
7906
|
+
value: ALL_PROPERTIES,
|
|
7907
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
|
|
7908
|
+
},
|
|
7909
|
+
...props
|
|
7910
|
+
];
|
|
7911
|
+
} catch {
|
|
7912
|
+
return [];
|
|
7913
|
+
}
|
|
7914
|
+
},
|
|
7915
|
+
applyAnswer: (state, answer) => ({ ...state, properties: answer }),
|
|
7916
|
+
toParameterUpdates: (state) => {
|
|
7917
|
+
const first = state.properties?.find((v) => v !== ALL_PROPERTIES);
|
|
7918
|
+
return first ? [{ slug: parameters13.propertyId.slug, value: first }] : [];
|
|
7919
|
+
}
|
|
7920
|
+
},
|
|
7921
|
+
{
|
|
7922
|
+
slug: "manualPropertyId",
|
|
7923
|
+
type: "select",
|
|
7924
|
+
allowFreeText: true,
|
|
7925
|
+
question: {
|
|
7926
|
+
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",
|
|
7927
|
+
en: "Enter your GA4 Property ID (e.g., 123456789). Found in GA4 Admin > Property Settings."
|
|
7928
|
+
},
|
|
7929
|
+
async fetchOptions(state, rt) {
|
|
7930
|
+
if (state.properties?.length) return [];
|
|
7931
|
+
const existing = rt.params[parameters13.propertyId.slug];
|
|
7932
|
+
return existing ? [{ value: existing, label: existing }] : [
|
|
7420
7933
|
{
|
|
7421
|
-
value:
|
|
7422
|
-
label: rt.language === "ja" ? "\
|
|
7423
|
-
}
|
|
7424
|
-
...props
|
|
7934
|
+
value: "example",
|
|
7935
|
+
label: rt.language === "ja" ? "\u4F8B: 123456789" : "Example: 123456789"
|
|
7936
|
+
}
|
|
7425
7937
|
];
|
|
7426
7938
|
},
|
|
7427
|
-
applyAnswer: (state, answer) => ({
|
|
7939
|
+
applyAnswer: (state, answer) => ({
|
|
7940
|
+
...state,
|
|
7941
|
+
manualPropertyId: answer[0]
|
|
7942
|
+
}),
|
|
7943
|
+
toParameterUpdates: (state) => state.manualPropertyId ? [
|
|
7944
|
+
{
|
|
7945
|
+
slug: parameters13.propertyId.slug,
|
|
7946
|
+
value: state.manualPropertyId
|
|
7947
|
+
}
|
|
7948
|
+
] : []
|
|
7428
7949
|
}
|
|
7429
7950
|
],
|
|
7430
7951
|
async finalize(state, rt) {
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
`### Account: ${accountLabel2}`,
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7952
|
+
const sections = ["## Google Analytics", ""];
|
|
7953
|
+
if (state.account && state.properties) {
|
|
7954
|
+
let summaries = [];
|
|
7955
|
+
try {
|
|
7956
|
+
summaries = await listAccountSummaries(rt.params);
|
|
7957
|
+
} catch {
|
|
7958
|
+
}
|
|
7959
|
+
const account = summaries.find(
|
|
7960
|
+
(s) => (s.account ?? s.name) === state.account
|
|
7961
|
+
);
|
|
7962
|
+
const accountLabel2 = account?.displayName ?? state.account.replace(/^accounts\//, "");
|
|
7963
|
+
const targetPropertyIds = await resolveSetupSelection({
|
|
7964
|
+
selected: state.properties,
|
|
7965
|
+
allSentinel: ALL_PROPERTIES,
|
|
7966
|
+
fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
|
|
7967
|
+
limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
|
|
7968
|
+
});
|
|
7969
|
+
sections.push(`### Account: ${accountLabel2}`, "");
|
|
7970
|
+
if (targetPropertyIds.length === 0) {
|
|
7971
|
+
sections.push("_No properties selected._", "");
|
|
7972
|
+
return sections.join("\n");
|
|
7973
|
+
}
|
|
7974
|
+
sections.push(
|
|
7975
|
+
"| Property ID | Display Name | Time Zone | Currency | Industry |"
|
|
7976
|
+
);
|
|
7977
|
+
sections.push(
|
|
7978
|
+
"|-------------|--------------|-----------|----------|----------|"
|
|
7979
|
+
);
|
|
7980
|
+
for (const pid of targetPropertyIds) {
|
|
7981
|
+
const prop = await getProperty(rt.params, pid).catch(() => null);
|
|
7982
|
+
const displayName3 = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
|
|
7983
|
+
const timeZone = prop?.timeZone ?? "-";
|
|
7984
|
+
const currency = prop?.currencyCode ?? "-";
|
|
7985
|
+
const industry = (prop?.industryCategory ?? "-").replace(
|
|
7986
|
+
/\|/g,
|
|
7987
|
+
"\\|"
|
|
7988
|
+
);
|
|
7989
|
+
sections.push(
|
|
7990
|
+
`| ${pid} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
|
|
7991
|
+
);
|
|
7992
|
+
}
|
|
7993
|
+
sections.push("");
|
|
7994
|
+
const firstPropertyId = targetPropertyIds[0];
|
|
7995
|
+
if (firstPropertyId) {
|
|
7996
|
+
const { dimensions, metrics } = await getMetadata(
|
|
7997
|
+
rt.params,
|
|
7998
|
+
firstPropertyId
|
|
7999
|
+
);
|
|
8000
|
+
appendMetadataSection(sections, dimensions, metrics);
|
|
8001
|
+
}
|
|
7453
8002
|
return sections.join("\n");
|
|
7454
8003
|
}
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
const
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
const currency = prop?.currencyCode ?? "-";
|
|
7462
|
-
const industry = (prop?.industryCategory ?? "-").replace(/\|/g, "\\|");
|
|
7463
|
-
sections.push(
|
|
7464
|
-
`| ${propertyId} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
|
|
8004
|
+
const propertyId = state.manualPropertyId ?? rt.params[parameters13.propertyId.slug];
|
|
8005
|
+
if (propertyId) {
|
|
8006
|
+
sections.push(`### Property: ${propertyId}`, "");
|
|
8007
|
+
const { dimensions, metrics } = await getMetadata(
|
|
8008
|
+
rt.params,
|
|
8009
|
+
propertyId
|
|
7465
8010
|
);
|
|
8011
|
+
appendMetadataSection(sections, dimensions, metrics);
|
|
8012
|
+
return sections.join("\n");
|
|
7466
8013
|
}
|
|
7467
|
-
sections.push(
|
|
8014
|
+
sections.push(
|
|
8015
|
+
"_Could not list GA4 accounts. Please enable the Google Analytics Admin API in your GCP project, or set the Property ID parameter manually._",
|
|
8016
|
+
""
|
|
8017
|
+
);
|
|
7468
8018
|
return sections.join("\n");
|
|
7469
8019
|
}
|
|
7470
8020
|
};
|
|
@@ -7712,13 +8262,20 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
|
|
|
7712
8262
|
error: "google-analytics: missing service account key"
|
|
7713
8263
|
};
|
|
7714
8264
|
}
|
|
8265
|
+
const propertyId = params[parameters13.propertyId.slug];
|
|
8266
|
+
if (!propertyId) {
|
|
8267
|
+
return { success: true };
|
|
8268
|
+
}
|
|
7715
8269
|
try {
|
|
7716
|
-
const res = await
|
|
8270
|
+
const res = await dataFetch(
|
|
8271
|
+
params,
|
|
8272
|
+
`/properties/${propertyId}/metadata`
|
|
8273
|
+
);
|
|
7717
8274
|
if (!res.ok) {
|
|
7718
8275
|
const body = await res.text().catch(() => res.statusText);
|
|
7719
8276
|
return {
|
|
7720
8277
|
success: false,
|
|
7721
|
-
error: `
|
|
8278
|
+
error: `Google Analytics API failed: HTTP ${res.status} ${body}`
|
|
7722
8279
|
};
|
|
7723
8280
|
}
|
|
7724
8281
|
return { success: true };
|
|
@@ -19358,7 +19915,7 @@ function escapeIdentifier(name) {
|
|
|
19358
19915
|
function quoteLiteral2(value) {
|
|
19359
19916
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
19360
19917
|
}
|
|
19361
|
-
async function
|
|
19918
|
+
async function fetchTableNames3(params, database) {
|
|
19362
19919
|
const rows = await runQuery9(
|
|
19363
19920
|
params,
|
|
19364
19921
|
`SELECT name FROM system.tables
|
|
@@ -19387,17 +19944,17 @@ var clickhouseSetupFlow = {
|
|
|
19387
19944
|
slug: "tables",
|
|
19388
19945
|
type: "multiSelect",
|
|
19389
19946
|
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)"
|
|
19947
|
+
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",
|
|
19948
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
19392
19949
|
},
|
|
19393
19950
|
async fetchOptions(state, rt) {
|
|
19394
19951
|
if (!state.database) return [];
|
|
19395
|
-
const names = await
|
|
19952
|
+
const names = await fetchTableNames3(rt.params, state.database);
|
|
19396
19953
|
const tableOptions = names.map((value) => ({ value }));
|
|
19397
19954
|
return [
|
|
19398
19955
|
{
|
|
19399
19956
|
value: ALL_TABLES11,
|
|
19400
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
19957
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
19401
19958
|
},
|
|
19402
19959
|
...tableOptions
|
|
19403
19960
|
];
|
|
@@ -19413,7 +19970,7 @@ var clickhouseSetupFlow = {
|
|
|
19413
19970
|
const targetTables = await resolveSetupSelection({
|
|
19414
19971
|
selected: state.tables,
|
|
19415
19972
|
allSentinel: ALL_TABLES11,
|
|
19416
|
-
fetchAll: () =>
|
|
19973
|
+
fetchAll: () => fetchTableNames3(rt.params, database),
|
|
19417
19974
|
limit: CLICKHOUSE_SETUP_MAX_TABLES
|
|
19418
19975
|
});
|
|
19419
19976
|
const sections = [
|
|
@@ -24012,7 +24569,7 @@ export default async function handler(c: Context) {
|
|
|
24012
24569
|
const region = params[parameters50.region.slug];
|
|
24013
24570
|
const baseUrl = region === "eu" ? "https://api-eu.customer.io" : "https://api.customer.io";
|
|
24014
24571
|
try {
|
|
24015
|
-
const res = await fetch(`${baseUrl}/v1/
|
|
24572
|
+
const res = await fetch(`${baseUrl}/v1/segments`, {
|
|
24016
24573
|
method: "GET",
|
|
24017
24574
|
headers: {
|
|
24018
24575
|
Authorization: `Bearer ${appApiKey}`,
|
|
@@ -29568,7 +30125,7 @@ function apiFetch27(params, path5, init) {
|
|
|
29568
30125
|
// ../connectors/src/connectors/gamma/setup-flow.ts
|
|
29569
30126
|
var ALL_FOLDERS = "__ALL_FOLDERS__";
|
|
29570
30127
|
var GAMMA_SETUP_MAX_FOLDERS = 20;
|
|
29571
|
-
var FOLDERS_PAGE_LIMIT =
|
|
30128
|
+
var FOLDERS_PAGE_LIMIT = 50;
|
|
29572
30129
|
async function listAllFolders(params) {
|
|
29573
30130
|
const results = [];
|
|
29574
30131
|
let after;
|
|
@@ -29589,7 +30146,7 @@ async function listAllFolders(params) {
|
|
|
29589
30146
|
return results;
|
|
29590
30147
|
}
|
|
29591
30148
|
async function listThemes(params) {
|
|
29592
|
-
const res = await apiFetch27(params, "/themes?limit=
|
|
30149
|
+
const res = await apiFetch27(params, "/themes?limit=50");
|
|
29593
30150
|
if (!res.ok) {
|
|
29594
30151
|
return [];
|
|
29595
30152
|
}
|
|
@@ -33426,7 +33983,8 @@ var semrushOnboarding = new ConnectorOnboarding({
|
|
|
33426
33983
|
});
|
|
33427
33984
|
|
|
33428
33985
|
// ../connectors/src/connectors/semrush/utils.ts
|
|
33429
|
-
var
|
|
33986
|
+
var BASE_URL59 = "https://api.semrush.com";
|
|
33987
|
+
var PROJECTS_BASE_URL = `${BASE_URL59}/management/v1`;
|
|
33430
33988
|
function projectsApiFetch(params, path5, init) {
|
|
33431
33989
|
const apiKey = params[parameters68.apiKey.slug];
|
|
33432
33990
|
if (!apiKey) {
|
|
@@ -33443,10 +34001,103 @@ function projectsApiFetch(params, path5, init) {
|
|
|
33443
34001
|
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
33444
34002
|
return fetch(url.toString(), { ...init, headers });
|
|
33445
34003
|
}
|
|
34004
|
+
async function reportFetch(params, query) {
|
|
34005
|
+
const apiKey = params[parameters68.apiKey.slug];
|
|
34006
|
+
if (!apiKey) {
|
|
34007
|
+
throw new Error(
|
|
34008
|
+
`semrush: missing required parameter: ${parameters68.apiKey.slug}`
|
|
34009
|
+
);
|
|
34010
|
+
}
|
|
34011
|
+
const url = new URL(`${BASE_URL59}/`);
|
|
34012
|
+
for (const [k, v] of Object.entries(query)) {
|
|
34013
|
+
url.searchParams.set(k, v);
|
|
34014
|
+
}
|
|
34015
|
+
url.searchParams.set("key", apiKey);
|
|
34016
|
+
const res = await fetch(url.toString());
|
|
34017
|
+
const text = await res.text();
|
|
34018
|
+
if (text.startsWith("ERROR ")) throw new Error(text.trim());
|
|
34019
|
+
return parseSemicolonCsv(text);
|
|
34020
|
+
}
|
|
34021
|
+
async function backlinksFetch(params, query) {
|
|
34022
|
+
const apiKey = params[parameters68.apiKey.slug];
|
|
34023
|
+
if (!apiKey) {
|
|
34024
|
+
throw new Error(
|
|
34025
|
+
`semrush: missing required parameter: ${parameters68.apiKey.slug}`
|
|
34026
|
+
);
|
|
34027
|
+
}
|
|
34028
|
+
const url = new URL(`${BASE_URL59}/analytics/v1/`);
|
|
34029
|
+
for (const [k, v] of Object.entries(query)) {
|
|
34030
|
+
url.searchParams.set(k, v);
|
|
34031
|
+
}
|
|
34032
|
+
url.searchParams.set("key", apiKey);
|
|
34033
|
+
const res = await fetch(url.toString());
|
|
34034
|
+
const text = await res.text();
|
|
34035
|
+
if (text.startsWith("ERROR ")) throw new Error(text.trim());
|
|
34036
|
+
return parseSemicolonCsv(text);
|
|
34037
|
+
}
|
|
34038
|
+
function parseSemicolonCsv(raw) {
|
|
34039
|
+
const lines = raw.trim().split("\n").filter(Boolean);
|
|
34040
|
+
if (lines.length === 0) return { columns: [], rows: [] };
|
|
34041
|
+
const columns = lines[0].split(";");
|
|
34042
|
+
const rows = lines.slice(1).map((line) => {
|
|
34043
|
+
const values = line.split(";");
|
|
34044
|
+
const row = {};
|
|
34045
|
+
for (let i = 0; i < columns.length; i++) {
|
|
34046
|
+
row[columns[i]] = values[i] ?? "";
|
|
34047
|
+
}
|
|
34048
|
+
return row;
|
|
34049
|
+
});
|
|
34050
|
+
return { columns, rows };
|
|
34051
|
+
}
|
|
33446
34052
|
|
|
33447
34053
|
// ../connectors/src/connectors/semrush/setup-flow.ts
|
|
33448
34054
|
var ALL_PROJECTS6 = "__ALL_PROJECTS__";
|
|
33449
34055
|
var SEMRUSH_SETUP_MAX_PROJECTS = 10;
|
|
34056
|
+
var SEMRUSH_DATABASES = [
|
|
34057
|
+
{ value: "us", label: "United States" },
|
|
34058
|
+
{ value: "uk", label: "United Kingdom" },
|
|
34059
|
+
{ value: "ca", label: "Canada" },
|
|
34060
|
+
{ value: "au", label: "Australia" },
|
|
34061
|
+
{ value: "de", label: "Germany" },
|
|
34062
|
+
{ value: "fr", label: "France" },
|
|
34063
|
+
{ value: "es", label: "Spain" },
|
|
34064
|
+
{ value: "it", label: "Italy" },
|
|
34065
|
+
{ value: "br", label: "Brazil" },
|
|
34066
|
+
{ value: "jp", label: "Japan" },
|
|
34067
|
+
{ value: "in", label: "India" },
|
|
34068
|
+
{ value: "ru", label: "Russia" },
|
|
34069
|
+
{ value: "nl", label: "Netherlands" },
|
|
34070
|
+
{ value: "se", label: "Sweden" },
|
|
34071
|
+
{ value: "mx", label: "Mexico" },
|
|
34072
|
+
{ value: "kr", label: "South Korea" },
|
|
34073
|
+
{ value: "sg", label: "Singapore" },
|
|
34074
|
+
{ value: "hk", label: "Hong Kong" },
|
|
34075
|
+
{ value: "tw", label: "Taiwan" }
|
|
34076
|
+
];
|
|
34077
|
+
var REPORT_TYPE_LABELS = {
|
|
34078
|
+
domain_overview: {
|
|
34079
|
+
en: "Domain Overview (rank, traffic, keyword count)",
|
|
34080
|
+
ja: "Domain Overview (\u30E9\u30F3\u30AF\u30FB\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u30FB\u30AD\u30FC\u30EF\u30FC\u30C9\u6570)"
|
|
34081
|
+
},
|
|
34082
|
+
organic_search: {
|
|
34083
|
+
en: "Organic Search (top organic keywords)",
|
|
34084
|
+
ja: "Organic Search (\u4E0A\u4F4D\u30AA\u30FC\u30AC\u30CB\u30C3\u30AF\u30AD\u30FC\u30EF\u30FC\u30C9)"
|
|
34085
|
+
},
|
|
34086
|
+
paid_search: {
|
|
34087
|
+
en: "Paid Search (top paid keywords)",
|
|
34088
|
+
ja: "Paid Search (\u4E0A\u4F4D\u6709\u6599\u30AD\u30FC\u30EF\u30FC\u30C9)"
|
|
34089
|
+
},
|
|
34090
|
+
backlinks: {
|
|
34091
|
+
en: "Backlinks (referring domains, backlink count)",
|
|
34092
|
+
ja: "Backlinks (\u53C2\u7167\u30C9\u30E1\u30A4\u30F3\u30FB\u88AB\u30EA\u30F3\u30AF\u6570)"
|
|
34093
|
+
}
|
|
34094
|
+
};
|
|
34095
|
+
var REPORT_TYPE_VALUES = [
|
|
34096
|
+
"domain_overview",
|
|
34097
|
+
"organic_search",
|
|
34098
|
+
"paid_search",
|
|
34099
|
+
"backlinks"
|
|
34100
|
+
];
|
|
33450
34101
|
function projectId(p) {
|
|
33451
34102
|
const raw = p.project_id ?? p.id;
|
|
33452
34103
|
return raw == null ? "" : String(raw);
|
|
@@ -33455,7 +34106,7 @@ function projectName(p) {
|
|
|
33455
34106
|
return p.project_name ?? p.name ?? p.domain ?? p.url ?? projectId(p);
|
|
33456
34107
|
}
|
|
33457
34108
|
function projectDomain(p) {
|
|
33458
|
-
return p.domain ?? p.url ?? "";
|
|
34109
|
+
return p.domain ?? p.domain_unicode ?? p.url ?? "";
|
|
33459
34110
|
}
|
|
33460
34111
|
function projectCreatedAt(p) {
|
|
33461
34112
|
return p.created_at ?? p.date_created ?? "";
|
|
@@ -33463,13 +34114,19 @@ function projectCreatedAt(p) {
|
|
|
33463
34114
|
async function fetchProjects(params) {
|
|
33464
34115
|
let res;
|
|
33465
34116
|
try {
|
|
33466
|
-
res = await projectsApiFetch(params, "/projects
|
|
34117
|
+
res = await projectsApiFetch(params, "/projects");
|
|
33467
34118
|
} catch (err) {
|
|
33468
|
-
return {
|
|
34119
|
+
return {
|
|
34120
|
+
ok: false,
|
|
34121
|
+
error: err instanceof Error ? err.message : String(err)
|
|
34122
|
+
};
|
|
33469
34123
|
}
|
|
33470
34124
|
if (!res.ok) {
|
|
33471
34125
|
const body2 = await res.text().catch(() => res.statusText);
|
|
33472
|
-
return {
|
|
34126
|
+
return {
|
|
34127
|
+
ok: false,
|
|
34128
|
+
error: `HTTP ${res.status} ${body2 || res.statusText}`
|
|
34129
|
+
};
|
|
33473
34130
|
}
|
|
33474
34131
|
let body;
|
|
33475
34132
|
try {
|
|
@@ -33483,9 +34140,171 @@ async function fetchProjects(params) {
|
|
|
33483
34140
|
const projects = Array.isArray(body) ? body : Array.isArray(body?.projects) ? body.projects : Array.isArray(body?.data) ? body.data : [];
|
|
33484
34141
|
return { ok: true, projects };
|
|
33485
34142
|
}
|
|
34143
|
+
function formatNumber(n) {
|
|
34144
|
+
return n.toLocaleString("en-US");
|
|
34145
|
+
}
|
|
34146
|
+
async function fetchDomainOverview(params, domain, database) {
|
|
34147
|
+
const sections = [];
|
|
34148
|
+
try {
|
|
34149
|
+
const report = await reportFetch(params, {
|
|
34150
|
+
type: "domain_ranks",
|
|
34151
|
+
domain,
|
|
34152
|
+
database
|
|
34153
|
+
});
|
|
34154
|
+
if (report.rows.length === 0) {
|
|
34155
|
+
sections.push("_No data found for this domain._", "");
|
|
34156
|
+
return sections;
|
|
34157
|
+
}
|
|
34158
|
+
const row = report.rows[0];
|
|
34159
|
+
sections.push("| Metric | Value |");
|
|
34160
|
+
sections.push("|--------|-------|");
|
|
34161
|
+
sections.push(
|
|
34162
|
+
`| Rank | ${row["Rank"] ?? "-"} |`,
|
|
34163
|
+
`| Organic Keywords | ${formatNumber(Number(row["Organic Keywords"]) || 0)} |`,
|
|
34164
|
+
`| Organic Traffic | ${formatNumber(Number(row["Organic Traffic"]) || 0)} |`,
|
|
34165
|
+
`| Organic Cost | $${formatNumber(Number(row["Organic Cost"]) || 0)} |`,
|
|
34166
|
+
`| Adwords Keywords | ${formatNumber(Number(row["Adwords Keywords"]) || 0)} |`,
|
|
34167
|
+
`| Adwords Traffic | ${formatNumber(Number(row["Adwords Traffic"]) || 0)} |`,
|
|
34168
|
+
`| Adwords Cost | $${formatNumber(Number(row["Adwords Cost"]) || 0)} |`
|
|
34169
|
+
);
|
|
34170
|
+
sections.push("");
|
|
34171
|
+
} catch (err) {
|
|
34172
|
+
sections.push(
|
|
34173
|
+
`_Error: ${err instanceof Error ? err.message : String(err)}_`,
|
|
34174
|
+
""
|
|
34175
|
+
);
|
|
34176
|
+
}
|
|
34177
|
+
return sections;
|
|
34178
|
+
}
|
|
34179
|
+
async function fetchOrganicSearch(params, domain, database) {
|
|
34180
|
+
return fetchKeywordReport(params, "domain_organic", domain, database);
|
|
34181
|
+
}
|
|
34182
|
+
async function fetchPaidSearch(params, domain, database) {
|
|
34183
|
+
return fetchKeywordReport(params, "domain_adwords", domain, database);
|
|
34184
|
+
}
|
|
34185
|
+
async function fetchKeywordReport(params, type, domain, database) {
|
|
34186
|
+
const sections = [];
|
|
34187
|
+
try {
|
|
34188
|
+
const report = await reportFetch(params, {
|
|
34189
|
+
type,
|
|
34190
|
+
domain,
|
|
34191
|
+
database,
|
|
34192
|
+
display_limit: "5"
|
|
34193
|
+
});
|
|
34194
|
+
if (report.rows.length === 0) {
|
|
34195
|
+
sections.push("_No data found._", "");
|
|
34196
|
+
return sections;
|
|
34197
|
+
}
|
|
34198
|
+
sections.push(...renderCsvTable(report, 5));
|
|
34199
|
+
sections.push("");
|
|
34200
|
+
} catch (err) {
|
|
34201
|
+
sections.push(
|
|
34202
|
+
`_Error: ${err instanceof Error ? err.message : String(err)}_`,
|
|
34203
|
+
""
|
|
34204
|
+
);
|
|
34205
|
+
}
|
|
34206
|
+
return sections;
|
|
34207
|
+
}
|
|
34208
|
+
async function fetchBacklinks(params, domain) {
|
|
34209
|
+
const sections = [];
|
|
34210
|
+
try {
|
|
34211
|
+
const report = await backlinksFetch(params, {
|
|
34212
|
+
type: "backlinks_overview",
|
|
34213
|
+
target: domain,
|
|
34214
|
+
target_type: "root_domain"
|
|
34215
|
+
});
|
|
34216
|
+
if (report.rows.length === 0) {
|
|
34217
|
+
sections.push("_No backlink data found._", "");
|
|
34218
|
+
return sections;
|
|
34219
|
+
}
|
|
34220
|
+
const row = report.rows[0];
|
|
34221
|
+
sections.push("| Metric | Value |");
|
|
34222
|
+
sections.push("|--------|-------|");
|
|
34223
|
+
for (const col of report.columns) {
|
|
34224
|
+
sections.push(`| ${col} | ${formatNumber(Number(row[col]) || 0)} |`);
|
|
34225
|
+
}
|
|
34226
|
+
sections.push("");
|
|
34227
|
+
} catch (err) {
|
|
34228
|
+
sections.push(
|
|
34229
|
+
`_Error: ${err instanceof Error ? err.message : String(err)}_`,
|
|
34230
|
+
""
|
|
34231
|
+
);
|
|
34232
|
+
}
|
|
34233
|
+
return sections;
|
|
34234
|
+
}
|
|
34235
|
+
function renderCsvTable(report, maxRows) {
|
|
34236
|
+
const cols = report.columns;
|
|
34237
|
+
const rows = report.rows.slice(0, maxRows);
|
|
34238
|
+
const lines = [];
|
|
34239
|
+
lines.push(`| ${cols.join(" | ")} |`);
|
|
34240
|
+
lines.push(`|${cols.map(() => "---").join("|")}|`);
|
|
34241
|
+
for (const row of rows) {
|
|
34242
|
+
const cells = cols.map((c) => (row[c] ?? "").replace(/\|/g, "\\|"));
|
|
34243
|
+
lines.push(`| ${cells.join(" | ")} |`);
|
|
34244
|
+
}
|
|
34245
|
+
return lines;
|
|
34246
|
+
}
|
|
33486
34247
|
var semrushSetupFlow = {
|
|
33487
34248
|
initialState: () => ({}),
|
|
33488
34249
|
steps: [
|
|
34250
|
+
{
|
|
34251
|
+
slug: "domain",
|
|
34252
|
+
type: "select",
|
|
34253
|
+
allowFreeText: true,
|
|
34254
|
+
question: {
|
|
34255
|
+
ja: "\u5206\u6790\u5BFE\u8C61\u306E\u30C9\u30E1\u30A4\u30F3\u3092\u9078\u629E\u307E\u305F\u306F\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
34256
|
+
en: "Select or enter the domain to analyze"
|
|
34257
|
+
},
|
|
34258
|
+
async fetchOptions(_state, rt) {
|
|
34259
|
+
const result = await fetchProjects(rt.params);
|
|
34260
|
+
if (!result.ok || result.projects.length === 0) return [];
|
|
34261
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34262
|
+
const options = [];
|
|
34263
|
+
for (const p of result.projects) {
|
|
34264
|
+
const d = projectDomain(p);
|
|
34265
|
+
if (d && !seen.has(d)) {
|
|
34266
|
+
seen.add(d);
|
|
34267
|
+
options.push({
|
|
34268
|
+
value: d,
|
|
34269
|
+
label: `${d} (${projectName(p)})`
|
|
34270
|
+
});
|
|
34271
|
+
}
|
|
34272
|
+
}
|
|
34273
|
+
return options;
|
|
34274
|
+
},
|
|
34275
|
+
applyAnswer: (state, answer) => ({ ...state, domain: answer[0] })
|
|
34276
|
+
},
|
|
34277
|
+
{
|
|
34278
|
+
slug: "database",
|
|
34279
|
+
type: "select",
|
|
34280
|
+
allowFreeText: false,
|
|
34281
|
+
question: {
|
|
34282
|
+
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",
|
|
34283
|
+
en: "Select the region (primary market for the target domain)"
|
|
34284
|
+
},
|
|
34285
|
+
async fetchOptions() {
|
|
34286
|
+
return SEMRUSH_DATABASES.map((db) => ({
|
|
34287
|
+
value: db.value,
|
|
34288
|
+
label: `${db.label} (${db.value})`
|
|
34289
|
+
}));
|
|
34290
|
+
},
|
|
34291
|
+
applyAnswer: (state, answer) => ({ ...state, database: answer[0] })
|
|
34292
|
+
},
|
|
34293
|
+
{
|
|
34294
|
+
slug: "reportTypes",
|
|
34295
|
+
type: "multiSelect",
|
|
34296
|
+
question: {
|
|
34297
|
+
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",
|
|
34298
|
+
en: "Select report types to explore (multi-select allowed)"
|
|
34299
|
+
},
|
|
34300
|
+
async fetchOptions(_state, rt) {
|
|
34301
|
+
return REPORT_TYPE_VALUES.map((value) => ({
|
|
34302
|
+
value,
|
|
34303
|
+
label: REPORT_TYPE_LABELS[value][rt.language]
|
|
34304
|
+
}));
|
|
34305
|
+
},
|
|
34306
|
+
applyAnswer: (state, answer) => ({ ...state, reportTypes: answer })
|
|
34307
|
+
},
|
|
33489
34308
|
{
|
|
33490
34309
|
slug: "projects",
|
|
33491
34310
|
type: "multiSelect",
|
|
@@ -33502,7 +34321,9 @@ var semrushSetupFlow = {
|
|
|
33502
34321
|
const id = projectId(p);
|
|
33503
34322
|
if (!id) return null;
|
|
33504
34323
|
return { value: id, label: projectName(p) };
|
|
33505
|
-
}).filter(
|
|
34324
|
+
}).filter(
|
|
34325
|
+
(opt) => opt !== null
|
|
34326
|
+
);
|
|
33506
34327
|
if (options.length === 0) return [];
|
|
33507
34328
|
return [
|
|
33508
34329
|
{
|
|
@@ -33516,49 +34337,80 @@ var semrushSetupFlow = {
|
|
|
33516
34337
|
}
|
|
33517
34338
|
],
|
|
33518
34339
|
async finalize(state, rt) {
|
|
33519
|
-
|
|
33520
|
-
|
|
34340
|
+
if (!state.domain || !state.database || !state.reportTypes) {
|
|
34341
|
+
throw new Error("Semrush setup: incomplete state on finalize");
|
|
34342
|
+
}
|
|
34343
|
+
const domain = state.domain;
|
|
34344
|
+
const database = state.database;
|
|
34345
|
+
const selected = state.reportTypes.filter(
|
|
34346
|
+
(r) => REPORT_TYPE_VALUES.includes(r)
|
|
34347
|
+
);
|
|
34348
|
+
const sections = [
|
|
34349
|
+
"## Semrush",
|
|
34350
|
+
"",
|
|
34351
|
+
`**Domain:** ${domain}`,
|
|
34352
|
+
`**Region:** ${database}`,
|
|
34353
|
+
""
|
|
34354
|
+
];
|
|
34355
|
+
for (const reportType of selected) {
|
|
33521
34356
|
sections.push(
|
|
33522
|
-
|
|
34357
|
+
`### ${REPORT_TYPE_LABELS[reportType].en}`,
|
|
33523
34358
|
""
|
|
33524
34359
|
);
|
|
33525
|
-
|
|
33526
|
-
|
|
33527
|
-
|
|
33528
|
-
|
|
33529
|
-
|
|
33530
|
-
|
|
33531
|
-
|
|
33532
|
-
|
|
33533
|
-
|
|
33534
|
-
|
|
33535
|
-
|
|
33536
|
-
|
|
33537
|
-
|
|
33538
|
-
|
|
33539
|
-
|
|
33540
|
-
|
|
33541
|
-
|
|
33542
|
-
|
|
33543
|
-
|
|
33544
|
-
|
|
33545
|
-
sections.push("_No projects selected._", "");
|
|
33546
|
-
return sections.join("\n");
|
|
34360
|
+
switch (reportType) {
|
|
34361
|
+
case "domain_overview":
|
|
34362
|
+
sections.push(
|
|
34363
|
+
...await fetchDomainOverview(rt.params, domain, database)
|
|
34364
|
+
);
|
|
34365
|
+
break;
|
|
34366
|
+
case "organic_search":
|
|
34367
|
+
sections.push(
|
|
34368
|
+
...await fetchOrganicSearch(rt.params, domain, database)
|
|
34369
|
+
);
|
|
34370
|
+
break;
|
|
34371
|
+
case "paid_search":
|
|
34372
|
+
sections.push(
|
|
34373
|
+
...await fetchPaidSearch(rt.params, domain, database)
|
|
34374
|
+
);
|
|
34375
|
+
break;
|
|
34376
|
+
case "backlinks":
|
|
34377
|
+
sections.push(...await fetchBacklinks(rt.params, domain));
|
|
34378
|
+
break;
|
|
34379
|
+
}
|
|
33547
34380
|
}
|
|
33548
|
-
|
|
33549
|
-
|
|
33550
|
-
|
|
33551
|
-
|
|
33552
|
-
|
|
33553
|
-
|
|
33554
|
-
|
|
34381
|
+
if (state.projects?.length) {
|
|
34382
|
+
const result = await fetchProjects(rt.params);
|
|
34383
|
+
if (result.ok) {
|
|
34384
|
+
const projectByIdMap = /* @__PURE__ */ new Map();
|
|
34385
|
+
for (const p of result.projects) {
|
|
34386
|
+
const id = projectId(p);
|
|
34387
|
+
if (id) projectByIdMap.set(id, p);
|
|
34388
|
+
}
|
|
34389
|
+
const targetIds = await resolveSetupSelection({
|
|
34390
|
+
selected: state.projects,
|
|
34391
|
+
allSentinel: ALL_PROJECTS6,
|
|
34392
|
+
fetchAll: async () => result.projects.map((p) => projectId(p)).filter((id) => id),
|
|
34393
|
+
limit: SEMRUSH_SETUP_MAX_PROJECTS
|
|
34394
|
+
});
|
|
34395
|
+
if (targetIds.length > 0) {
|
|
34396
|
+
sections.push("### Projects", "");
|
|
34397
|
+
sections.push("| Project | Domain | Created |");
|
|
34398
|
+
sections.push("|---------|--------|---------|");
|
|
34399
|
+
for (const id of targetIds) {
|
|
34400
|
+
const p = projectByIdMap.get(id);
|
|
34401
|
+
if (!p) {
|
|
34402
|
+
sections.push(`| ${id} | - | - |`);
|
|
34403
|
+
continue;
|
|
34404
|
+
}
|
|
34405
|
+
const name = projectName(p).replace(/\|/g, "\\|");
|
|
34406
|
+
const dom = projectDomain(p).replace(/\|/g, "\\|") || "-";
|
|
34407
|
+
const created = projectCreatedAt(p) || "-";
|
|
34408
|
+
sections.push(`| ${name} | ${dom} | ${created} |`);
|
|
34409
|
+
}
|
|
34410
|
+
sections.push("");
|
|
34411
|
+
}
|
|
33555
34412
|
}
|
|
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
34413
|
}
|
|
33561
|
-
sections.push("");
|
|
33562
34414
|
return sections.join("\n");
|
|
33563
34415
|
}
|
|
33564
34416
|
};
|
|
@@ -33819,7 +34671,7 @@ API \u30E6\u30CB\u30C3\u30C8\u6B8B\u91CF\u306E\u78BA\u8A8D\uFF08\u7121\u6599\u30
|
|
|
33819
34671
|
|
|
33820
34672
|
// ../connectors/src/connectors/google-search-console-oauth/tools/list-sites.ts
|
|
33821
34673
|
import { z as z84 } from "zod";
|
|
33822
|
-
var
|
|
34674
|
+
var BASE_URL60 = "https://searchconsole.googleapis.com/webmasters/v3";
|
|
33823
34675
|
var REQUEST_TIMEOUT_MS67 = 6e4;
|
|
33824
34676
|
var cachedToken30 = null;
|
|
33825
34677
|
async function getProxyToken30(config) {
|
|
@@ -33890,7 +34742,7 @@ var listSitesTool = new ConnectorTool({
|
|
|
33890
34742
|
`[connector-request] google-search-console-oauth/${connection.name}: listSites`
|
|
33891
34743
|
);
|
|
33892
34744
|
try {
|
|
33893
|
-
const url = `${
|
|
34745
|
+
const url = `${BASE_URL60}/sites`;
|
|
33894
34746
|
const token = await getProxyToken30(config.oauthProxy);
|
|
33895
34747
|
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
33896
34748
|
const controller = new AbortController();
|
|
@@ -34072,7 +34924,7 @@ var googleSearchConsoleOauthSetupFlow = {
|
|
|
34072
34924
|
import { z as z85 } from "zod";
|
|
34073
34925
|
var BASE_HOST10 = "https://searchconsole.googleapis.com";
|
|
34074
34926
|
var BASE_PATH_SEGMENT10 = "/webmasters/v3";
|
|
34075
|
-
var
|
|
34927
|
+
var BASE_URL61 = `${BASE_HOST10}${BASE_PATH_SEGMENT10}`;
|
|
34076
34928
|
var REQUEST_TIMEOUT_MS68 = 6e4;
|
|
34077
34929
|
var cachedToken31 = null;
|
|
34078
34930
|
async function getProxyToken31(config) {
|
|
@@ -34157,7 +35009,7 @@ For URL Inspection API requests, use the absolute path '/v1/urlInspection/index:
|
|
|
34157
35009
|
resolvedPath,
|
|
34158
35010
|
BASE_PATH_SEGMENT10
|
|
34159
35011
|
);
|
|
34160
|
-
let url = `${
|
|
35012
|
+
let url = `${BASE_URL61}${normalizedPath}`;
|
|
34161
35013
|
if (queryParams) {
|
|
34162
35014
|
const searchParams = new URLSearchParams(queryParams);
|
|
34163
35015
|
url += `?${searchParams.toString()}`;
|
|
@@ -34483,7 +35335,7 @@ function isInternalSchema3(name) {
|
|
|
34483
35335
|
if (lower.startsWith("pg_toast_")) return true;
|
|
34484
35336
|
return false;
|
|
34485
35337
|
}
|
|
34486
|
-
async function
|
|
35338
|
+
async function fetchTableNames4(params, schema) {
|
|
34487
35339
|
const rows = await runQuery10(
|
|
34488
35340
|
params,
|
|
34489
35341
|
`SELECT table_name FROM information_schema.tables
|
|
@@ -34516,17 +35368,17 @@ var supabaseSetupFlow = {
|
|
|
34516
35368
|
slug: "tables",
|
|
34517
35369
|
type: "multiSelect",
|
|
34518
35370
|
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)"
|
|
35371
|
+
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",
|
|
35372
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
34521
35373
|
},
|
|
34522
35374
|
async fetchOptions(state, rt) {
|
|
34523
35375
|
if (!state.schema) return [];
|
|
34524
|
-
const names = await
|
|
35376
|
+
const names = await fetchTableNames4(rt.params, state.schema);
|
|
34525
35377
|
const tableOptions = names.map((value) => ({ value }));
|
|
34526
35378
|
return [
|
|
34527
35379
|
{
|
|
34528
35380
|
value: ALL_TABLES13,
|
|
34529
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
35381
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
34530
35382
|
},
|
|
34531
35383
|
...tableOptions
|
|
34532
35384
|
];
|
|
@@ -34542,7 +35394,7 @@ var supabaseSetupFlow = {
|
|
|
34542
35394
|
const targetTables = await resolveSetupSelection({
|
|
34543
35395
|
selected: state.tables,
|
|
34544
35396
|
allSentinel: ALL_TABLES13,
|
|
34545
|
-
fetchAll: () =>
|
|
35397
|
+
fetchAll: () => fetchTableNames4(rt.params, schema),
|
|
34546
35398
|
limit: SUPABASE_SETUP_MAX_TABLES
|
|
34547
35399
|
});
|
|
34548
35400
|
const sections = [
|
|
@@ -34777,13 +35629,13 @@ var parameters71 = {
|
|
|
34777
35629
|
};
|
|
34778
35630
|
|
|
34779
35631
|
// ../connectors/src/connectors/clickup/utils.ts
|
|
34780
|
-
var
|
|
35632
|
+
var BASE_URL62 = "https://api.clickup.com/api/v2";
|
|
34781
35633
|
async function apiFetch30(params, path5, init) {
|
|
34782
35634
|
const token = params[parameters71.apiToken.slug];
|
|
34783
35635
|
if (!token) {
|
|
34784
35636
|
throw new Error("clickup: missing required parameter: api-token");
|
|
34785
35637
|
}
|
|
34786
|
-
const url = `${
|
|
35638
|
+
const url = `${BASE_URL62}${path5.startsWith("/") ? "" : "/"}${path5}`;
|
|
34787
35639
|
const headers = new Headers(init?.headers);
|
|
34788
35640
|
headers.set("Authorization", token);
|
|
34789
35641
|
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
@@ -34911,7 +35763,7 @@ var clickupSetupFlow = {
|
|
|
34911
35763
|
import { z as z87 } from "zod";
|
|
34912
35764
|
var BASE_HOST11 = "https://api.clickup.com";
|
|
34913
35765
|
var BASE_PATH_SEGMENT11 = "/api/v2";
|
|
34914
|
-
var
|
|
35766
|
+
var BASE_URL63 = `${BASE_HOST11}${BASE_PATH_SEGMENT11}`;
|
|
34915
35767
|
var REQUEST_TIMEOUT_MS69 = 6e4;
|
|
34916
35768
|
var inputSchema87 = z87.object({
|
|
34917
35769
|
toolUseIntent: z87.string().optional().describe(
|
|
@@ -34984,7 +35836,7 @@ Pagination: ClickUp uses zero-indexed \`page\` query parameter on list endpoints
|
|
|
34984
35836
|
try {
|
|
34985
35837
|
const token = parameters71.apiToken.getValue(connection);
|
|
34986
35838
|
const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT11);
|
|
34987
|
-
const url = `${
|
|
35839
|
+
const url = `${BASE_URL63}${normalizedPath}`;
|
|
34988
35840
|
const controller = new AbortController();
|
|
34989
35841
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS69);
|
|
34990
35842
|
try {
|
|
@@ -35314,7 +36166,7 @@ function quoteLiteral4(value) {
|
|
|
35314
36166
|
}
|
|
35315
36167
|
function buildFlow(options) {
|
|
35316
36168
|
const { connectorName, forceEncrypt } = options;
|
|
35317
|
-
async function
|
|
36169
|
+
async function fetchTableNames5(params, schema) {
|
|
35318
36170
|
const rows = await runSqlServerSetupQuery(
|
|
35319
36171
|
params,
|
|
35320
36172
|
`SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
|
|
@@ -35349,17 +36201,17 @@ function buildFlow(options) {
|
|
|
35349
36201
|
slug: "tables",
|
|
35350
36202
|
type: "multiSelect",
|
|
35351
36203
|
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)"
|
|
36204
|
+
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",
|
|
36205
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
35354
36206
|
},
|
|
35355
36207
|
async fetchOptions(state, rt) {
|
|
35356
36208
|
if (!state.schema) return [];
|
|
35357
|
-
const names = await
|
|
36209
|
+
const names = await fetchTableNames5(rt.params, state.schema);
|
|
35358
36210
|
const tableOptions = names.map((value) => ({ value }));
|
|
35359
36211
|
return [
|
|
35360
36212
|
{
|
|
35361
36213
|
value: ALL_TABLES14,
|
|
35362
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
36214
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
35363
36215
|
},
|
|
35364
36216
|
...tableOptions
|
|
35365
36217
|
];
|
|
@@ -35375,7 +36227,7 @@ function buildFlow(options) {
|
|
|
35375
36227
|
const targetTables = await resolveSetupSelection({
|
|
35376
36228
|
selected: state.tables,
|
|
35377
36229
|
allSentinel: ALL_TABLES14,
|
|
35378
|
-
fetchAll: () =>
|
|
36230
|
+
fetchAll: () => fetchTableNames5(rt.params, schema),
|
|
35379
36231
|
limit: SQLSERVER_SETUP_MAX_TABLES
|
|
35380
36232
|
});
|
|
35381
36233
|
const sections = [
|
|
@@ -36370,14 +37222,15 @@ function isInternalOwner(name) {
|
|
|
36370
37222
|
function quoteLiteral5(value) {
|
|
36371
37223
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
36372
37224
|
}
|
|
36373
|
-
async function
|
|
37225
|
+
async function fetchTableAndViewNames2(params, owner) {
|
|
36374
37226
|
const rows = await runOracleSetupQuery(
|
|
36375
37227
|
params,
|
|
36376
|
-
`SELECT TABLE_NAME FROM ALL_TABLES
|
|
36377
|
-
|
|
36378
|
-
|
|
37228
|
+
`SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = ${quoteLiteral5(owner)}
|
|
37229
|
+
UNION
|
|
37230
|
+
SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER = ${quoteLiteral5(owner)}
|
|
37231
|
+
ORDER BY 1`
|
|
36379
37232
|
);
|
|
36380
|
-
return rows.map((r) => String(r["TABLE_NAME"] ?? "")).filter((name) => name);
|
|
37233
|
+
return rows.map((r) => String(r["TABLE_NAME"] ?? r["VIEW_NAME"] ?? "")).filter((name) => name);
|
|
36381
37234
|
}
|
|
36382
37235
|
var oracleSetupFlow = {
|
|
36383
37236
|
initialState: () => ({}),
|
|
@@ -36402,17 +37255,17 @@ var oracleSetupFlow = {
|
|
|
36402
37255
|
slug: "tables",
|
|
36403
37256
|
type: "multiSelect",
|
|
36404
37257
|
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)"
|
|
37258
|
+
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",
|
|
37259
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
36407
37260
|
},
|
|
36408
37261
|
async fetchOptions(state, rt) {
|
|
36409
37262
|
if (!state.owner) return [];
|
|
36410
|
-
const names = await
|
|
37263
|
+
const names = await fetchTableAndViewNames2(rt.params, state.owner);
|
|
36411
37264
|
const tableOptions = names.map((value) => ({ value }));
|
|
36412
37265
|
return [
|
|
36413
37266
|
{
|
|
36414
37267
|
value: ALL_TABLES15,
|
|
36415
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
37268
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
36416
37269
|
},
|
|
36417
37270
|
...tableOptions
|
|
36418
37271
|
];
|
|
@@ -36428,9 +37281,22 @@ var oracleSetupFlow = {
|
|
|
36428
37281
|
const targetTables = await resolveSetupSelection({
|
|
36429
37282
|
selected: state.tables,
|
|
36430
37283
|
allSentinel: ALL_TABLES15,
|
|
36431
|
-
fetchAll: () =>
|
|
37284
|
+
fetchAll: () => fetchTableAndViewNames2(rt.params, owner),
|
|
36432
37285
|
limit: ORACLE_SETUP_MAX_TABLES
|
|
36433
37286
|
});
|
|
37287
|
+
const typeRows = targetTables.length > 0 ? await runOracleSetupQuery(
|
|
37288
|
+
rt.params,
|
|
37289
|
+
`SELECT OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS
|
|
37290
|
+
WHERE OWNER = ${quoteLiteral5(owner)}
|
|
37291
|
+
AND OBJECT_NAME IN (${targetTables.map(quoteLiteral5).join(", ")})
|
|
37292
|
+
AND OBJECT_TYPE IN ('TABLE', 'VIEW')`
|
|
37293
|
+
) : [];
|
|
37294
|
+
const typeMap = new Map(
|
|
37295
|
+
typeRows.map((r) => [
|
|
37296
|
+
String(r["OBJECT_NAME"] ?? ""),
|
|
37297
|
+
String(r["OBJECT_TYPE"] ?? "TABLE")
|
|
37298
|
+
])
|
|
37299
|
+
);
|
|
36434
37300
|
const sections = [
|
|
36435
37301
|
"## Oracle Database",
|
|
36436
37302
|
"",
|
|
@@ -36438,6 +37304,7 @@ var oracleSetupFlow = {
|
|
|
36438
37304
|
""
|
|
36439
37305
|
];
|
|
36440
37306
|
for (const table of targetTables) {
|
|
37307
|
+
const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
|
|
36441
37308
|
const cols = await runOracleSetupQuery(
|
|
36442
37309
|
rt.params,
|
|
36443
37310
|
`SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
|
|
@@ -36446,7 +37313,7 @@ var oracleSetupFlow = {
|
|
|
36446
37313
|
AND TABLE_NAME = ${quoteLiteral5(table)}
|
|
36447
37314
|
ORDER BY COLUMN_ID`
|
|
36448
37315
|
);
|
|
36449
|
-
sections.push(`####
|
|
37316
|
+
sections.push(`#### ${heading}: ${table}`, "");
|
|
36450
37317
|
sections.push("| Column | Type | Nullable | Default |");
|
|
36451
37318
|
sections.push("|--------|------|----------|---------|");
|
|
36452
37319
|
for (const c of cols) {
|
|
@@ -38751,7 +39618,7 @@ export default async function handler(c: Context) {
|
|
|
38751
39618
|
import { z as z97 } from "zod";
|
|
38752
39619
|
var BASE_HOST12 = "https://api.powerbi.com";
|
|
38753
39620
|
var BASE_PATH_SEGMENT18 = "/v1.0/myorg";
|
|
38754
|
-
var
|
|
39621
|
+
var BASE_URL64 = `${BASE_HOST12}${BASE_PATH_SEGMENT18}`;
|
|
38755
39622
|
var REQUEST_TIMEOUT_MS74 = 6e4;
|
|
38756
39623
|
var cachedToken32 = null;
|
|
38757
39624
|
async function getProxyToken32(config) {
|
|
@@ -38833,7 +39700,7 @@ The signed-in user must have access to the workspace; unlike Service Principals,
|
|
|
38833
39700
|
);
|
|
38834
39701
|
try {
|
|
38835
39702
|
const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT18);
|
|
38836
|
-
let url = `${
|
|
39703
|
+
let url = `${BASE_URL64}${normalizedPath}`;
|
|
38837
39704
|
if (queryParams) {
|
|
38838
39705
|
const searchParams = new URLSearchParams(queryParams);
|
|
38839
39706
|
url += `?${searchParams.toString()}`;
|
|
@@ -38916,14 +39783,18 @@ var powerbiOauthOnboarding = new ConnectorOnboarding({
|
|
|
38916
39783
|
var parameters80 = {};
|
|
38917
39784
|
|
|
38918
39785
|
// ../connectors/src/connectors/powerbi-oauth/utils.ts
|
|
38919
|
-
var
|
|
39786
|
+
var BASE_URL65 = "https://api.powerbi.com/v1.0/myorg";
|
|
38920
39787
|
function apiFetch35(proxyFetch, path5, init) {
|
|
38921
|
-
const url = `${
|
|
39788
|
+
const url = `${BASE_URL65}${path5.startsWith("/") ? "" : "/"}${path5}`;
|
|
38922
39789
|
return proxyFetch(url, init);
|
|
38923
39790
|
}
|
|
38924
39791
|
|
|
38925
39792
|
// ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
|
|
38926
39793
|
var ALL_WORKSPACES = "__ALL_WORKSPACES__";
|
|
39794
|
+
var MY_WORKSPACE = "__MY_WORKSPACE__";
|
|
39795
|
+
var ALL_DATASETS = "__ALL_DATASETS__";
|
|
39796
|
+
var ALL_REPORTS = "__ALL_REPORTS__";
|
|
39797
|
+
var ALL_DASHBOARDS = "__ALL_DASHBOARDS__";
|
|
38927
39798
|
var POWERBI_SETUP_MAX_WORKSPACES = 10;
|
|
38928
39799
|
var RESOURCE_DISPLAY_LIMIT = 25;
|
|
38929
39800
|
var RESOURCE_DATASETS = "datasets";
|
|
@@ -38939,14 +39810,12 @@ async function listGroups(proxyFetch) {
|
|
|
38939
39810
|
return data.value ?? [];
|
|
38940
39811
|
}
|
|
38941
39812
|
async function listResource(proxyFetch, groupId, resource) {
|
|
38942
|
-
const
|
|
38943
|
-
|
|
38944
|
-
`/groups/${encodeURIComponent(groupId)}/${resource}`
|
|
38945
|
-
);
|
|
39813
|
+
const path5 = groupId === MY_WORKSPACE ? `/${resource}` : `/groups/${encodeURIComponent(groupId)}/${resource}`;
|
|
39814
|
+
const res = await apiFetch35(proxyFetch, path5);
|
|
38946
39815
|
if (!res.ok) {
|
|
38947
39816
|
const body = await res.text().catch(() => res.statusText);
|
|
38948
39817
|
throw new Error(
|
|
38949
|
-
`powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
|
|
39818
|
+
`powerbi: list ${resource} for ${groupId === MY_WORKSPACE ? "My workspace" : `group ${groupId}`} failed (${res.status}): ${body}`
|
|
38950
39819
|
);
|
|
38951
39820
|
}
|
|
38952
39821
|
const data = await res.json();
|
|
@@ -38955,6 +39824,99 @@ async function listResource(proxyFetch, groupId, resource) {
|
|
|
38955
39824
|
function resourceLabel(r) {
|
|
38956
39825
|
return r.name ?? r.displayName ?? r.id ?? "(unknown)";
|
|
38957
39826
|
}
|
|
39827
|
+
var INTERNAL_TABLE_PREFIXES = [
|
|
39828
|
+
"DateTableTemplate_",
|
|
39829
|
+
"LocalDateTable_"
|
|
39830
|
+
];
|
|
39831
|
+
function isInternalColumn(name) {
|
|
39832
|
+
return /^RowNumber-[0-9A-Fa-f-]+$/.test(name);
|
|
39833
|
+
}
|
|
39834
|
+
async function fetchDatasetSchema(proxyFetch, wsId, datasetId) {
|
|
39835
|
+
const pathPrefix = wsId === MY_WORKSPACE ? "" : `/groups/${encodeURIComponent(wsId)}`;
|
|
39836
|
+
const daxQuery = 'EVALUATE SELECTCOLUMNS(COLUMNSTATISTICS(), "T", [Table Name], "C", [Column Name])';
|
|
39837
|
+
const res = await apiFetch35(
|
|
39838
|
+
proxyFetch,
|
|
39839
|
+
`${pathPrefix}/datasets/${encodeURIComponent(datasetId)}/executeQueries`,
|
|
39840
|
+
{
|
|
39841
|
+
method: "POST",
|
|
39842
|
+
headers: { "Content-Type": "application/json" },
|
|
39843
|
+
body: JSON.stringify({
|
|
39844
|
+
queries: [{ query: daxQuery }],
|
|
39845
|
+
serializerSettings: { includeNulls: true }
|
|
39846
|
+
})
|
|
39847
|
+
}
|
|
39848
|
+
);
|
|
39849
|
+
if (!res.ok) return /* @__PURE__ */ new Map();
|
|
39850
|
+
const data = await res.json();
|
|
39851
|
+
const rows = data.results?.[0]?.tables?.[0]?.rows ?? [];
|
|
39852
|
+
const schema = /* @__PURE__ */ new Map();
|
|
39853
|
+
for (const row of rows) {
|
|
39854
|
+
const table = row["[T]"] ?? "";
|
|
39855
|
+
const column = row["[C]"] ?? "";
|
|
39856
|
+
if (!table || !column) continue;
|
|
39857
|
+
if (INTERNAL_TABLE_PREFIXES.some((p) => table.startsWith(p))) continue;
|
|
39858
|
+
if (isInternalColumn(column)) continue;
|
|
39859
|
+
if (!schema.has(table)) schema.set(table, []);
|
|
39860
|
+
schema.get(table).push(column);
|
|
39861
|
+
}
|
|
39862
|
+
return schema;
|
|
39863
|
+
}
|
|
39864
|
+
function workspaceName(wsId, groupById, language) {
|
|
39865
|
+
if (wsId === MY_WORKSPACE) {
|
|
39866
|
+
return language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace";
|
|
39867
|
+
}
|
|
39868
|
+
return groupById.get(wsId)?.name ?? wsId;
|
|
39869
|
+
}
|
|
39870
|
+
async function resolveWorkspaceIds(selected, proxyFetch) {
|
|
39871
|
+
return resolveSetupSelection({
|
|
39872
|
+
selected,
|
|
39873
|
+
allSentinel: ALL_WORKSPACES,
|
|
39874
|
+
fetchAll: async () => {
|
|
39875
|
+
const groups = await listGroups(proxyFetch);
|
|
39876
|
+
return [MY_WORKSPACE, ...groups.map((g) => g.id).filter(Boolean)];
|
|
39877
|
+
},
|
|
39878
|
+
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
39879
|
+
});
|
|
39880
|
+
}
|
|
39881
|
+
function compoundKey(wsId, objectId) {
|
|
39882
|
+
return `${wsId}:${objectId}`;
|
|
39883
|
+
}
|
|
39884
|
+
function parseCompoundKey(key) {
|
|
39885
|
+
const idx = key.indexOf(":");
|
|
39886
|
+
if (idx < 0) return { wsId: "", objectId: key };
|
|
39887
|
+
return { wsId: key.slice(0, idx), objectId: key.slice(idx + 1) };
|
|
39888
|
+
}
|
|
39889
|
+
async function fetchObjectOptions(state, resource, allSentinel, allLabelJa, allLabelEn, rt) {
|
|
39890
|
+
if (!state.workspaces?.length || !state.resources?.includes(resource))
|
|
39891
|
+
return [];
|
|
39892
|
+
const wsIds = await resolveWorkspaceIds(
|
|
39893
|
+
state.workspaces,
|
|
39894
|
+
rt.config.proxyFetch
|
|
39895
|
+
);
|
|
39896
|
+
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
39897
|
+
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
39898
|
+
const multiWorkspace = wsIds.length > 1;
|
|
39899
|
+
const options = [];
|
|
39900
|
+
for (const wsId of wsIds) {
|
|
39901
|
+
const wsLabel = workspaceName(wsId, groupById, rt.language);
|
|
39902
|
+
const items = await listResource(rt.config.proxyFetch, wsId, resource);
|
|
39903
|
+
for (const item of items) {
|
|
39904
|
+
if (!item.id) continue;
|
|
39905
|
+
options.push({
|
|
39906
|
+
value: compoundKey(wsId, item.id),
|
|
39907
|
+
label: multiWorkspace ? `${wsLabel} / ${resourceLabel(item)}` : resourceLabel(item)
|
|
39908
|
+
});
|
|
39909
|
+
}
|
|
39910
|
+
}
|
|
39911
|
+
if (options.length === 0) return [];
|
|
39912
|
+
return [
|
|
39913
|
+
{
|
|
39914
|
+
value: allSentinel,
|
|
39915
|
+
label: rt.language === "ja" ? allLabelJa : allLabelEn
|
|
39916
|
+
},
|
|
39917
|
+
...options
|
|
39918
|
+
];
|
|
39919
|
+
}
|
|
38958
39920
|
var powerbiOauthSetupFlow = {
|
|
38959
39921
|
initialState: () => ({}),
|
|
38960
39922
|
steps: [
|
|
@@ -38973,6 +39935,10 @@ var powerbiOauthSetupFlow = {
|
|
|
38973
39935
|
value: ALL_WORKSPACES,
|
|
38974
39936
|
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
|
|
38975
39937
|
},
|
|
39938
|
+
{
|
|
39939
|
+
value: MY_WORKSPACE,
|
|
39940
|
+
label: rt.language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace"
|
|
39941
|
+
},
|
|
38976
39942
|
...options
|
|
38977
39943
|
];
|
|
38978
39944
|
},
|
|
@@ -38987,16 +39953,82 @@ var powerbiOauthSetupFlow = {
|
|
|
38987
39953
|
},
|
|
38988
39954
|
async fetchOptions(state, rt) {
|
|
38989
39955
|
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
39956
|
return [
|
|
38994
|
-
{
|
|
38995
|
-
|
|
38996
|
-
|
|
39957
|
+
{
|
|
39958
|
+
value: RESOURCE_DATASETS,
|
|
39959
|
+
label: rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets"
|
|
39960
|
+
},
|
|
39961
|
+
{
|
|
39962
|
+
value: RESOURCE_REPORTS,
|
|
39963
|
+
label: rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports"
|
|
39964
|
+
},
|
|
39965
|
+
{
|
|
39966
|
+
value: RESOURCE_DASHBOARDS,
|
|
39967
|
+
label: rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards"
|
|
39968
|
+
}
|
|
38997
39969
|
];
|
|
38998
39970
|
},
|
|
38999
39971
|
applyAnswer: (state, answer) => ({ ...state, resources: answer })
|
|
39972
|
+
},
|
|
39973
|
+
{
|
|
39974
|
+
slug: "datasets",
|
|
39975
|
+
type: "multiSelect",
|
|
39976
|
+
question: {
|
|
39977
|
+
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",
|
|
39978
|
+
en: "Select the datasets you want to use (multi-select allowed)"
|
|
39979
|
+
},
|
|
39980
|
+
async fetchOptions(state, rt) {
|
|
39981
|
+
return fetchObjectOptions(
|
|
39982
|
+
state,
|
|
39983
|
+
RESOURCE_DATASETS,
|
|
39984
|
+
ALL_DATASETS,
|
|
39985
|
+
"\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8",
|
|
39986
|
+
"All datasets",
|
|
39987
|
+
rt
|
|
39988
|
+
);
|
|
39989
|
+
},
|
|
39990
|
+
applyAnswer: (state, answer) => ({ ...state, selectedDatasets: answer })
|
|
39991
|
+
},
|
|
39992
|
+
{
|
|
39993
|
+
slug: "reports",
|
|
39994
|
+
type: "multiSelect",
|
|
39995
|
+
question: {
|
|
39996
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
39997
|
+
en: "Select the reports you want to use (multi-select allowed)"
|
|
39998
|
+
},
|
|
39999
|
+
async fetchOptions(state, rt) {
|
|
40000
|
+
return fetchObjectOptions(
|
|
40001
|
+
state,
|
|
40002
|
+
RESOURCE_REPORTS,
|
|
40003
|
+
ALL_REPORTS,
|
|
40004
|
+
"\u3059\u3079\u3066\u306E\u30EC\u30DD\u30FC\u30C8",
|
|
40005
|
+
"All reports",
|
|
40006
|
+
rt
|
|
40007
|
+
);
|
|
40008
|
+
},
|
|
40009
|
+
applyAnswer: (state, answer) => ({ ...state, selectedReports: answer })
|
|
40010
|
+
},
|
|
40011
|
+
{
|
|
40012
|
+
slug: "dashboards",
|
|
40013
|
+
type: "multiSelect",
|
|
40014
|
+
question: {
|
|
40015
|
+
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",
|
|
40016
|
+
en: "Select the dashboards you want to use (multi-select allowed)"
|
|
40017
|
+
},
|
|
40018
|
+
async fetchOptions(state, rt) {
|
|
40019
|
+
return fetchObjectOptions(
|
|
40020
|
+
state,
|
|
40021
|
+
RESOURCE_DASHBOARDS,
|
|
40022
|
+
ALL_DASHBOARDS,
|
|
40023
|
+
"\u3059\u3079\u3066\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9",
|
|
40024
|
+
"All dashboards",
|
|
40025
|
+
rt
|
|
40026
|
+
);
|
|
40027
|
+
},
|
|
40028
|
+
applyAnswer: (state, answer) => ({
|
|
40029
|
+
...state,
|
|
40030
|
+
selectedDashboards: answer
|
|
40031
|
+
})
|
|
39000
40032
|
}
|
|
39001
40033
|
],
|
|
39002
40034
|
async finalize(state, rt) {
|
|
@@ -39005,37 +40037,119 @@ var powerbiOauthSetupFlow = {
|
|
|
39005
40037
|
}
|
|
39006
40038
|
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
39007
40039
|
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
39008
|
-
const
|
|
39009
|
-
|
|
39010
|
-
|
|
39011
|
-
|
|
39012
|
-
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
39013
|
-
});
|
|
40040
|
+
const wsIds = await resolveWorkspaceIds(
|
|
40041
|
+
state.workspaces,
|
|
40042
|
+
rt.config.proxyFetch
|
|
40043
|
+
);
|
|
39014
40044
|
const selectedResources = new Set(state.resources);
|
|
40045
|
+
async function resolveObjects(selected, allSentinel, resource) {
|
|
40046
|
+
const byWorkspace = /* @__PURE__ */ new Map();
|
|
40047
|
+
if (!selected || !selectedResources.has(resource)) return byWorkspace;
|
|
40048
|
+
if (selected.includes(allSentinel)) {
|
|
40049
|
+
for (const wsId of wsIds) {
|
|
40050
|
+
const items = await listResource(
|
|
40051
|
+
rt.config.proxyFetch,
|
|
40052
|
+
wsId,
|
|
40053
|
+
resource
|
|
40054
|
+
);
|
|
40055
|
+
const ids = items.map((i) => i.id).filter((id) => !!id);
|
|
40056
|
+
if (ids.length > 0) byWorkspace.set(wsId, new Set(ids));
|
|
40057
|
+
}
|
|
40058
|
+
} else {
|
|
40059
|
+
for (const key of selected) {
|
|
40060
|
+
if (key === allSentinel) continue;
|
|
40061
|
+
const { wsId, objectId } = parseCompoundKey(key);
|
|
40062
|
+
if (!byWorkspace.has(wsId)) byWorkspace.set(wsId, /* @__PURE__ */ new Set());
|
|
40063
|
+
byWorkspace.get(wsId).add(objectId);
|
|
40064
|
+
}
|
|
40065
|
+
}
|
|
40066
|
+
return byWorkspace;
|
|
40067
|
+
}
|
|
40068
|
+
const datasetsByWs = await resolveObjects(
|
|
40069
|
+
state.selectedDatasets,
|
|
40070
|
+
ALL_DATASETS,
|
|
40071
|
+
RESOURCE_DATASETS
|
|
40072
|
+
);
|
|
40073
|
+
const reportsByWs = await resolveObjects(
|
|
40074
|
+
state.selectedReports,
|
|
40075
|
+
ALL_REPORTS,
|
|
40076
|
+
RESOURCE_REPORTS
|
|
40077
|
+
);
|
|
40078
|
+
const dashboardsByWs = await resolveObjects(
|
|
40079
|
+
state.selectedDashboards,
|
|
40080
|
+
ALL_DASHBOARDS,
|
|
40081
|
+
RESOURCE_DASHBOARDS
|
|
40082
|
+
);
|
|
40083
|
+
const allWsIds = /* @__PURE__ */ new Set([
|
|
40084
|
+
...datasetsByWs.keys(),
|
|
40085
|
+
...reportsByWs.keys(),
|
|
40086
|
+
...dashboardsByWs.keys()
|
|
40087
|
+
]);
|
|
39015
40088
|
const sections = ["## Power BI", ""];
|
|
39016
|
-
if (
|
|
39017
|
-
sections.push("_No
|
|
40089
|
+
if (allWsIds.size === 0) {
|
|
40090
|
+
sections.push("_No resources selected._", "");
|
|
39018
40091
|
return sections.join("\n");
|
|
39019
40092
|
}
|
|
39020
|
-
for (const
|
|
39021
|
-
|
|
39022
|
-
const name =
|
|
39023
|
-
sections.push(`### Workspace: ${name}`, ""
|
|
39024
|
-
|
|
39025
|
-
|
|
39026
|
-
|
|
39027
|
-
|
|
40093
|
+
for (const wsId of wsIds) {
|
|
40094
|
+
if (!allWsIds.has(wsId)) continue;
|
|
40095
|
+
const name = workspaceName(wsId, groupById, rt.language);
|
|
40096
|
+
sections.push(`### Workspace: ${name}`, "");
|
|
40097
|
+
if (wsId !== MY_WORKSPACE) {
|
|
40098
|
+
sections.push(`- id: \`${wsId}\``);
|
|
40099
|
+
}
|
|
40100
|
+
const datasetIds = datasetsByWs.get(wsId);
|
|
40101
|
+
if (datasetIds?.size) {
|
|
40102
|
+
const items = await listResource(
|
|
40103
|
+
rt.config.proxyFetch,
|
|
40104
|
+
wsId,
|
|
40105
|
+
RESOURCE_DATASETS
|
|
40106
|
+
);
|
|
40107
|
+
const filtered = items.filter(
|
|
40108
|
+
(item) => item.id && datasetIds.has(item.id)
|
|
40109
|
+
);
|
|
40110
|
+
for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
40111
|
+
sections.push(`#### Dataset: ${resourceLabel(item)}`, "");
|
|
40112
|
+
const schema = await fetchDatasetSchema(
|
|
40113
|
+
rt.config.proxyFetch,
|
|
40114
|
+
wsId,
|
|
40115
|
+
item.id
|
|
40116
|
+
);
|
|
40117
|
+
if (schema.size > 0) {
|
|
40118
|
+
for (const [table, columns] of schema) {
|
|
40119
|
+
sections.push(`##### Table: ${table}`, "");
|
|
40120
|
+
sections.push("| Column |");
|
|
40121
|
+
sections.push("|--------|");
|
|
40122
|
+
for (const col of columns) {
|
|
40123
|
+
sections.push(`| ${col} |`);
|
|
40124
|
+
}
|
|
40125
|
+
sections.push("");
|
|
40126
|
+
}
|
|
40127
|
+
} else {
|
|
40128
|
+
sections.push("_Schema not available._", "");
|
|
40129
|
+
}
|
|
40130
|
+
}
|
|
40131
|
+
}
|
|
40132
|
+
for (const [resource, selectedByWs, heading] of [
|
|
40133
|
+
[RESOURCE_REPORTS, reportsByWs, "Reports"],
|
|
40134
|
+
[RESOURCE_DASHBOARDS, dashboardsByWs, "Dashboards"]
|
|
39028
40135
|
]) {
|
|
39029
|
-
|
|
39030
|
-
|
|
39031
|
-
const
|
|
39032
|
-
|
|
39033
|
-
|
|
40136
|
+
const selectedIds = selectedByWs.get(wsId);
|
|
40137
|
+
if (!selectedIds?.size) continue;
|
|
40138
|
+
const items = await listResource(
|
|
40139
|
+
rt.config.proxyFetch,
|
|
40140
|
+
wsId,
|
|
40141
|
+
resource
|
|
40142
|
+
);
|
|
40143
|
+
const filtered = items.filter(
|
|
40144
|
+
(item) => item.id && selectedIds.has(item.id)
|
|
40145
|
+
);
|
|
40146
|
+
sections.push(`- ${heading} (${filtered.length}):`);
|
|
40147
|
+
for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
39034
40148
|
sections.push(` - ${resourceLabel(item)}`);
|
|
39035
40149
|
}
|
|
39036
|
-
if (
|
|
40150
|
+
if (filtered.length > RESOURCE_DISPLAY_LIMIT) {
|
|
39037
40151
|
sections.push(
|
|
39038
|
-
` - \u2026and ${
|
|
40152
|
+
` - \u2026and ${filtered.length - RESOURCE_DISPLAY_LIMIT} more`
|
|
39039
40153
|
);
|
|
39040
40154
|
}
|
|
39041
40155
|
}
|
|
@@ -39306,7 +40420,11 @@ async function tableauProxyApiFetch(proxyFetch, params, path5, init) {
|
|
|
39306
40420
|
|
|
39307
40421
|
// ../connectors/src/connectors/tableau/setup-flow.ts
|
|
39308
40422
|
var ALL_PROJECTS7 = "__ALL_PROJECTS__";
|
|
40423
|
+
var ALL_WORKBOOKS = "__ALL_WORKBOOKS__";
|
|
39309
40424
|
var TABLEAU_SETUP_MAX_PROJECTS = 10;
|
|
40425
|
+
var MAX_WORKBOOKS_DETAIL = 10;
|
|
40426
|
+
var MAX_VIEWS_PER_WORKBOOK = 5;
|
|
40427
|
+
var MAX_SAMPLE_ROWS = 5;
|
|
39310
40428
|
var PAGE_SIZE2 = 100;
|
|
39311
40429
|
async function listAllProjects3(rt) {
|
|
39312
40430
|
const all = [];
|
|
@@ -39355,6 +40473,57 @@ async function listProjectResources(rt, resource) {
|
|
|
39355
40473
|
}
|
|
39356
40474
|
return all;
|
|
39357
40475
|
}
|
|
40476
|
+
async function listViewsForWorkbook(rt, workbookId) {
|
|
40477
|
+
const res = await tableauProxyApiFetch(
|
|
40478
|
+
rt.config.proxyFetch,
|
|
40479
|
+
rt.params,
|
|
40480
|
+
`/sites/{siteId}/workbooks/${encodeURIComponent(workbookId)}/views`
|
|
40481
|
+
);
|
|
40482
|
+
if (!res.ok) return [];
|
|
40483
|
+
const data = await res.json();
|
|
40484
|
+
return data.views?.view ?? [];
|
|
40485
|
+
}
|
|
40486
|
+
async function fetchViewDataSample(rt, viewId) {
|
|
40487
|
+
try {
|
|
40488
|
+
const res = await tableauProxyApiFetch(
|
|
40489
|
+
rt.config.proxyFetch,
|
|
40490
|
+
rt.params,
|
|
40491
|
+
`/sites/{siteId}/views/${encodeURIComponent(viewId)}/data`
|
|
40492
|
+
);
|
|
40493
|
+
if (!res.ok) return null;
|
|
40494
|
+
const csv = await res.text();
|
|
40495
|
+
const lines = csv.trim().split("\n").filter(Boolean);
|
|
40496
|
+
if (lines.length === 0) return null;
|
|
40497
|
+
const columns = parseCsvLine(lines[0]);
|
|
40498
|
+
const rows = lines.slice(1, 1 + MAX_SAMPLE_ROWS).map(parseCsvLine);
|
|
40499
|
+
return { columns, rows };
|
|
40500
|
+
} catch {
|
|
40501
|
+
return null;
|
|
40502
|
+
}
|
|
40503
|
+
}
|
|
40504
|
+
function parseCsvLine(line) {
|
|
40505
|
+
const result = [];
|
|
40506
|
+
let current = "";
|
|
40507
|
+
let inQuotes = false;
|
|
40508
|
+
for (let i = 0; i < line.length; i++) {
|
|
40509
|
+
const ch = line[i];
|
|
40510
|
+
if (ch === '"') {
|
|
40511
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
40512
|
+
current += '"';
|
|
40513
|
+
i++;
|
|
40514
|
+
} else {
|
|
40515
|
+
inQuotes = !inQuotes;
|
|
40516
|
+
}
|
|
40517
|
+
} else if (ch === "," && !inQuotes) {
|
|
40518
|
+
result.push(current.trim());
|
|
40519
|
+
current = "";
|
|
40520
|
+
} else {
|
|
40521
|
+
current += ch;
|
|
40522
|
+
}
|
|
40523
|
+
}
|
|
40524
|
+
result.push(current.trim());
|
|
40525
|
+
return result;
|
|
40526
|
+
}
|
|
39358
40527
|
var tableauSetupFlow = {
|
|
39359
40528
|
initialState: () => ({}),
|
|
39360
40529
|
steps: [
|
|
@@ -39377,6 +40546,39 @@ var tableauSetupFlow = {
|
|
|
39377
40546
|
];
|
|
39378
40547
|
},
|
|
39379
40548
|
applyAnswer: (state, answer) => ({ ...state, projects: answer })
|
|
40549
|
+
},
|
|
40550
|
+
{
|
|
40551
|
+
slug: "workbooks",
|
|
40552
|
+
type: "multiSelect",
|
|
40553
|
+
question: {
|
|
40554
|
+
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",
|
|
40555
|
+
en: "Select the workbooks to analyze (multi-select allowed)"
|
|
40556
|
+
},
|
|
40557
|
+
async fetchOptions(state, rt) {
|
|
40558
|
+
if (!state.projects?.length) return [];
|
|
40559
|
+
const allProjects = await listAllProjects3(rt);
|
|
40560
|
+
const targetIds = await resolveSetupSelection({
|
|
40561
|
+
selected: state.projects,
|
|
40562
|
+
allSentinel: ALL_PROJECTS7,
|
|
40563
|
+
fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
|
|
40564
|
+
limit: TABLEAU_SETUP_MAX_PROJECTS
|
|
40565
|
+
});
|
|
40566
|
+
const targetSet = new Set(targetIds);
|
|
40567
|
+
const workbooks = await listProjectResources(rt, "workbooks");
|
|
40568
|
+
const options = workbooks.filter((wb) => wb.id && wb.project?.id && targetSet.has(wb.project.id)).map((wb) => ({
|
|
40569
|
+
value: wb.id,
|
|
40570
|
+
label: wb.name ?? wb.id ?? "(unknown)"
|
|
40571
|
+
}));
|
|
40572
|
+
if (options.length === 0) return [];
|
|
40573
|
+
return [
|
|
40574
|
+
{
|
|
40575
|
+
value: ALL_WORKBOOKS,
|
|
40576
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30D6\u30C3\u30AF" : "All workbooks"
|
|
40577
|
+
},
|
|
40578
|
+
...options
|
|
40579
|
+
];
|
|
40580
|
+
},
|
|
40581
|
+
applyAnswer: (state, answer) => ({ ...state, workbooks: answer })
|
|
39380
40582
|
}
|
|
39381
40583
|
],
|
|
39382
40584
|
async finalize(state, rt) {
|
|
@@ -39385,25 +40587,33 @@ var tableauSetupFlow = {
|
|
|
39385
40587
|
}
|
|
39386
40588
|
const allProjects = await listAllProjects3(rt);
|
|
39387
40589
|
const projectById = new Map(allProjects.map((p) => [p.id, p]));
|
|
39388
|
-
const
|
|
40590
|
+
const targetProjectIds = await resolveSetupSelection({
|
|
39389
40591
|
selected: state.projects,
|
|
39390
40592
|
allSentinel: ALL_PROJECTS7,
|
|
39391
40593
|
fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
|
|
39392
40594
|
limit: TABLEAU_SETUP_MAX_PROJECTS
|
|
39393
40595
|
});
|
|
39394
40596
|
const sections = ["## Tableau", ""];
|
|
39395
|
-
if (!
|
|
40597
|
+
if (!targetProjectIds.length) {
|
|
39396
40598
|
sections.push("_No projects selected._", "");
|
|
39397
40599
|
return sections.join("\n");
|
|
39398
40600
|
}
|
|
39399
|
-
const [
|
|
40601
|
+
const [allWorkbooks, datasources] = await Promise.all([
|
|
39400
40602
|
listProjectResources(rt, "workbooks"),
|
|
39401
40603
|
listProjectResources(rt, "datasources")
|
|
39402
40604
|
]);
|
|
40605
|
+
const projectIdSet = new Set(targetProjectIds);
|
|
40606
|
+
const targetWorkbooks = await resolveSetupSelection({
|
|
40607
|
+
selected: state.workbooks ?? [],
|
|
40608
|
+
allSentinel: ALL_WORKBOOKS,
|
|
40609
|
+
fetchAll: async () => allWorkbooks.filter((wb) => wb.id && wb.project?.id && projectIdSet.has(wb.project.id)).map((wb) => wb.id).filter(Boolean),
|
|
40610
|
+
limit: MAX_WORKBOOKS_DETAIL
|
|
40611
|
+
});
|
|
40612
|
+
const targetWorkbookSet = new Set(targetWorkbooks);
|
|
39403
40613
|
const workbooksByProject = /* @__PURE__ */ new Map();
|
|
39404
|
-
for (const wb of
|
|
40614
|
+
for (const wb of allWorkbooks) {
|
|
39405
40615
|
const pid = wb.project?.id;
|
|
39406
|
-
if (!pid) continue;
|
|
40616
|
+
if (!pid || !projectIdSet.has(pid)) continue;
|
|
39407
40617
|
const bucket = workbooksByProject.get(pid) ?? [];
|
|
39408
40618
|
bucket.push(wb);
|
|
39409
40619
|
workbooksByProject.set(pid, bucket);
|
|
@@ -39411,32 +40621,78 @@ var tableauSetupFlow = {
|
|
|
39411
40621
|
const datasourcesByProject = /* @__PURE__ */ new Map();
|
|
39412
40622
|
for (const ds of datasources) {
|
|
39413
40623
|
const pid = ds.project?.id;
|
|
39414
|
-
if (!pid) continue;
|
|
40624
|
+
if (!pid || !projectIdSet.has(pid)) continue;
|
|
39415
40625
|
const bucket = datasourcesByProject.get(pid) ?? [];
|
|
39416
40626
|
bucket.push(ds);
|
|
39417
40627
|
datasourcesByProject.set(pid, bucket);
|
|
39418
40628
|
}
|
|
39419
|
-
|
|
39420
|
-
|
|
39421
|
-
const
|
|
39422
|
-
sections.push(`### Project: ${name}`, ""
|
|
39423
|
-
const projectWorkbooks = workbooksByProject.get(
|
|
39424
|
-
|
|
39425
|
-
|
|
39426
|
-
|
|
39427
|
-
|
|
39428
|
-
|
|
39429
|
-
|
|
40629
|
+
const allDiscoveredColumns = [];
|
|
40630
|
+
for (const pid of targetProjectIds) {
|
|
40631
|
+
const project = projectById.get(pid);
|
|
40632
|
+
sections.push(`### Project: ${project?.name ?? pid}`, "");
|
|
40633
|
+
const projectWorkbooks = workbooksByProject.get(pid) ?? [];
|
|
40634
|
+
for (const wb of projectWorkbooks) {
|
|
40635
|
+
if (!wb.id) continue;
|
|
40636
|
+
const isDetailed = targetWorkbookSet.has(wb.id);
|
|
40637
|
+
sections.push(`#### Workbook: ${wb.name ?? wb.id}`, "");
|
|
40638
|
+
if (!isDetailed) continue;
|
|
40639
|
+
const views = await listViewsForWorkbook(rt, wb.id);
|
|
40640
|
+
if (views.length === 0) {
|
|
40641
|
+
sections.push("_No views found._", "");
|
|
40642
|
+
continue;
|
|
40643
|
+
}
|
|
40644
|
+
for (const view of views.slice(0, MAX_VIEWS_PER_WORKBOOK)) {
|
|
40645
|
+
if (!view.id) continue;
|
|
40646
|
+
sections.push(`##### View: ${view.name ?? view.id}`, "");
|
|
40647
|
+
const sample = await fetchViewDataSample(rt, view.id);
|
|
40648
|
+
if (!sample || sample.columns.length === 0) {
|
|
40649
|
+
sections.push("_Data not available._", "");
|
|
40650
|
+
continue;
|
|
40651
|
+
}
|
|
40652
|
+
allDiscoveredColumns.push(...sample.columns);
|
|
40653
|
+
sections.push(`| ${sample.columns.join(" | ")} |`);
|
|
40654
|
+
sections.push(`|${sample.columns.map(() => "---").join("|")}|`);
|
|
40655
|
+
for (const row of sample.rows) {
|
|
40656
|
+
const cells = row.map((c) => c.replace(/\|/g, "\\|"));
|
|
40657
|
+
sections.push(`| ${cells.join(" | ")} |`);
|
|
40658
|
+
}
|
|
40659
|
+
sections.push("");
|
|
40660
|
+
}
|
|
39430
40661
|
}
|
|
39431
|
-
const projectDatasources = datasourcesByProject.get(
|
|
39432
|
-
|
|
39433
|
-
|
|
39434
|
-
|
|
40662
|
+
const projectDatasources = datasourcesByProject.get(pid) ?? [];
|
|
40663
|
+
if (projectDatasources.length > 0) {
|
|
40664
|
+
sections.push(`#### Datasources (${projectDatasources.length})`, "");
|
|
40665
|
+
for (const ds of projectDatasources.slice(0, 25)) {
|
|
40666
|
+
sections.push(`- ${ds.name ?? ds.id ?? "(unknown)"}`);
|
|
40667
|
+
}
|
|
40668
|
+
sections.push("");
|
|
39435
40669
|
}
|
|
39436
|
-
|
|
39437
|
-
|
|
40670
|
+
}
|
|
40671
|
+
if (allDiscoveredColumns.length > 0) {
|
|
40672
|
+
const unique = [...new Set(allDiscoveredColumns.map((c) => c.toLowerCase()))];
|
|
40673
|
+
const themes = [];
|
|
40674
|
+
const hasPattern = (keywords) => unique.some((c) => keywords.some((k) => c.includes(k)));
|
|
40675
|
+
if (hasPattern(["revenue", "sales", "amount", "price", "cost", "profit", "\u58F2\u4E0A", "\u91D1\u984D", "\u5229\u76CA"]))
|
|
40676
|
+
themes.push("Revenue & profitability analysis (trends, breakdown by segment)");
|
|
40677
|
+
if (hasPattern(["date", "month", "year", "quarter", "day", "\u65E5\u4ED8", "\u6708", "\u5E74", "\u671F"]))
|
|
40678
|
+
themes.push("Time-series trend analysis (YoY, MoM comparisons)");
|
|
40679
|
+
if (hasPattern(["region", "country", "city", "state", "\u5730\u57DF", "\u56FD", "\u90FD\u5E02", "\u5E02"]))
|
|
40680
|
+
themes.push("Geographic/regional performance comparison");
|
|
40681
|
+
if (hasPattern(["product", "category", "item", "sku", "\u5546\u54C1", "\u30AB\u30C6\u30B4\u30EA"]))
|
|
40682
|
+
themes.push("Product/category mix analysis");
|
|
40683
|
+
if (hasPattern(["customer", "user", "account", "\u9867\u5BA2", "\u30E6\u30FC\u30B6\u30FC"]))
|
|
40684
|
+
themes.push("Customer segmentation and behavior analysis");
|
|
40685
|
+
if (hasPattern(["quantity", "count", "volume", "\u6570\u91CF", "\u4EF6\u6570"]))
|
|
40686
|
+
themes.push("Volume and demand pattern analysis");
|
|
40687
|
+
if (hasPattern(["rate", "ratio", "percentage", "%", "\u7387"]))
|
|
40688
|
+
themes.push("KPI ratio tracking and benchmarking");
|
|
40689
|
+
if (themes.length > 0) {
|
|
40690
|
+
sections.push("### Suggested Analysis Themes", "");
|
|
40691
|
+
for (const theme of themes) {
|
|
40692
|
+
sections.push(`- ${theme}`);
|
|
40693
|
+
}
|
|
40694
|
+
sections.push("");
|
|
39438
40695
|
}
|
|
39439
|
-
sections.push("");
|
|
39440
40696
|
}
|
|
39441
40697
|
return sections.join("\n");
|
|
39442
40698
|
}
|
|
@@ -39446,27 +40702,36 @@ var tableauSetupFlow = {
|
|
|
39446
40702
|
import { z as z98 } from "zod";
|
|
39447
40703
|
var DEFAULT_API_VERSION2 = "3.28";
|
|
39448
40704
|
var REQUEST_TIMEOUT_MS75 = 6e4;
|
|
39449
|
-
|
|
39450
|
-
|
|
39451
|
-
|
|
39452
|
-
|
|
39453
|
-
throw new Error(
|
|
39454
|
-
"Tableau session manager is not configured. Missing INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL or INTERNAL_SQUADBASE_SANDBOX_ID."
|
|
39455
|
-
);
|
|
40705
|
+
var cachedToken33 = null;
|
|
40706
|
+
async function getProxyToken33(config) {
|
|
40707
|
+
if (cachedToken33 && cachedToken33.expiresAt > Date.now() + 6e4) {
|
|
40708
|
+
return cachedToken33.token;
|
|
39456
40709
|
}
|
|
39457
|
-
const
|
|
39458
|
-
const url = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
40710
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
39459
40711
|
const res = await fetch(url, {
|
|
39460
40712
|
method: "POST",
|
|
39461
|
-
headers: {
|
|
40713
|
+
headers: {
|
|
40714
|
+
"Content-Type": "application/json",
|
|
40715
|
+
"x-api-key": config.appApiKey,
|
|
40716
|
+
"project-id": config.projectId
|
|
40717
|
+
},
|
|
40718
|
+
body: JSON.stringify({
|
|
40719
|
+
sandboxId: config.sandboxId,
|
|
40720
|
+
issuedBy: "coding-agent"
|
|
40721
|
+
})
|
|
39462
40722
|
});
|
|
39463
40723
|
if (!res.ok) {
|
|
39464
|
-
const
|
|
40724
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
39465
40725
|
throw new Error(
|
|
39466
|
-
`Failed to
|
|
40726
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
39467
40727
|
);
|
|
39468
40728
|
}
|
|
39469
|
-
|
|
40729
|
+
const data = await res.json();
|
|
40730
|
+
cachedToken33 = {
|
|
40731
|
+
token: data.token,
|
|
40732
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
40733
|
+
};
|
|
40734
|
+
return data.token;
|
|
39470
40735
|
}
|
|
39471
40736
|
function buildBaseUrl7(serverUrl, apiVersion) {
|
|
39472
40737
|
return `${serverUrl.replace(/\/$/, "")}/api/${apiVersion}`;
|
|
@@ -39508,7 +40773,7 @@ All paths are relative to {serverUrl}/api/{apiVersion}. Use the literal placehol
|
|
|
39508
40773
|
Accept and Content-Type headers default to application/json so list responses come back as JSON instead of Tableau's default XML.`,
|
|
39509
40774
|
inputSchema: inputSchema98,
|
|
39510
40775
|
outputSchema: outputSchema98,
|
|
39511
|
-
async execute({ connectionId, method, path: path5, queryParams, body }, connections) {
|
|
40776
|
+
async execute({ connectionId, method, path: path5, queryParams, body }, connections, config) {
|
|
39512
40777
|
const connection = connections.find((c) => c.id === connectionId);
|
|
39513
40778
|
if (!connection) {
|
|
39514
40779
|
return {
|
|
@@ -39523,50 +40788,42 @@ Accept and Content-Type headers default to application/json so list responses co
|
|
|
39523
40788
|
const serverUrl = parameters81.serverUrl.getValue(connection);
|
|
39524
40789
|
const apiVersion = parameters81.apiVersion.tryGetValue(connection) || DEFAULT_API_VERSION2;
|
|
39525
40790
|
const trimmedPath = path5.trim().replace(/^([^/])/, "/$1");
|
|
39526
|
-
const queryString = queryParams ? `?${new URLSearchParams(queryParams).toString()}` : "";
|
|
39527
40791
|
const baseUrl = buildBaseUrl7(serverUrl, apiVersion);
|
|
40792
|
+
let url = `${baseUrl}${trimmedPath}`;
|
|
40793
|
+
if (queryParams) {
|
|
40794
|
+
url += `?${new URLSearchParams(queryParams).toString()}`;
|
|
40795
|
+
}
|
|
40796
|
+
const token = await getProxyToken33(config.oauthProxy);
|
|
40797
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
39528
40798
|
const controller = new AbortController();
|
|
39529
40799
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS75);
|
|
39530
40800
|
try {
|
|
39531
|
-
|
|
39532
|
-
|
|
39533
|
-
|
|
39534
|
-
|
|
39535
|
-
|
|
39536
|
-
|
|
39537
|
-
|
|
39538
|
-
|
|
39539
|
-
const init = {
|
|
40801
|
+
const response = await fetch(proxyUrl, {
|
|
40802
|
+
method: "POST",
|
|
40803
|
+
headers: {
|
|
40804
|
+
"Content-Type": "application/json",
|
|
40805
|
+
Authorization: `Bearer ${token}`
|
|
40806
|
+
},
|
|
40807
|
+
body: JSON.stringify({
|
|
40808
|
+
url,
|
|
39540
40809
|
method,
|
|
39541
|
-
|
|
39542
|
-
|
|
39543
|
-
|
|
39544
|
-
|
|
39545
|
-
|
|
39546
|
-
|
|
39547
|
-
|
|
39548
|
-
|
|
39549
|
-
|
|
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 };
|
|
40810
|
+
...body !== void 0 ? { body } : {}
|
|
40811
|
+
}),
|
|
40812
|
+
signal: controller.signal
|
|
40813
|
+
});
|
|
40814
|
+
const text = await response.text();
|
|
40815
|
+
const data = text ? (() => {
|
|
40816
|
+
try {
|
|
40817
|
+
return JSON.parse(text);
|
|
40818
|
+
} catch {
|
|
40819
|
+
return text;
|
|
39567
40820
|
}
|
|
39568
|
-
|
|
40821
|
+
})() : null;
|
|
40822
|
+
if (!response.ok) {
|
|
40823
|
+
const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
|
|
40824
|
+
return { success: false, error: errorMessage };
|
|
39569
40825
|
}
|
|
40826
|
+
return { success: true, status: response.status, data };
|
|
39570
40827
|
} finally {
|
|
39571
40828
|
clearTimeout(timeout);
|
|
39572
40829
|
}
|
|
@@ -39758,12 +41015,12 @@ export default async function handler(c: Context) {
|
|
|
39758
41015
|
import { z as z99 } from "zod";
|
|
39759
41016
|
var BASE_HOST13 = "https://graph.microsoft.com";
|
|
39760
41017
|
var BASE_PATH_SEGMENT19 = "/v1.0";
|
|
39761
|
-
var
|
|
41018
|
+
var BASE_URL66 = `${BASE_HOST13}${BASE_PATH_SEGMENT19}`;
|
|
39762
41019
|
var REQUEST_TIMEOUT_MS76 = 6e4;
|
|
39763
|
-
var
|
|
39764
|
-
async function
|
|
39765
|
-
if (
|
|
39766
|
-
return
|
|
41020
|
+
var cachedToken34 = null;
|
|
41021
|
+
async function getProxyToken34(config) {
|
|
41022
|
+
if (cachedToken34 && cachedToken34.expiresAt > Date.now() + 6e4) {
|
|
41023
|
+
return cachedToken34.token;
|
|
39767
41024
|
}
|
|
39768
41025
|
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
39769
41026
|
const res = await fetch(url, {
|
|
@@ -39785,7 +41042,7 @@ async function getProxyToken33(config) {
|
|
|
39785
41042
|
);
|
|
39786
41043
|
}
|
|
39787
41044
|
const data = await res.json();
|
|
39788
|
-
|
|
41045
|
+
cachedToken34 = {
|
|
39789
41046
|
token: data.token,
|
|
39790
41047
|
expiresAt: new Date(data.expiresAt).getTime()
|
|
39791
41048
|
};
|
|
@@ -39837,12 +41094,12 @@ For full-text search use the \`$search\` query parameter (must be wrapped in dou
|
|
|
39837
41094
|
);
|
|
39838
41095
|
try {
|
|
39839
41096
|
const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT19);
|
|
39840
|
-
let url = `${
|
|
41097
|
+
let url = `${BASE_URL66}${normalizedPath}`;
|
|
39841
41098
|
if (queryParams) {
|
|
39842
41099
|
const searchParams = new URLSearchParams(queryParams);
|
|
39843
41100
|
url += `?${searchParams.toString()}`;
|
|
39844
41101
|
}
|
|
39845
|
-
const token = await
|
|
41102
|
+
const token = await getProxyToken34(config.oauthProxy);
|
|
39846
41103
|
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
39847
41104
|
const controller = new AbortController();
|
|
39848
41105
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS76);
|