@squadbase/vite-server 0.1.10-dev.5aa0720 → 0.1.10-dev.5b0c0a8
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 +775 -89268
- package/dist/connectors/azure-sql.js +1 -20213
- package/dist/connectors/cosmosdb.js +6 -6
- package/dist/connectors/google-ads.js +196 -120
- package/dist/connectors/jdbc.js +54 -20224
- package/dist/connectors/mongodb.d.ts +5 -0
- package/dist/connectors/mongodb.js +879 -0
- package/dist/connectors/oracle.js +10 -20215
- package/dist/connectors/sqlserver.js +1 -20213
- package/dist/index.js +844 -89347
- package/dist/main.js +829 -89332
- package/dist/vite-plugin.js +724 -89227
- package/package.json +8 -2
- package/dist/cli/cpufeatures-ORCDQN2Y.node +0 -0
- package/dist/cli/sshcrypto-P3UBA7BP.node +0 -0
- package/dist/cpufeatures-ORCDQN2Y.node +0 -0
- package/dist/sshcrypto-P3UBA7BP.node +0 -0
|
@@ -109,7 +109,7 @@ function createClient(params) {
|
|
|
109
109
|
queryOptions.partitionKey = options.partitionKey;
|
|
110
110
|
}
|
|
111
111
|
const iterator = cont.items.query(sql, queryOptions);
|
|
112
|
-
const { resources } = await iterator.
|
|
112
|
+
const { resources } = await iterator.fetchAll();
|
|
113
113
|
return resources ?? [];
|
|
114
114
|
} catch (err) {
|
|
115
115
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -445,7 +445,7 @@ Use \`TOP n\` (not \`LIMIT n\`) to bound the result. Cross-partition queries are
|
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
447
|
const iterator = cont.items.query(sql, queryOptions);
|
|
448
|
-
const { resources, requestCharge } = await iterator.
|
|
448
|
+
const { resources, requestCharge } = await iterator.fetchAll();
|
|
449
449
|
const documents = resources ?? [];
|
|
450
450
|
const truncated = documents.length > MAX_DOCUMENTS;
|
|
451
451
|
return {
|
|
@@ -486,7 +486,7 @@ var cosmosdbConnector = new ConnectorPlugin({
|
|
|
486
486
|
|
|
487
487
|
### Business Logic
|
|
488
488
|
|
|
489
|
-
The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables.
|
|
489
|
+
The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables, and do NOT \`import { CosmosClient } from "@azure/cosmos"\` in handler code \u2014 the \`@azure/cosmos\` driver is not part of the user dashboard's runtime, only of the connector SDK.
|
|
490
490
|
|
|
491
491
|
\u26A0\uFE0F **The client returned by \`connection(connectionId)\` is NOT the raw \`@azure/cosmos\` \`CosmosClient\`.** It is a thin wrapper exposing only two methods:
|
|
492
492
|
- \`client.query<T>(container, sql, options?) => Promise<T[]>\` \u2014 runs a Cosmos SQL query against the named container and returns the **already-unwrapped** items array (no \`{ resources }\` wrapper). \`options\` accepts \`{ maxItemCount?: number; partitionKey?: unknown }\`.
|
|
@@ -522,7 +522,7 @@ export default async function handler(_c: Context) {
|
|
|
522
522
|
- Queries always target a single container and reference items via the alias \`c\` (e.g. \`SELECT c.id, c.name FROM c WHERE c.status = 'active'\`).
|
|
523
523
|
- Row limiting: use \`TOP n\` (e.g. \`SELECT TOP 100 * FROM c\`). \`LIMIT\` is **not** supported. \`OFFSET m LIMIT n\` is supported on newer accounts but \`TOP\` is the safe default.
|
|
524
524
|
- System fields are prefixed with an underscore (\`c.id\`, \`c._ts\` for the modification timestamp, \`c._etag\`).
|
|
525
|
-
- Aggregates: \`COUNT(1)\`, \`SUM\`, \`AVG\`, \`MIN\`, \`MAX\`, with \`GROUP BY\` (e.g. \`SELECT c.country, COUNT(1) AS n FROM c GROUP BY c.country\`).
|
|
525
|
+
- Aggregates: \`COUNT(1)\`, \`SUM\`, \`AVG\`, \`MIN\`, \`MAX\`, with \`GROUP BY\` (e.g. \`SELECT c.country, COUNT(1) AS n FROM c GROUP BY c.country\`). Cross-partition \`GROUP BY\` is fully supported \u2014 the connector drains all result pages internally, so trust the returned rows even for queries that span many partitions. Do **not** work around perceived missing rows by re-fetching all items and aggregating in TypeScript.
|
|
526
526
|
- Joins: only **intra-document** joins via \`JOIN\` over arrays inside the same item; there is no cross-container/cross-document join.
|
|
527
527
|
- Always bound results with \`TOP n\` and prefer scoped queries with a \`partitionKey\` value when possible \u2014 cross-partition queries cost more RUs.`,
|
|
528
528
|
ja: `### \u30C4\u30FC\u30EB
|
|
@@ -532,7 +532,7 @@ export default async function handler(_c: Context) {
|
|
|
532
532
|
|
|
533
533
|
### Business Logic
|
|
534
534
|
|
|
535
|
-
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
535
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u305F\u308A\u3001\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3067 \`import { CosmosClient } from "@azure/cosmos"\` \u3092\u884C\u3063\u305F\u308A\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044 \u2014 \`@azure/cosmos\` \u30C9\u30E9\u30A4\u30D0\u306F\u30E6\u30FC\u30B6\u30FC\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u306E\u30E9\u30F3\u30BF\u30A4\u30E0\u306B\u306F\u542B\u307E\u308C\u305A\u3001\u30B3\u30CD\u30AF\u30BFSDK\u5185\u90E8\u306B\u306E\u307F\u5B58\u5728\u3057\u307E\u3059\u3002
|
|
536
536
|
|
|
537
537
|
\u26A0\uFE0F **\`connection(connectionId)\` \u304C\u8FD4\u3059\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u306F \`@azure/cosmos\` \u306E \`CosmosClient\` \u305D\u306E\u3082\u306E\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002** \u4EE5\u4E0B\u306E2\u30E1\u30BD\u30C3\u30C9\u306E\u307F\u3092\u516C\u958B\u3059\u308B\u8584\u3044\u30E9\u30C3\u30D1\u30FC\u3067\u3059\uFF1A
|
|
538
538
|
- \`client.query<T>(container, sql, options?) => Promise<T[]>\` \u2014 \u6307\u5B9A\u30B3\u30F3\u30C6\u30CA\u306B\u5BFE\u3057\u3066 Cosmos SQL \u3092\u5B9F\u884C\u3057\u3001**\u3059\u3067\u306B\u5C55\u958B\u6E08\u307F\u306E\u30A2\u30A4\u30C6\u30E0\u914D\u5217**\u3092\u8FD4\u3059\uFF08\`{ resources }\` \u3067\u30E9\u30C3\u30D7\u3055\u308C\u3066\u3044\u306A\u3044\uFF09\u3002\`options\` \u306F \`{ maxItemCount?: number; partitionKey?: unknown }\`\u3002
|
|
@@ -568,7 +568,7 @@ export default async function handler(_c: Context) {
|
|
|
568
568
|
- \u30AF\u30A8\u30EA\u306F\u5E38\u306B\u5358\u4E00\u30B3\u30F3\u30C6\u30CA\u3092\u5BFE\u8C61\u3068\u3057\u3001\u30A2\u30A4\u30C6\u30E0\u306F\u5225\u540D \`c\` \u3067\u53C2\u7167\u3057\u307E\u3059\uFF08\u4F8B: \`SELECT c.id, c.name FROM c WHERE c.status = 'active'\`\uFF09\u3002
|
|
569
569
|
- \u884C\u6570\u5236\u9650: \`TOP n\` \u3092\u4F7F\u7528\u3057\u307E\u3059\uFF08\u4F8B: \`SELECT TOP 100 * FROM c\`\uFF09\u3002\`LIMIT\` \u306F **\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093**\u3002\u65B0\u3057\u3044\u30A2\u30AB\u30A6\u30F3\u30C8\u3067\u306F \`OFFSET m LIMIT n\` \u304C\u4F7F\u3048\u307E\u3059\u304C\u3001\u5B89\u5168\u5074\u306E\u65E2\u5B9A\u306F \`TOP\` \u3067\u3059\u3002
|
|
570
570
|
- \u30B7\u30B9\u30C6\u30E0\u30D5\u30A3\u30FC\u30EB\u30C9\u306F\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u59CB\u307E\u308A\uFF08\`c.id\`\u3001\u5909\u66F4\u6642\u523B\u306E \`c._ts\`\u3001\`c._etag\`\uFF09\u3002
|
|
571
|
-
- \u96C6\u7D04: \`COUNT(1)\`\u3001\`SUM\`\u3001\`AVG\`\u3001\`MIN\`\u3001\`MAX\` \u3092 \`GROUP BY\` \u3068\u7D44\u307F\u5408\u308F\u305B\u307E\u3059\uFF08\u4F8B: \`SELECT c.country, COUNT(1) AS n FROM c GROUP BY c.country\`\uFF09\u3002
|
|
571
|
+
- \u96C6\u7D04: \`COUNT(1)\`\u3001\`SUM\`\u3001\`AVG\`\u3001\`MIN\`\u3001\`MAX\` \u3092 \`GROUP BY\` \u3068\u7D44\u307F\u5408\u308F\u305B\u307E\u3059\uFF08\u4F8B: \`SELECT c.country, COUNT(1) AS n FROM c GROUP BY c.country\`\uFF09\u3002\u30AF\u30ED\u30B9\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u306E \`GROUP BY\` \u3082\u5B8C\u5168\u306B\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u304A\u308A\u3001\u30B3\u30CD\u30AF\u30BF\u304C\u5185\u90E8\u3067\u5168\u7D50\u679C\u30DA\u30FC\u30B8\u3092\u30C9\u30EC\u30A4\u30F3\u3059\u308B\u305F\u3081\u3001\u591A\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u306B\u307E\u305F\u304C\u308B\u30AF\u30A8\u30EA\u3067\u3082\u8FD4\u3063\u3066\u304D\u305F\u884C\u6570\u3092\u305D\u306E\u307E\u307E\u4FE1\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002**\u300C\u7D50\u679C\u304C\u6B20\u3051\u3066\u3044\u308B\u3088\u3046\u306B\u898B\u3048\u308B\u300D\u304B\u3089\u3068\u3044\u3063\u3066\u5168\u4EF6\u53D6\u5F97\u2192TS \u5074\u3067\u96C6\u8A08\u3059\u308B\u8FC2\u56DE\u306F\u3057\u306A\u3044\u3053\u3068\u3002**
|
|
572
572
|
- \u7D50\u5408: \u540C\u4E00\u30A2\u30A4\u30C6\u30E0\u5185\u306E\u914D\u5217\u306B\u5BFE\u3059\u308B **\u30A4\u30F3\u30C8\u30E9\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8** \`JOIN\` \u306E\u307F\u3067\u3001\u30B3\u30F3\u30C6\u30CA\u9593\uFF0F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u9593\u306E\u7D50\u5408\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u307E\u305B\u3093\u3002
|
|
573
573
|
- \u7D50\u679C\u4EF6\u6570\u306F\u5FC5\u305A \`TOP n\` \u3067\u5236\u9650\u3057\u3001\u53EF\u80FD\u3067\u3042\u308C\u3070 \`partitionKey\` \u3067\u5358\u4E00\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u306B\u30B9\u30B3\u30FC\u30D7\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u30AF\u30ED\u30B9\u30D1\u30FC\u30C6\u30A3\u30B7\u30E7\u30F3\u30AF\u30A8\u30EA\u306F RU \u3092\u591A\u304F\u6D88\u8CBB\u3057\u307E\u3059\uFF09\u3002`
|
|
574
574
|
},
|
|
@@ -42,6 +42,39 @@ var ParameterDefinition = class {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
// ../connectors/src/connectors/google-ads/constants.ts
|
|
46
|
+
var VERSION_FALLBACK_ORDER = ["v22", "v23", "v24"];
|
|
47
|
+
var cachedWorkingVersion = VERSION_FALLBACK_ORDER[0];
|
|
48
|
+
var looksSunset = (contentType) => {
|
|
49
|
+
return contentType != null && contentType.toLowerCase().includes("text/html");
|
|
50
|
+
};
|
|
51
|
+
async function fetchGoogleAdsWithVersionFallback(attempt) {
|
|
52
|
+
const order = [
|
|
53
|
+
cachedWorkingVersion,
|
|
54
|
+
...VERSION_FALLBACK_ORDER.filter((v) => v !== cachedWorkingVersion)
|
|
55
|
+
];
|
|
56
|
+
let lastResponse = null;
|
|
57
|
+
for (let i = 0; i < order.length; i++) {
|
|
58
|
+
const version = order[i];
|
|
59
|
+
const baseUrl = `https://googleads.googleapis.com/${version}/`;
|
|
60
|
+
const response = await attempt(baseUrl);
|
|
61
|
+
const contentType = response.headers.get("content-type");
|
|
62
|
+
if (looksSunset(contentType) && i < order.length - 1) {
|
|
63
|
+
console.warn(
|
|
64
|
+
`[google-ads] version ${version} returned a sunset/HTML response (status ${response.status}); retrying with newer version`
|
|
65
|
+
);
|
|
66
|
+
lastResponse = response;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
cachedWorkingVersion = version;
|
|
70
|
+
return response;
|
|
71
|
+
}
|
|
72
|
+
return lastResponse ?? new Response(null, {
|
|
73
|
+
status: 502,
|
|
74
|
+
statusText: "All Google Ads API versions returned sunset responses"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
45
78
|
// ../connectors/src/connectors/google-ads/parameters.ts
|
|
46
79
|
var parameters = {
|
|
47
80
|
customerId: new ParameterDefinition({
|
|
@@ -52,29 +85,13 @@ var parameters = {
|
|
|
52
85
|
type: "text",
|
|
53
86
|
secret: false,
|
|
54
87
|
required: false
|
|
55
|
-
}),
|
|
56
|
-
developerToken: new ParameterDefinition({
|
|
57
|
-
slug: "developer-token",
|
|
58
|
-
name: "Google Ads Developer Token",
|
|
59
|
-
description: "The developer token for accessing the Google Ads API. Required for all API requests.",
|
|
60
|
-
envVarBaseKey: "GOOGLE_ADS_DEVELOPER_TOKEN",
|
|
61
|
-
type: "text",
|
|
62
|
-
secret: true,
|
|
63
|
-
required: true
|
|
64
88
|
})
|
|
65
89
|
};
|
|
66
90
|
|
|
67
91
|
// ../connectors/src/connectors/google-ads/sdk/index.ts
|
|
68
|
-
var BASE_URL = "https://googleads.googleapis.com/v18/";
|
|
69
92
|
function createClient(params, fetchFn = fetch) {
|
|
70
93
|
const rawCustomerId = params[parameters.customerId.slug];
|
|
71
94
|
const defaultCustomerId = rawCustomerId?.replace(/-/g, "") ?? "";
|
|
72
|
-
const developerToken = params[parameters.developerToken.slug];
|
|
73
|
-
if (!developerToken) {
|
|
74
|
-
throw new Error(
|
|
75
|
-
`google-ads: missing required parameter: ${parameters.developerToken.slug}`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
95
|
function resolveCustomerId(override) {
|
|
79
96
|
const id = override?.replace(/-/g, "") ?? defaultCustomerId;
|
|
80
97
|
if (!id) {
|
|
@@ -86,26 +103,26 @@ function createClient(params, fetchFn = fetch) {
|
|
|
86
103
|
}
|
|
87
104
|
function request(path2, init) {
|
|
88
105
|
const resolvedPath = defaultCustomerId ? path2.replace(/\{customerId\}/g, defaultCustomerId) : path2;
|
|
89
|
-
const url = `${BASE_URL}${resolvedPath}`;
|
|
90
106
|
const headers = new Headers(init?.headers);
|
|
91
|
-
headers.set("developer-token", developerToken);
|
|
92
107
|
if (defaultCustomerId) {
|
|
93
108
|
headers.set("login-customer-id", defaultCustomerId);
|
|
94
109
|
}
|
|
95
|
-
return
|
|
110
|
+
return fetchGoogleAdsWithVersionFallback(
|
|
111
|
+
(baseUrl) => fetchFn(`${baseUrl}${resolvedPath}`, { ...init, headers })
|
|
112
|
+
);
|
|
96
113
|
}
|
|
97
114
|
async function search(query, customerId) {
|
|
98
115
|
const cid = resolveCustomerId(customerId);
|
|
99
|
-
const url = `${BASE_URL}customers/${cid}/googleAds:searchStream`;
|
|
100
116
|
const headers = new Headers();
|
|
101
117
|
headers.set("Content-Type", "application/json");
|
|
102
|
-
headers.set("developer-token", developerToken);
|
|
103
118
|
headers.set("login-customer-id", cid);
|
|
104
|
-
const response = await
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
const response = await fetchGoogleAdsWithVersionFallback(
|
|
120
|
+
(baseUrl) => fetchFn(`${baseUrl}customers/${cid}/googleAds:searchStream`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers,
|
|
123
|
+
body: JSON.stringify({ query })
|
|
124
|
+
})
|
|
125
|
+
);
|
|
109
126
|
if (!response.ok) {
|
|
110
127
|
const body = await response.text();
|
|
111
128
|
throw new Error(
|
|
@@ -116,10 +133,9 @@ function createClient(params, fetchFn = fetch) {
|
|
|
116
133
|
return data.flatMap((chunk) => chunk.results ?? []);
|
|
117
134
|
}
|
|
118
135
|
async function listAccessibleCustomers() {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const response = await fetchFn(url, { method: "GET", headers });
|
|
136
|
+
const response = await fetchGoogleAdsWithVersionFallback(
|
|
137
|
+
(baseUrl) => fetchFn(`${baseUrl}customers:listAccessibleCustomers`, { method: "GET" })
|
|
138
|
+
);
|
|
123
139
|
if (!response.ok) {
|
|
124
140
|
const body = await response.text();
|
|
125
141
|
throw new Error(
|
|
@@ -289,7 +305,65 @@ var AUTH_TYPES = {
|
|
|
289
305
|
|
|
290
306
|
// ../connectors/src/connectors/google-ads/tools/list-customers.ts
|
|
291
307
|
import { z } from "zod";
|
|
292
|
-
|
|
308
|
+
|
|
309
|
+
// ../connectors/src/connectors/google-ads/error.ts
|
|
310
|
+
var parseJsonOrNull = (text) => {
|
|
311
|
+
if (text.length === 0) return null;
|
|
312
|
+
try {
|
|
313
|
+
return JSON.parse(text);
|
|
314
|
+
} catch {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
319
|
+
var collectGoogleAdsErrorCodes = (details) => {
|
|
320
|
+
if (!Array.isArray(details)) return [];
|
|
321
|
+
const codes = [];
|
|
322
|
+
for (const detail of details) {
|
|
323
|
+
if (!isRecord(detail)) continue;
|
|
324
|
+
const errors = detail.errors;
|
|
325
|
+
if (!Array.isArray(errors)) continue;
|
|
326
|
+
for (const e of errors) {
|
|
327
|
+
if (!isRecord(e)) continue;
|
|
328
|
+
const errorCode = e.errorCode;
|
|
329
|
+
if (!isRecord(errorCode)) continue;
|
|
330
|
+
for (const [k, v] of Object.entries(errorCode)) {
|
|
331
|
+
if (typeof v === "string") codes.push(`${k}=${v}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return codes;
|
|
336
|
+
};
|
|
337
|
+
var extractGoogleAdsErrorMessage = (status, statusText, parsedBody, rawText) => {
|
|
338
|
+
const fallback = `HTTP ${status} ${statusText}`;
|
|
339
|
+
if (isRecord(parsedBody)) {
|
|
340
|
+
const errorField = parsedBody.error;
|
|
341
|
+
if (typeof errorField === "string") return errorField;
|
|
342
|
+
if (isRecord(errorField)) {
|
|
343
|
+
const message = typeof errorField.message === "string" ? errorField.message : null;
|
|
344
|
+
const errorStatus = typeof errorField.status === "string" ? errorField.status : null;
|
|
345
|
+
const codes = collectGoogleAdsErrorCodes(errorField.details);
|
|
346
|
+
const parts = [
|
|
347
|
+
fallback,
|
|
348
|
+
errorStatus,
|
|
349
|
+
message,
|
|
350
|
+
codes.length > 0 ? `[${codes.join(", ")}]` : null
|
|
351
|
+
].filter((p) => p != null && p.length > 0);
|
|
352
|
+
if (parts.length > 1) return parts.join(": ");
|
|
353
|
+
}
|
|
354
|
+
if (typeof parsedBody.message === "string") {
|
|
355
|
+
return `${fallback}: ${parsedBody.message}`;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (rawText.length > 0) {
|
|
359
|
+
const trimmed = rawText.trim();
|
|
360
|
+
const preview = trimmed.length > 500 ? `${trimmed.slice(0, 500)}\u2026` : trimmed;
|
|
361
|
+
return `${fallback}: ${preview}`;
|
|
362
|
+
}
|
|
363
|
+
return fallback;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// ../connectors/src/connectors/google-ads/tools/list-customers.ts
|
|
293
367
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
294
368
|
var cachedToken = null;
|
|
295
369
|
async function getProxyToken(config) {
|
|
@@ -360,58 +434,65 @@ var listCustomersTool = new ConnectorTool({
|
|
|
360
434
|
`[connector-request] google-ads/${connection2.name}: listCustomers`
|
|
361
435
|
);
|
|
362
436
|
try {
|
|
363
|
-
const developerToken = parameters.developerToken.getValue(connection2);
|
|
364
437
|
const token = await getProxyToken(config.oauthProxy);
|
|
365
438
|
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
366
439
|
const controller = new AbortController();
|
|
367
440
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
368
441
|
try {
|
|
369
|
-
const response = await
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
"Content-Type": "application/json",
|
|
373
|
-
Authorization: `Bearer ${token}`
|
|
374
|
-
},
|
|
375
|
-
body: JSON.stringify({
|
|
376
|
-
url: `${BASE_URL2}customers:listAccessibleCustomers`,
|
|
377
|
-
method: "GET",
|
|
442
|
+
const response = await fetchGoogleAdsWithVersionFallback(
|
|
443
|
+
(baseUrl) => fetch(proxyUrl, {
|
|
444
|
+
method: "POST",
|
|
378
445
|
headers: {
|
|
379
|
-
"
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
446
|
+
"Content-Type": "application/json",
|
|
447
|
+
Authorization: `Bearer ${token}`
|
|
448
|
+
},
|
|
449
|
+
body: JSON.stringify({
|
|
450
|
+
url: `${baseUrl}customers:listAccessibleCustomers`,
|
|
451
|
+
method: "GET"
|
|
452
|
+
}),
|
|
453
|
+
signal: controller.signal
|
|
454
|
+
})
|
|
455
|
+
);
|
|
456
|
+
const rawText = await response.text();
|
|
457
|
+
const data = parseJsonOrNull(rawText);
|
|
385
458
|
if (!response.ok) {
|
|
386
|
-
|
|
387
|
-
|
|
459
|
+
return {
|
|
460
|
+
success: false,
|
|
461
|
+
error: extractGoogleAdsErrorMessage(
|
|
462
|
+
response.status,
|
|
463
|
+
response.statusText,
|
|
464
|
+
data,
|
|
465
|
+
rawText
|
|
466
|
+
)
|
|
467
|
+
};
|
|
388
468
|
}
|
|
389
|
-
const customerIds = (data
|
|
469
|
+
const customerIds = (data?.resourceNames ?? []).map(
|
|
390
470
|
(rn) => rn.replace(/^customers\//, "")
|
|
391
471
|
);
|
|
392
472
|
const customers = [];
|
|
393
473
|
for (const cid of customerIds) {
|
|
394
474
|
try {
|
|
395
|
-
const detailResponse = await
|
|
396
|
-
|
|
397
|
-
headers: {
|
|
398
|
-
"Content-Type": "application/json",
|
|
399
|
-
Authorization: `Bearer ${token}`
|
|
400
|
-
},
|
|
401
|
-
body: JSON.stringify({
|
|
402
|
-
url: `${BASE_URL2}customers/${cid}/googleAds:searchStream`,
|
|
475
|
+
const detailResponse = await fetchGoogleAdsWithVersionFallback(
|
|
476
|
+
(baseUrl) => fetch(proxyUrl, {
|
|
403
477
|
method: "POST",
|
|
404
478
|
headers: {
|
|
405
479
|
"Content-Type": "application/json",
|
|
406
|
-
|
|
407
|
-
"login-customer-id": cid
|
|
480
|
+
Authorization: `Bearer ${token}`
|
|
408
481
|
},
|
|
409
482
|
body: JSON.stringify({
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
483
|
+
url: `${baseUrl}customers/${cid}/googleAds:searchStream`,
|
|
484
|
+
method: "POST",
|
|
485
|
+
headers: {
|
|
486
|
+
"Content-Type": "application/json",
|
|
487
|
+
"login-customer-id": cid
|
|
488
|
+
},
|
|
489
|
+
body: JSON.stringify({
|
|
490
|
+
query: "SELECT customer.id, customer.descriptive_name FROM customer LIMIT 1"
|
|
491
|
+
})
|
|
492
|
+
}),
|
|
493
|
+
signal: controller.signal
|
|
494
|
+
})
|
|
495
|
+
);
|
|
415
496
|
if (detailResponse.ok) {
|
|
416
497
|
const detailData = await detailResponse.json();
|
|
417
498
|
const customer = detailData?.[0]?.results?.[0]?.customer;
|
|
@@ -449,30 +530,24 @@ var googleAdsOnboarding = new ConnectorOnboarding({
|
|
|
449
530
|
connectionSetupInstructions: {
|
|
450
531
|
ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Ads (OAuth) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
|
|
451
532
|
|
|
452
|
-
1. \
|
|
533
|
+
1. \`${listCustomersToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Ads\u30AB\u30B9\u30BF\u30DE\u30FC\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
|
|
453
534
|
2. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
454
|
-
- \`parameterSlug\`: \`"developer-token"\`
|
|
455
|
-
- \`value\`: \u30E6\u30FC\u30B6\u30FC\u304C\u63D0\u4F9B\u3057\u305F Developer Token
|
|
456
|
-
3. \`${listCustomersToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Ads\u30AB\u30B9\u30BF\u30DE\u30FC\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
|
|
457
|
-
4. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
458
535
|
- \`parameterSlug\`: \`"customer-id"\`
|
|
459
536
|
- \`options\`: \u30AB\u30B9\u30BF\u30DE\u30FC\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30A2\u30AB\u30A6\u30F3\u30C8\u540D (id: \u30AB\u30B9\u30BF\u30DE\u30FCID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30AB\u30B9\u30BF\u30DE\u30FCID
|
|
460
|
-
|
|
537
|
+
- \u30AB\u30B9\u30BF\u30DE\u30FC\u304C **0\u4EF6** \u306E\u5834\u5408\u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u4E2D\u65AD\u3057\u3001\u30E6\u30FC\u30B6\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u306A\u3044\u65E8\u3092\u4F1D\u3048\u308B
|
|
538
|
+
3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30AB\u30B9\u30BF\u30DE\u30FC\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u306E\u3067\u3001\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080
|
|
461
539
|
|
|
462
540
|
#### \u5236\u7D04
|
|
463
541
|
- **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30EC\u30DD\u30FC\u30C8\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u306E\u307F
|
|
464
542
|
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u3002\u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
|
|
465
543
|
en: `Follow these steps to set up the Google Ads (OAuth) connection.
|
|
466
544
|
|
|
467
|
-
1.
|
|
545
|
+
1. Call \`${listCustomersToolName}\` to get the list of Google Ads customer accounts accessible with the OAuth credentials
|
|
468
546
|
2. Call \`updateConnectionParameters\`:
|
|
469
|
-
- \`parameterSlug\`: \`"developer-token"\`
|
|
470
|
-
- \`value\`: The Developer Token provided by the user
|
|
471
|
-
3. Call \`${listCustomersToolName}\` to get the list of Google Ads customer accounts accessible with the OAuth credentials
|
|
472
|
-
4. Call \`updateConnectionParameters\`:
|
|
473
547
|
- \`parameterSlug\`: \`"customer-id"\`
|
|
474
548
|
- \`options\`: The customer list. Each option's \`label\` should be \`Account Name (id: customerId)\`, \`value\` should be the customer ID
|
|
475
|
-
|
|
549
|
+
- If **0 customers** are returned, abort setup and inform the user that no accessible accounts are available
|
|
550
|
+
3. The \`label\` of the user's selected customer will arrive as a message. Proceed to the next step
|
|
476
551
|
|
|
477
552
|
#### Constraints
|
|
478
553
|
- **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
|
|
@@ -488,7 +563,6 @@ var googleAdsOnboarding = new ConnectorOnboarding({
|
|
|
488
563
|
|
|
489
564
|
// ../connectors/src/connectors/google-ads/tools/request.ts
|
|
490
565
|
import { z as z2 } from "zod";
|
|
491
|
-
var BASE_URL3 = "https://googleads.googleapis.com/v18/";
|
|
492
566
|
var REQUEST_TIMEOUT_MS2 = 6e4;
|
|
493
567
|
var cachedToken2 = null;
|
|
494
568
|
async function getProxyToken2(config) {
|
|
@@ -528,7 +602,7 @@ var inputSchema2 = z2.object({
|
|
|
528
602
|
connectionId: z2.string().describe("ID of the Google Ads OAuth connection to use"),
|
|
529
603
|
method: z2.enum(["GET", "POST"]).describe("HTTP method"),
|
|
530
604
|
path: z2.string().describe(
|
|
531
|
-
"API path appended to https://googleads.googleapis.com
|
|
605
|
+
"API path appended to https://googleads.googleapis.com/<version>/ (e.g., 'customers/{customerId}/googleAds:searchStream'). The API version is auto-managed and {customerId} is automatically replaced."
|
|
532
606
|
),
|
|
533
607
|
body: z2.record(z2.string(), z2.unknown()).optional().describe("POST request body (JSON)")
|
|
534
608
|
});
|
|
@@ -545,7 +619,7 @@ var outputSchema2 = z2.discriminatedUnion("success", [
|
|
|
545
619
|
]);
|
|
546
620
|
var requestTool = new ConnectorTool({
|
|
547
621
|
name: "request",
|
|
548
|
-
description: `Send authenticated requests to the Google Ads API
|
|
622
|
+
description: `Send authenticated requests to the Google Ads API.
|
|
549
623
|
Authentication is handled automatically via OAuth proxy.
|
|
550
624
|
{customerId} in the path is automatically replaced with the connection's customer ID (hyphens removed).`,
|
|
551
625
|
inputSchema: inputSchema2,
|
|
@@ -565,36 +639,42 @@ Authentication is handled automatically via OAuth proxy.
|
|
|
565
639
|
const rawCustomerId = parameters.customerId.tryGetValue(connection2);
|
|
566
640
|
const customerId = rawCustomerId?.replace(/-/g, "") ?? "";
|
|
567
641
|
const resolvedPath = customerId ? path2.replace(/\{customerId\}/g, customerId) : path2;
|
|
568
|
-
const url = `${BASE_URL3}${resolvedPath}`;
|
|
569
642
|
const token = await getProxyToken2(config.oauthProxy);
|
|
570
643
|
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
571
644
|
const controller = new AbortController();
|
|
572
645
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
573
646
|
try {
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
headers: {
|
|
578
|
-
"Content-Type": "application/json",
|
|
579
|
-
Authorization: `Bearer ${token}`
|
|
580
|
-
},
|
|
581
|
-
body: JSON.stringify({
|
|
582
|
-
url,
|
|
583
|
-
method,
|
|
647
|
+
const response = await fetchGoogleAdsWithVersionFallback(
|
|
648
|
+
(baseUrl) => fetch(proxyUrl, {
|
|
649
|
+
method: "POST",
|
|
584
650
|
headers: {
|
|
585
651
|
"Content-Type": "application/json",
|
|
586
|
-
|
|
587
|
-
...customerId ? { "login-customer-id": customerId } : {}
|
|
652
|
+
Authorization: `Bearer ${token}`
|
|
588
653
|
},
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
654
|
+
body: JSON.stringify({
|
|
655
|
+
url: `${baseUrl}${resolvedPath}`,
|
|
656
|
+
method,
|
|
657
|
+
headers: {
|
|
658
|
+
"Content-Type": "application/json",
|
|
659
|
+
...customerId ? { "login-customer-id": customerId } : {}
|
|
660
|
+
},
|
|
661
|
+
...method === "POST" && body ? { body: JSON.stringify(body) } : {}
|
|
662
|
+
}),
|
|
663
|
+
signal: controller.signal
|
|
664
|
+
})
|
|
665
|
+
);
|
|
666
|
+
const rawText = await response.text();
|
|
667
|
+
const data = parseJsonOrNull(rawText);
|
|
594
668
|
if (!response.ok) {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
669
|
+
return {
|
|
670
|
+
success: false,
|
|
671
|
+
error: extractGoogleAdsErrorMessage(
|
|
672
|
+
response.status,
|
|
673
|
+
response.statusText,
|
|
674
|
+
data,
|
|
675
|
+
rawText
|
|
676
|
+
)
|
|
677
|
+
};
|
|
598
678
|
}
|
|
599
679
|
return { success: true, status: response.status, data };
|
|
600
680
|
} finally {
|
|
@@ -764,26 +844,22 @@ const customerIds = await ads.listAccessibleCustomers();
|
|
|
764
844
|
if (!customerId) {
|
|
765
845
|
return { success: true };
|
|
766
846
|
}
|
|
767
|
-
const developerToken = params[parameters.developerToken.slug];
|
|
768
|
-
if (!developerToken) {
|
|
769
|
-
return {
|
|
770
|
-
success: false,
|
|
771
|
-
error: "Developer token is required"
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
const url = `https://googleads.googleapis.com/v18/customers/${customerId}/googleAds:searchStream`;
|
|
775
847
|
try {
|
|
776
|
-
const res = await
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
848
|
+
const res = await fetchGoogleAdsWithVersionFallback(
|
|
849
|
+
(baseUrl) => proxyFetch(
|
|
850
|
+
`${baseUrl}customers/${customerId}/googleAds:searchStream`,
|
|
851
|
+
{
|
|
852
|
+
method: "POST",
|
|
853
|
+
headers: {
|
|
854
|
+
"Content-Type": "application/json",
|
|
855
|
+
"login-customer-id": customerId
|
|
856
|
+
},
|
|
857
|
+
body: JSON.stringify({
|
|
858
|
+
query: "SELECT customer.id FROM customer LIMIT 1"
|
|
859
|
+
})
|
|
860
|
+
}
|
|
861
|
+
)
|
|
862
|
+
);
|
|
787
863
|
if (!res.ok) {
|
|
788
864
|
const errorText = await res.text().catch(() => res.statusText);
|
|
789
865
|
return {
|