@squadbase/vite-server 0.1.17-dev.a9ddcfa → 0.1.17-dev.e4768d1
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 +8941 -3700
- package/dist/connectors/airtable-oauth.js +87 -23
- package/dist/connectors/airtable.js +130 -23
- package/dist/connectors/amplitude.js +47 -23
- package/dist/connectors/anthropic.js +41 -17
- package/dist/connectors/asana.js +76 -25
- package/dist/connectors/attio.js +69 -28
- package/dist/connectors/aws-billing.js +47 -23
- package/dist/connectors/azure-sql.js +322 -25
- package/dist/connectors/backlog-api-key.js +79 -30
- package/dist/connectors/clickup.js +89 -25
- package/dist/connectors/cosmosdb.js +51 -27
- package/dist/connectors/customerio.js +47 -23
- package/dist/connectors/dbt.js +725 -40
- package/dist/connectors/freshdesk.js +121 -23
- package/dist/connectors/freshsales.js +47 -23
- package/dist/connectors/freshservice.js +47 -23
- package/dist/connectors/gamma.js +54 -30
- package/dist/connectors/gemini.js +41 -17
- package/dist/connectors/github.js +51 -27
- package/dist/connectors/gmail-oauth.js +42 -23
- package/dist/connectors/gmail.js +43 -19
- package/dist/connectors/google-ads.js +47 -23
- package/dist/connectors/google-analytics-oauth.js +191 -40
- package/dist/connectors/google-analytics.js +529 -111
- package/dist/connectors/google-audit-log.js +43 -19
- package/dist/connectors/google-calendar-oauth.js +100 -30
- package/dist/connectors/google-calendar.js +100 -26
- package/dist/connectors/google-docs.js +42 -23
- package/dist/connectors/google-drive.js +64 -23
- package/dist/connectors/google-search-console-oauth.js +165 -32
- package/dist/connectors/google-sheets.js +142 -199
- package/dist/connectors/google-slides.js +42 -23
- package/dist/connectors/grafana.js +84 -25
- package/dist/connectors/hackernews.d.ts +5 -0
- package/dist/connectors/hackernews.js +909 -0
- package/dist/connectors/hubspot-oauth.js +73 -22
- package/dist/connectors/hubspot.js +64 -24
- package/dist/connectors/influxdb.js +47 -23
- package/dist/connectors/intercom-oauth.js +104 -25
- package/dist/connectors/intercom.js +51 -27
- package/dist/connectors/jdbc.js +76 -25
- package/dist/connectors/jira-api-key.js +107 -26
- package/dist/connectors/kintone-api-token.js +105 -33
- package/dist/connectors/kintone.js +182 -26
- package/dist/connectors/linear.js +93 -27
- package/dist/connectors/linkedin-ads.js +80 -29
- package/dist/connectors/mailchimp-oauth.js +45 -21
- package/dist/connectors/mailchimp.js +45 -21
- package/dist/connectors/meta-ads-oauth.js +72 -29
- package/dist/connectors/meta-ads.js +74 -29
- package/dist/connectors/mixpanel.js +47 -23
- package/dist/connectors/monday.js +48 -24
- package/dist/connectors/mongodb.js +47 -23
- package/dist/connectors/notion-oauth.js +92 -24
- package/dist/connectors/notion.js +144 -26
- package/dist/connectors/openai.js +41 -17
- package/dist/connectors/oracle.js +316 -26
- package/dist/connectors/outlook-oauth.js +53 -34
- package/dist/connectors/powerbi-oauth.js +45 -26
- package/dist/connectors/salesforce.js +150 -24
- package/dist/connectors/semrush.js +45 -21
- package/dist/connectors/sentry.js +75 -25
- package/dist/connectors/shopify-oauth.js +75 -23
- package/dist/connectors/shopify.js +47 -23
- package/dist/connectors/sqlserver.js +322 -25
- package/dist/connectors/stripe-api-key.js +105 -30
- package/dist/connectors/stripe-oauth.js +102 -32
- package/dist/connectors/supabase.js +315 -21
- package/dist/connectors/tableau.js +54 -30
- package/dist/connectors/tiktok-ads.js +76 -31
- package/dist/connectors/wix-store.js +47 -23
- package/dist/connectors/x.d.ts +5 -0
- package/dist/connectors/x.js +951 -0
- package/dist/connectors/zendesk-oauth.js +87 -25
- package/dist/connectors/zendesk.js +51 -27
- package/dist/index.js +9005 -3709
- package/dist/main.js +9005 -3709
- package/dist/vite-plugin.js +8939 -3698
- package/package.json +12 -4
package/dist/connectors/gmail.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
-
var __esm = (fn, res) => function __init() {
|
|
3
|
-
|
|
2
|
+
var __esm = (fn, res, err) => function __init() {
|
|
3
|
+
if (err) throw err[0];
|
|
4
|
+
try {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
} catch (e) {
|
|
7
|
+
throw err = [e], e;
|
|
8
|
+
}
|
|
4
9
|
};
|
|
5
10
|
|
|
6
11
|
// ../connectors/src/parameter-definition.ts
|
|
@@ -187,6 +192,15 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
187
192
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
188
193
|
*/
|
|
189
194
|
setup;
|
|
195
|
+
/**
|
|
196
|
+
* 統一 introspection。SQL DB の `information_schema` / `SHOW` / `DESCRIBE` や SaaS の
|
|
197
|
+
* メタデータ API といった取得経路の差を吸収し、tables / columns / PK / FK を共通型
|
|
198
|
+
* {@link IntrospectedSchema} へ正規化して返す。取得経路は {@link IntrospectContext} で
|
|
199
|
+
* 抽象化され、SQL DB は `ctx.query`、SaaS は `ctx.proxyFetch` + `ctx.params` を使う。
|
|
200
|
+
* `ctx.profile === true` のときは L2 プロファイル(行数・NULL 率等)も best-effort で埋める。
|
|
201
|
+
* coding-agent の `DataContextIndex` がデータ地図を構築する際に使う。
|
|
202
|
+
*/
|
|
203
|
+
introspect;
|
|
190
204
|
/**
|
|
191
205
|
* Opt-out of the default "verify before save" behavior on connection
|
|
192
206
|
* creation. The backend invokes `checkConnection` synchronously while
|
|
@@ -201,6 +215,14 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
201
215
|
* the default verify-on-create behavior without opt-in.
|
|
202
216
|
*/
|
|
203
217
|
skipConnectionCheckOnCreate;
|
|
218
|
+
/**
|
|
219
|
+
* 決定論的な「立ち上げ survey」レシピ(ルールベース prewarm 基盤)。実装した connector は、LLM を使わずに
|
|
220
|
+
* read-only で自分を survey する probe 列(テーブル/列メタデータ → 小サンプル)を宣言する。coding-agent の
|
|
221
|
+
* recon driver がこれを読み、connector ツールの `execute` を直接呼んで結果を seed にする。未実装の connector は
|
|
222
|
+
* driver 側で safely skip される(その connection は listConnections のみ seed)。標準 `information_schema` を
|
|
223
|
+
* 持つ SQL connector は `makeStandardSqlSurveyProbes` を使える。**probe は必ず read-only**。
|
|
224
|
+
*/
|
|
225
|
+
surveyProbes;
|
|
204
226
|
constructor(config) {
|
|
205
227
|
this.slug = config.slug;
|
|
206
228
|
this.authType = config.authType;
|
|
@@ -218,7 +240,9 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
218
240
|
this.query = config.query;
|
|
219
241
|
this.checkConnection = config.checkConnection;
|
|
220
242
|
this.setup = config.setup;
|
|
243
|
+
this.introspect = config.introspect;
|
|
221
244
|
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
245
|
+
this.surveyProbes = config.surveyProbes;
|
|
222
246
|
}
|
|
223
247
|
get connectorKey() {
|
|
224
248
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -226,7 +250,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
226
250
|
/**
|
|
227
251
|
* Create tools for connections that belong to this connector.
|
|
228
252
|
* Filters connections by connectorKey internally.
|
|
229
|
-
* Returns tools keyed as
|
|
253
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
230
254
|
*/
|
|
231
255
|
createTools(connections, config, opts) {
|
|
232
256
|
const myConnections = connections.filter(
|
|
@@ -236,7 +260,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
236
260
|
for (const t of Object.values(this.tools)) {
|
|
237
261
|
const tool = t.createTool(myConnections, config);
|
|
238
262
|
const originalToModelOutput = tool.toModelOutput;
|
|
239
|
-
result[
|
|
263
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
240
264
|
...tool,
|
|
241
265
|
toModelOutput: async (options) => {
|
|
242
266
|
if (!originalToModelOutput) {
|
|
@@ -256,25 +280,25 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
256
280
|
if (authType) return `${slug}-${authType}`;
|
|
257
281
|
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
258
282
|
// user-password
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
283
|
+
postgresql: "user-password",
|
|
284
|
+
mysql: "user-password",
|
|
285
|
+
clickhouse: "user-password",
|
|
286
|
+
kintone: "user-password",
|
|
263
287
|
"squadbase-db": "user-password",
|
|
264
288
|
// service-account
|
|
265
|
-
|
|
266
|
-
|
|
289
|
+
snowflake: "service-account",
|
|
290
|
+
bigquery: "service-account",
|
|
267
291
|
"google-analytics": "service-account",
|
|
268
292
|
"google-calendar": "service-account",
|
|
269
293
|
"aws-athena": "service-account",
|
|
270
|
-
|
|
294
|
+
redshift: "service-account",
|
|
271
295
|
// api-key
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
296
|
+
databricks: "api-key",
|
|
297
|
+
dbt: "api-key",
|
|
298
|
+
airtable: "api-key",
|
|
299
|
+
openai: "api-key",
|
|
300
|
+
gemini: "api-key",
|
|
301
|
+
anthropic: "api-key",
|
|
278
302
|
"wix-store": "api-key"
|
|
279
303
|
};
|
|
280
304
|
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
@@ -721,7 +745,7 @@ var gmailConnector = new ConnectorPlugin({
|
|
|
721
745
|
systemPrompt: {
|
|
722
746
|
en: `### Tools
|
|
723
747
|
|
|
724
|
-
- \`
|
|
748
|
+
- \`connector_gmail-service-account_request_with_delegation\`: Call the Gmail API on behalf of the specified Workspace user via Domain-wide Delegation. Pass \`subject\` as the target user's email; the token will be issued as that user. Always pass \`scopes\`.
|
|
725
749
|
|
|
726
750
|
### OAuth Scopes (pass as \`scopes\` argument)
|
|
727
751
|
|
|
@@ -814,7 +838,7 @@ for (const msg of messages.messages ?? []) {
|
|
|
814
838
|
\`\`\``,
|
|
815
839
|
ja: `### \u30C4\u30FC\u30EB
|
|
816
840
|
|
|
817
|
-
- \`
|
|
841
|
+
- \`connector_gmail-service-account_request_with_delegation\`: \u6307\u5B9A\u3055\u308C\u305F Workspace \u30E6\u30FC\u30B6\u30FC\u306B\u4EE3\u308F\u3063\u3066 Domain-wide Delegation \u7D4C\u7531\u3067 Gmail API \u3092\u547C\u3073\u51FA\u3057\u307E\u3059\u3002\u4EE3\u7406\u5BFE\u8C61\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 \`subject\` \u3068\u3057\u3066\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30C8\u30FC\u30AF\u30F3\u306F\u305D\u306E\u30E6\u30FC\u30B6\u30FC\u3068\u3057\u3066\u767A\u884C\u3055\u308C\u307E\u3059\u3002\`scopes\` \u3082\u6BCE\u56DE\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
818
842
|
|
|
819
843
|
### OAuth \u30B9\u30B3\u30FC\u30D7 (\`scopes\` \u5F15\u6570\u3067\u6E21\u3059)
|
|
820
844
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
-
var __esm = (fn, res) => function __init() {
|
|
3
|
-
|
|
2
|
+
var __esm = (fn, res, err) => function __init() {
|
|
3
|
+
if (err) throw err[0];
|
|
4
|
+
try {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
} catch (e) {
|
|
7
|
+
throw err = [e], e;
|
|
8
|
+
}
|
|
4
9
|
};
|
|
5
10
|
|
|
6
11
|
// ../connectors/src/parameter-definition.ts
|
|
@@ -235,6 +240,15 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
235
240
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
236
241
|
*/
|
|
237
242
|
setup;
|
|
243
|
+
/**
|
|
244
|
+
* 統一 introspection。SQL DB の `information_schema` / `SHOW` / `DESCRIBE` や SaaS の
|
|
245
|
+
* メタデータ API といった取得経路の差を吸収し、tables / columns / PK / FK を共通型
|
|
246
|
+
* {@link IntrospectedSchema} へ正規化して返す。取得経路は {@link IntrospectContext} で
|
|
247
|
+
* 抽象化され、SQL DB は `ctx.query`、SaaS は `ctx.proxyFetch` + `ctx.params` を使う。
|
|
248
|
+
* `ctx.profile === true` のときは L2 プロファイル(行数・NULL 率等)も best-effort で埋める。
|
|
249
|
+
* coding-agent の `DataContextIndex` がデータ地図を構築する際に使う。
|
|
250
|
+
*/
|
|
251
|
+
introspect;
|
|
238
252
|
/**
|
|
239
253
|
* Opt-out of the default "verify before save" behavior on connection
|
|
240
254
|
* creation. The backend invokes `checkConnection` synchronously while
|
|
@@ -249,6 +263,14 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
249
263
|
* the default verify-on-create behavior without opt-in.
|
|
250
264
|
*/
|
|
251
265
|
skipConnectionCheckOnCreate;
|
|
266
|
+
/**
|
|
267
|
+
* 決定論的な「立ち上げ survey」レシピ(ルールベース prewarm 基盤)。実装した connector は、LLM を使わずに
|
|
268
|
+
* read-only で自分を survey する probe 列(テーブル/列メタデータ → 小サンプル)を宣言する。coding-agent の
|
|
269
|
+
* recon driver がこれを読み、connector ツールの `execute` を直接呼んで結果を seed にする。未実装の connector は
|
|
270
|
+
* driver 側で safely skip される(その connection は listConnections のみ seed)。標準 `information_schema` を
|
|
271
|
+
* 持つ SQL connector は `makeStandardSqlSurveyProbes` を使える。**probe は必ず read-only**。
|
|
272
|
+
*/
|
|
273
|
+
surveyProbes;
|
|
252
274
|
constructor(config) {
|
|
253
275
|
this.slug = config.slug;
|
|
254
276
|
this.authType = config.authType;
|
|
@@ -266,7 +288,9 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
266
288
|
this.query = config.query;
|
|
267
289
|
this.checkConnection = config.checkConnection;
|
|
268
290
|
this.setup = config.setup;
|
|
291
|
+
this.introspect = config.introspect;
|
|
269
292
|
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
293
|
+
this.surveyProbes = config.surveyProbes;
|
|
270
294
|
}
|
|
271
295
|
get connectorKey() {
|
|
272
296
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -274,7 +298,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
274
298
|
/**
|
|
275
299
|
* Create tools for connections that belong to this connector.
|
|
276
300
|
* Filters connections by connectorKey internally.
|
|
277
|
-
* Returns tools keyed as
|
|
301
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
278
302
|
*/
|
|
279
303
|
createTools(connections, config, opts) {
|
|
280
304
|
const myConnections = connections.filter(
|
|
@@ -284,7 +308,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
284
308
|
for (const t of Object.values(this.tools)) {
|
|
285
309
|
const tool = t.createTool(myConnections, config);
|
|
286
310
|
const originalToModelOutput = tool.toModelOutput;
|
|
287
|
-
result[
|
|
311
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
288
312
|
...tool,
|
|
289
313
|
toModelOutput: async (options) => {
|
|
290
314
|
if (!originalToModelOutput) {
|
|
@@ -304,25 +328,25 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
304
328
|
if (authType) return `${slug}-${authType}`;
|
|
305
329
|
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
306
330
|
// user-password
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
331
|
+
postgresql: "user-password",
|
|
332
|
+
mysql: "user-password",
|
|
333
|
+
clickhouse: "user-password",
|
|
334
|
+
kintone: "user-password",
|
|
311
335
|
"squadbase-db": "user-password",
|
|
312
336
|
// service-account
|
|
313
|
-
|
|
314
|
-
|
|
337
|
+
snowflake: "service-account",
|
|
338
|
+
bigquery: "service-account",
|
|
315
339
|
"google-analytics": "service-account",
|
|
316
340
|
"google-calendar": "service-account",
|
|
317
341
|
"aws-athena": "service-account",
|
|
318
|
-
|
|
342
|
+
redshift: "service-account",
|
|
319
343
|
// api-key
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
344
|
+
databricks: "api-key",
|
|
345
|
+
dbt: "api-key",
|
|
346
|
+
airtable: "api-key",
|
|
347
|
+
openai: "api-key",
|
|
348
|
+
gemini: "api-key",
|
|
349
|
+
anthropic: "api-key",
|
|
326
350
|
"wix-store": "api-key"
|
|
327
351
|
};
|
|
328
352
|
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
@@ -662,9 +686,9 @@ var googleAdsOnboarding = new ConnectorOnboarding({
|
|
|
662
686
|
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
663
687
|
},
|
|
664
688
|
dataOverviewInstructions: {
|
|
665
|
-
en: `1. Call
|
|
689
|
+
en: `1. Call connector_google-ads-oauth_request with POST customers/{customerId}/googleAds:searchStream to explore available campaign data using GAQL: SELECT campaign.id, campaign.name, campaign.status FROM campaign LIMIT 10
|
|
666
690
|
2. Explore ad group and keyword data as needed to understand the data structure`,
|
|
667
|
-
ja: `1.
|
|
691
|
+
ja: `1. connector_google-ads-oauth_request \u3067 POST customers/{customerId}/googleAds:searchStream \u3092\u547C\u3073\u51FA\u3057\u3001GAQL\u3067\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30C7\u30FC\u30BF\u3092\u63A2\u7D22: SELECT campaign.id, campaign.name, campaign.status FROM campaign LIMIT 10
|
|
668
692
|
2. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u5E83\u544A\u30B0\u30EB\u30FC\u30D7\u3084\u30AD\u30FC\u30EF\u30FC\u30C9\u30C7\u30FC\u30BF\u3092\u63A2\u7D22\u3057\u3001\u30C7\u30FC\u30BF\u69CB\u9020\u3092\u628A\u63E1`
|
|
669
693
|
}
|
|
670
694
|
});
|
|
@@ -936,8 +960,8 @@ var googleAdsConnector = new ConnectorPlugin({
|
|
|
936
960
|
systemPrompt: {
|
|
937
961
|
en: `### Tools (setup-time only)
|
|
938
962
|
|
|
939
|
-
- \`
|
|
940
|
-
- \`
|
|
963
|
+
- \`connector_google-ads-oauth_request\`: Send authenticated requests to the Google Ads API during setup / data overview. Use it for GAQL queries via searchStream. The {customerId} placeholder in paths is automatically replaced (hyphens removed). Authentication and developer token are configured automatically.
|
|
964
|
+
- \`connector_google-ads-oauth_listCustomers\`: List accessible Google Ads customer accounts. Use this during setup to discover available accounts.
|
|
941
965
|
|
|
942
966
|
> **Important**: These tools are only available at setup time. Inside server-logic handlers, use the SDK (\`connection(id).search\`, etc.) \u2014 the SDK's fetch is already wired through the OAuth proxy. **Do NOT** hand-roll HTTP calls to \`_sqcore/connections/*/request\` from a handler.
|
|
943
967
|
|
|
@@ -998,8 +1022,8 @@ const customerIds = await ads.listAccessibleCustomers();
|
|
|
998
1022
|
\`\`\``,
|
|
999
1023
|
ja: `### \u30C4\u30FC\u30EB\uFF08\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306E\u307F\uFF09
|
|
1000
1024
|
|
|
1001
|
-
- \`
|
|
1002
|
-
- \`
|
|
1025
|
+
- \`connector_google-ads-oauth_request\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3084\u30C7\u30FC\u30BF\u6982\u8981\u628A\u63E1\u6642\u306B Google Ads API \u3078\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002searchStream \u3092\u4F7F\u3063\u305F GAQL \u30AF\u30A8\u30EA\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E {customerId} \u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\uFF08\u30CF\u30A4\u30D5\u30F3\u306F\u9664\u53BB\uFF09\u3002\u8A8D\u8A3C\u3068\u30C7\u30D9\u30ED\u30C3\u30D1\u30FC\u30C8\u30FC\u30AF\u30F3\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
|
|
1026
|
+
- \`connector_google-ads-oauth_listCustomers\`: \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A Google Ads \u9867\u5BA2\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306B\u5229\u7528\u53EF\u80FD\u306A\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u78BA\u8A8D\u3059\u308B\u305F\u3081\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002
|
|
1003
1027
|
|
|
1004
1028
|
> **\u91CD\u8981**: \u3053\u308C\u3089\u306E\u30C4\u30FC\u30EB\u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306E\u307F\u5229\u7528\u53EF\u80FD\u3067\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u30ED\u30B8\u30C3\u30AF\u306E\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u5FC5\u305A SDK\uFF08\`connection(id).search\` \u306A\u3069\uFF09\u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002SDK \u306E fetch \u306F OAuth \u30D7\u30ED\u30AD\u30B7\u7D4C\u7531\u3067\u65E2\u306B\u914D\u7DDA\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u304B\u3089 \`_sqcore/connections/*/request\` \u3092\u624B\u66F8\u304D\u3067\u547C\u3073\u51FA\u3055\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
1005
1029
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
-
var __esm = (fn, res) => function __init() {
|
|
3
|
-
|
|
2
|
+
var __esm = (fn, res, err) => function __init() {
|
|
3
|
+
if (err) throw err[0];
|
|
4
|
+
try {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
} catch (e) {
|
|
7
|
+
throw err = [e], e;
|
|
8
|
+
}
|
|
4
9
|
};
|
|
5
10
|
|
|
6
11
|
// ../connectors/src/parameter-definition.ts
|
|
@@ -216,6 +221,15 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
216
221
|
* `runSetupFlow` from `setup-flow.ts`.
|
|
217
222
|
*/
|
|
218
223
|
setup;
|
|
224
|
+
/**
|
|
225
|
+
* 統一 introspection。SQL DB の `information_schema` / `SHOW` / `DESCRIBE` や SaaS の
|
|
226
|
+
* メタデータ API といった取得経路の差を吸収し、tables / columns / PK / FK を共通型
|
|
227
|
+
* {@link IntrospectedSchema} へ正規化して返す。取得経路は {@link IntrospectContext} で
|
|
228
|
+
* 抽象化され、SQL DB は `ctx.query`、SaaS は `ctx.proxyFetch` + `ctx.params` を使う。
|
|
229
|
+
* `ctx.profile === true` のときは L2 プロファイル(行数・NULL 率等)も best-effort で埋める。
|
|
230
|
+
* coding-agent の `DataContextIndex` がデータ地図を構築する際に使う。
|
|
231
|
+
*/
|
|
232
|
+
introspect;
|
|
219
233
|
/**
|
|
220
234
|
* Opt-out of the default "verify before save" behavior on connection
|
|
221
235
|
* creation. The backend invokes `checkConnection` synchronously while
|
|
@@ -230,6 +244,14 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
230
244
|
* the default verify-on-create behavior without opt-in.
|
|
231
245
|
*/
|
|
232
246
|
skipConnectionCheckOnCreate;
|
|
247
|
+
/**
|
|
248
|
+
* 決定論的な「立ち上げ survey」レシピ(ルールベース prewarm 基盤)。実装した connector は、LLM を使わずに
|
|
249
|
+
* read-only で自分を survey する probe 列(テーブル/列メタデータ → 小サンプル)を宣言する。coding-agent の
|
|
250
|
+
* recon driver がこれを読み、connector ツールの `execute` を直接呼んで結果を seed にする。未実装の connector は
|
|
251
|
+
* driver 側で safely skip される(その connection は listConnections のみ seed)。標準 `information_schema` を
|
|
252
|
+
* 持つ SQL connector は `makeStandardSqlSurveyProbes` を使える。**probe は必ず read-only**。
|
|
253
|
+
*/
|
|
254
|
+
surveyProbes;
|
|
233
255
|
constructor(config) {
|
|
234
256
|
this.slug = config.slug;
|
|
235
257
|
this.authType = config.authType;
|
|
@@ -247,7 +269,9 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
247
269
|
this.query = config.query;
|
|
248
270
|
this.checkConnection = config.checkConnection;
|
|
249
271
|
this.setup = config.setup;
|
|
272
|
+
this.introspect = config.introspect;
|
|
250
273
|
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
274
|
+
this.surveyProbes = config.surveyProbes;
|
|
251
275
|
}
|
|
252
276
|
get connectorKey() {
|
|
253
277
|
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
@@ -255,7 +279,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
255
279
|
/**
|
|
256
280
|
* Create tools for connections that belong to this connector.
|
|
257
281
|
* Filters connections by connectorKey internally.
|
|
258
|
-
* Returns tools keyed as
|
|
282
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
259
283
|
*/
|
|
260
284
|
createTools(connections, config, opts) {
|
|
261
285
|
const myConnections = connections.filter(
|
|
@@ -265,7 +289,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
265
289
|
for (const t of Object.values(this.tools)) {
|
|
266
290
|
const tool = t.createTool(myConnections, config);
|
|
267
291
|
const originalToModelOutput = tool.toModelOutput;
|
|
268
|
-
result[
|
|
292
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
269
293
|
...tool,
|
|
270
294
|
toModelOutput: async (options) => {
|
|
271
295
|
if (!originalToModelOutput) {
|
|
@@ -285,25 +309,25 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
285
309
|
if (authType) return `${slug}-${authType}`;
|
|
286
310
|
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
287
311
|
// user-password
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
312
|
+
postgresql: "user-password",
|
|
313
|
+
mysql: "user-password",
|
|
314
|
+
clickhouse: "user-password",
|
|
315
|
+
kintone: "user-password",
|
|
292
316
|
"squadbase-db": "user-password",
|
|
293
317
|
// service-account
|
|
294
|
-
|
|
295
|
-
|
|
318
|
+
snowflake: "service-account",
|
|
319
|
+
bigquery: "service-account",
|
|
296
320
|
"google-analytics": "service-account",
|
|
297
321
|
"google-calendar": "service-account",
|
|
298
322
|
"aws-athena": "service-account",
|
|
299
|
-
|
|
323
|
+
redshift: "service-account",
|
|
300
324
|
// api-key
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
325
|
+
databricks: "api-key",
|
|
326
|
+
dbt: "api-key",
|
|
327
|
+
airtable: "api-key",
|
|
328
|
+
openai: "api-key",
|
|
329
|
+
gemini: "api-key",
|
|
330
|
+
anthropic: "api-key",
|
|
307
331
|
"wix-store": "api-key"
|
|
308
332
|
};
|
|
309
333
|
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
@@ -665,15 +689,16 @@ var googleAnalyticsOauthOnboarding = new ConnectorOnboarding({
|
|
|
665
689
|
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
666
690
|
},
|
|
667
691
|
dataOverviewInstructions: {
|
|
668
|
-
en: `1. Call
|
|
669
|
-
2. Call
|
|
670
|
-
ja: `1.
|
|
671
|
-
2.
|
|
692
|
+
en: `1. Call connector_google-analytics-oauth_request with GET properties/{propertyId}/metadata to list available dimensions and metrics
|
|
693
|
+
2. Call connector_google-analytics-oauth_request with POST properties/{propertyId}:runReport using a small date range and basic metrics to verify data availability`,
|
|
694
|
+
ja: `1. connector_google-analytics-oauth_request \u3067 GET properties/{propertyId}/metadata \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30C7\u30A3\u30E1\u30F3\u30B7\u30E7\u30F3\u3068\u30E1\u30C8\u30EA\u30AF\u30B9\u306E\u4E00\u89A7\u3092\u53D6\u5F97
|
|
695
|
+
2. connector_google-analytics-oauth_request \u3067 POST properties/{propertyId}:runReport \u3092\u77ED\u3044\u671F\u9593\u3068\u57FA\u672C\u30E1\u30C8\u30EA\u30AF\u30B9\u3067\u547C\u3073\u51FA\u3057\u3001\u30C7\u30FC\u30BF\u306E\u53EF\u7528\u6027\u3092\u78BA\u8A8D`
|
|
672
696
|
}
|
|
673
697
|
});
|
|
674
698
|
|
|
675
699
|
// ../connectors/src/connectors/google-analytics-oauth/setup-flow.ts
|
|
676
700
|
var ADMIN_BASE_URL3 = "https://analyticsadmin.googleapis.com/v1beta";
|
|
701
|
+
var DATA_BASE_URL = "https://analyticsdata.googleapis.com/v1beta";
|
|
677
702
|
var ALL_PROPERTIES = "__ALL_PROPERTIES__";
|
|
678
703
|
var GOOGLE_ANALYTICS_OAUTH_SETUP_MAX_PROPERTIES = 20;
|
|
679
704
|
async function listAccountSummaries(proxyFetch) {
|
|
@@ -704,6 +729,44 @@ async function getProperty(proxyFetch, propertyId) {
|
|
|
704
729
|
if (!res.ok) return null;
|
|
705
730
|
return await res.json();
|
|
706
731
|
}
|
|
732
|
+
async function getMetadata(proxyFetch, propertyId) {
|
|
733
|
+
try {
|
|
734
|
+
const res = await proxyFetch(
|
|
735
|
+
`${DATA_BASE_URL}/properties/${propertyId}/metadata`,
|
|
736
|
+
{ method: "GET" }
|
|
737
|
+
);
|
|
738
|
+
if (!res.ok) return { dimensions: [], metrics: [] };
|
|
739
|
+
const data = await res.json();
|
|
740
|
+
return {
|
|
741
|
+
dimensions: data.dimensions ?? [],
|
|
742
|
+
metrics: data.metrics ?? []
|
|
743
|
+
};
|
|
744
|
+
} catch {
|
|
745
|
+
return { dimensions: [], metrics: [] };
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
async function runSampleReport(proxyFetch, propertyId, dimensions, metrics, limit) {
|
|
749
|
+
try {
|
|
750
|
+
const res = await proxyFetch(
|
|
751
|
+
`${DATA_BASE_URL}/properties/${propertyId}:runReport`,
|
|
752
|
+
{
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: { "Content-Type": "application/json" },
|
|
755
|
+
body: JSON.stringify({
|
|
756
|
+
dateRanges: [{ startDate: "28daysAgo", endDate: "today" }],
|
|
757
|
+
dimensions: dimensions.map((name) => ({ name })),
|
|
758
|
+
metrics: metrics.map((name) => ({ name })),
|
|
759
|
+
limit
|
|
760
|
+
})
|
|
761
|
+
}
|
|
762
|
+
);
|
|
763
|
+
if (!res.ok) return [];
|
|
764
|
+
const data = await res.json();
|
|
765
|
+
return data.rows ?? [];
|
|
766
|
+
} catch {
|
|
767
|
+
return [];
|
|
768
|
+
}
|
|
769
|
+
}
|
|
707
770
|
var googleAnalyticsOauthSetupFlow = {
|
|
708
771
|
initialState: () => ({}),
|
|
709
772
|
steps: [
|
|
@@ -787,23 +850,111 @@ var googleAnalyticsOauthSetupFlow = {
|
|
|
787
850
|
sections.push("_No properties selected._", "");
|
|
788
851
|
return sections.join("\n");
|
|
789
852
|
}
|
|
790
|
-
sections.push(
|
|
791
|
-
"| Property ID | Display Name | Time Zone | Currency | Industry |"
|
|
792
|
-
);
|
|
793
|
-
sections.push(
|
|
794
|
-
"|-------------|--------------|-----------|----------|----------|"
|
|
795
|
-
);
|
|
796
853
|
for (const propertyId of targetPropertyIds) {
|
|
797
854
|
const prop = await getProperty(rt.config.proxyFetch, propertyId);
|
|
798
|
-
const displayName =
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
855
|
+
const displayName = prop?.displayName ?? propertyId;
|
|
856
|
+
sections.push(`### Property: ${displayName} (${propertyId})`, "");
|
|
857
|
+
if (prop?.timeZone || prop?.currencyCode || prop?.industryCategory) {
|
|
858
|
+
const details = [];
|
|
859
|
+
if (prop.timeZone) details.push(`Time Zone: ${prop.timeZone}`);
|
|
860
|
+
if (prop.currencyCode) details.push(`Currency: ${prop.currencyCode}`);
|
|
861
|
+
if (prop.industryCategory)
|
|
862
|
+
details.push(`Industry: ${prop.industryCategory}`);
|
|
863
|
+
sections.push(details.join(" | "), "");
|
|
864
|
+
}
|
|
865
|
+
const metadata = await getMetadata(rt.config.proxyFetch, propertyId);
|
|
866
|
+
if (metadata.dimensions.length > 0) {
|
|
867
|
+
const categories = /* @__PURE__ */ new Map();
|
|
868
|
+
for (const d of metadata.dimensions) {
|
|
869
|
+
const cat = d.category || "Other";
|
|
870
|
+
if (!categories.has(cat)) categories.set(cat, []);
|
|
871
|
+
categories.get(cat).push(d.uiName ?? d.apiName ?? "");
|
|
872
|
+
}
|
|
873
|
+
sections.push("#### Available Dimensions", "");
|
|
874
|
+
for (const [cat, dims] of categories) {
|
|
875
|
+
sections.push(
|
|
876
|
+
`- **${cat}**: ${dims.slice(0, 10).join(", ")}${dims.length > 10 ? ` \u2026+${dims.length - 10}` : ""}`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
sections.push("");
|
|
880
|
+
}
|
|
881
|
+
if (metadata.metrics.length > 0) {
|
|
882
|
+
const categories = /* @__PURE__ */ new Map();
|
|
883
|
+
for (const m of metadata.metrics) {
|
|
884
|
+
const cat = m.category || "Other";
|
|
885
|
+
if (!categories.has(cat)) categories.set(cat, []);
|
|
886
|
+
categories.get(cat).push(m.uiName ?? m.apiName ?? "");
|
|
887
|
+
}
|
|
888
|
+
sections.push("#### Available Metrics", "");
|
|
889
|
+
for (const [cat, mets] of categories) {
|
|
890
|
+
sections.push(
|
|
891
|
+
`- **${cat}**: ${mets.slice(0, 10).join(", ")}${mets.length > 10 ? ` \u2026+${mets.length - 10}` : ""}`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
sections.push("");
|
|
895
|
+
}
|
|
896
|
+
const trafficRows = await runSampleReport(
|
|
897
|
+
rt.config.proxyFetch,
|
|
898
|
+
propertyId,
|
|
899
|
+
["date"],
|
|
900
|
+
["sessions", "activeUsers", "screenPageViews"],
|
|
901
|
+
7
|
|
902
|
+
);
|
|
903
|
+
if (trafficRows.length > 0) {
|
|
904
|
+
sections.push("#### Traffic Summary (last 28 days, by date)", "");
|
|
905
|
+
sections.push("| Date | Sessions | Active Users | Page Views |");
|
|
906
|
+
sections.push("|------|----------|-------------|------------|");
|
|
907
|
+
for (const row of trafficRows) {
|
|
908
|
+
const d = row.dimensionValues?.[0]?.value ?? "";
|
|
909
|
+
const s = row.metricValues?.[0]?.value ?? "0";
|
|
910
|
+
const u = row.metricValues?.[1]?.value ?? "0";
|
|
911
|
+
const p = row.metricValues?.[2]?.value ?? "0";
|
|
912
|
+
sections.push(`| ${d} | ${s} | ${u} | ${p} |`);
|
|
913
|
+
}
|
|
914
|
+
sections.push("");
|
|
915
|
+
}
|
|
916
|
+
const channelRows = await runSampleReport(
|
|
917
|
+
rt.config.proxyFetch,
|
|
918
|
+
propertyId,
|
|
919
|
+
["sessionDefaultChannelGroup"],
|
|
920
|
+
["sessions", "activeUsers"],
|
|
921
|
+
10
|
|
922
|
+
);
|
|
923
|
+
if (channelRows.length > 0) {
|
|
924
|
+
sections.push("#### Top Channels (last 28 days)", "");
|
|
925
|
+
sections.push("| Channel | Sessions | Active Users |");
|
|
926
|
+
sections.push("|---------|----------|-------------|");
|
|
927
|
+
for (const row of channelRows) {
|
|
928
|
+
const ch = row.dimensionValues?.[0]?.value ?? "";
|
|
929
|
+
const s = row.metricValues?.[0]?.value ?? "0";
|
|
930
|
+
const u = row.metricValues?.[1]?.value ?? "0";
|
|
931
|
+
sections.push(`| ${ch} | ${s} | ${u} |`);
|
|
932
|
+
}
|
|
933
|
+
sections.push("");
|
|
934
|
+
}
|
|
935
|
+
const pageRows = await runSampleReport(
|
|
936
|
+
rt.config.proxyFetch,
|
|
937
|
+
propertyId,
|
|
938
|
+
["pagePath"],
|
|
939
|
+
["screenPageViews", "activeUsers"],
|
|
940
|
+
10
|
|
804
941
|
);
|
|
942
|
+
if (pageRows.length > 0) {
|
|
943
|
+
sections.push("#### Top Pages (last 28 days)", "");
|
|
944
|
+
sections.push("| Page Path | Page Views | Active Users |");
|
|
945
|
+
sections.push("|-----------|------------|-------------|");
|
|
946
|
+
for (const row of pageRows) {
|
|
947
|
+
const pg = (row.dimensionValues?.[0]?.value ?? "").replace(
|
|
948
|
+
/\|/g,
|
|
949
|
+
"\\|"
|
|
950
|
+
);
|
|
951
|
+
const v = row.metricValues?.[0]?.value ?? "0";
|
|
952
|
+
const u = row.metricValues?.[1]?.value ?? "0";
|
|
953
|
+
sections.push(`| ${pg} | ${v} | ${u} |`);
|
|
954
|
+
}
|
|
955
|
+
sections.push("");
|
|
956
|
+
}
|
|
805
957
|
}
|
|
806
|
-
sections.push("");
|
|
807
958
|
return sections.join("\n");
|
|
808
959
|
}
|
|
809
960
|
};
|
|
@@ -956,9 +1107,9 @@ var googleAnalyticsOauthConnector = new ConnectorPlugin({
|
|
|
956
1107
|
systemPrompt: {
|
|
957
1108
|
en: `### Tools
|
|
958
1109
|
|
|
959
|
-
- \`
|
|
960
|
-
- \`
|
|
961
|
-
- \`
|
|
1110
|
+
- \`connector_google-analytics-oauth_request\`: Send authenticated requests to the GA4 Data API. Use it for running reports, getting metadata, and realtime reports. The {propertyId} placeholder in paths is automatically replaced. Authentication is configured automatically via OAuth.
|
|
1111
|
+
- \`connector_google-analytics-oauth_listAccounts\`: List accessible Google Analytics accounts. Use during setup to discover available accounts.
|
|
1112
|
+
- \`connector_google-analytics-oauth_listProperties\`: List GA4 properties for a given account. Use during setup to select the target property.
|
|
962
1113
|
|
|
963
1114
|
### GA4 Data API Reference
|
|
964
1115
|
|
|
@@ -1028,9 +1179,9 @@ const realtime = await ga.runRealtimeReport({
|
|
|
1028
1179
|
\`\`\``,
|
|
1029
1180
|
ja: `### \u30C4\u30FC\u30EB
|
|
1030
1181
|
|
|
1031
|
-
- \`
|
|
1032
|
-
- \`
|
|
1033
|
-
- \`
|
|
1182
|
+
- \`connector_google-analytics-oauth_request\`: GA4 Data API\u3078\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002\u30EC\u30DD\u30FC\u30C8\u306E\u5B9F\u884C\u3001\u30E1\u30BF\u30C7\u30FC\u30BF\u306E\u53D6\u5F97\u3001\u30EA\u30A2\u30EB\u30BF\u30A4\u30E0\u30EC\u30DD\u30FC\u30C8\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E{propertyId}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002OAuth\u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
|
|
1183
|
+
- \`connector_google-analytics-oauth_listAccounts\`: \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Analytics\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306B\u5229\u7528\u53EF\u80FD\u306A\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u78BA\u8A8D\u3059\u308B\u305F\u3081\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002
|
|
1184
|
+
- \`connector_google-analytics-oauth_listProperties\`: \u6307\u5B9A\u30A2\u30AB\u30A6\u30F3\u30C8\u306EGA4\u30D7\u30ED\u30D1\u30C6\u30A3\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306B\u30BF\u30FC\u30B2\u30C3\u30C8\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u9078\u629E\u3059\u308B\u305F\u3081\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002
|
|
1034
1185
|
|
|
1035
1186
|
### GA4 Data API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
1036
1187
|
|