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