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