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