@squadbase/vite-server 0.1.3-dev.5 → 0.1.3-dev.6
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 +1812 -1477
- package/dist/connectors/gmail.d.ts +5 -0
- package/dist/connectors/gmail.js +802 -0
- package/dist/connectors/google-ads-oauth.js +1 -1
- package/dist/connectors/google-analytics.js +256 -26
- package/dist/connectors/google-calendar.d.ts +8 -1
- package/dist/connectors/google-calendar.js +63 -30
- package/dist/index.js +1812 -1477
- package/dist/main.js +1812 -1477
- package/dist/vite-plugin.js +1812 -1477
- package/package.json +5 -1
|
@@ -59,11 +59,11 @@ var parameters = {
|
|
|
59
59
|
propertyId: new ParameterDefinition({
|
|
60
60
|
slug: "property-id",
|
|
61
61
|
name: "Google Analytics Property ID",
|
|
62
|
-
description: "The Google Analytics 4 property ID (e.g., 123456789).",
|
|
62
|
+
description: "The Google Analytics 4 property ID (e.g., 123456789). Set during connection setup.",
|
|
63
63
|
envVarBaseKey: "GA_PROPERTY_ID",
|
|
64
64
|
type: "text",
|
|
65
65
|
secret: false,
|
|
66
|
-
required:
|
|
66
|
+
required: false
|
|
67
67
|
})
|
|
68
68
|
};
|
|
69
69
|
|
|
@@ -125,7 +125,7 @@ function createClient(params) {
|
|
|
125
125
|
}
|
|
126
126
|
let cachedToken = null;
|
|
127
127
|
let tokenExpiresAt = 0;
|
|
128
|
-
async function
|
|
128
|
+
async function getAccessToken2() {
|
|
129
129
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
130
130
|
if (cachedToken && nowSec < tokenExpiresAt - 60) {
|
|
131
131
|
return cachedToken;
|
|
@@ -156,7 +156,7 @@ function createClient(params) {
|
|
|
156
156
|
}
|
|
157
157
|
return {
|
|
158
158
|
async request(path2, init) {
|
|
159
|
-
const accessToken = await
|
|
159
|
+
const accessToken = await getAccessToken2();
|
|
160
160
|
const resolvedPath = path2.replace(/\{propertyId\}/g, propertyId);
|
|
161
161
|
const url = `${BASE_URL.replace(/\/+$/, "")}/${resolvedPath.replace(/^\/+/, "")}`;
|
|
162
162
|
const headers = new Headers(init?.headers);
|
|
@@ -331,8 +331,230 @@ var AUTH_TYPES = {
|
|
|
331
331
|
USER_PASSWORD: "user-password"
|
|
332
332
|
};
|
|
333
333
|
|
|
334
|
+
// ../connectors/src/connectors/google-analytics/tools/list-accounts.ts
|
|
335
|
+
import { z } from "zod";
|
|
336
|
+
|
|
337
|
+
// ../connectors/src/connectors/google-analytics/tools/auth.ts
|
|
338
|
+
var SCOPES = [
|
|
339
|
+
"https://www.googleapis.com/auth/analytics.readonly"
|
|
340
|
+
];
|
|
341
|
+
async function getAccessToken(connection2) {
|
|
342
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
343
|
+
const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
|
|
344
|
+
const credentials = JSON.parse(
|
|
345
|
+
Buffer.from(keyJsonBase64, "base64").toString("utf-8")
|
|
346
|
+
);
|
|
347
|
+
const auth = new GoogleAuth({
|
|
348
|
+
credentials,
|
|
349
|
+
scopes: SCOPES
|
|
350
|
+
});
|
|
351
|
+
const token = await auth.getAccessToken();
|
|
352
|
+
if (!token) {
|
|
353
|
+
throw new Error("Failed to obtain access token");
|
|
354
|
+
}
|
|
355
|
+
return token;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// ../connectors/src/connectors/google-analytics/tools/list-accounts.ts
|
|
359
|
+
var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta/";
|
|
360
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
361
|
+
var inputSchema = z.object({
|
|
362
|
+
toolUseIntent: z.string().optional().describe(
|
|
363
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
364
|
+
),
|
|
365
|
+
connectionId: z.string().describe("ID of the Google Analytics connection to use")
|
|
366
|
+
});
|
|
367
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
368
|
+
z.object({
|
|
369
|
+
success: z.literal(true),
|
|
370
|
+
accounts: z.array(
|
|
371
|
+
z.object({
|
|
372
|
+
name: z.string(),
|
|
373
|
+
displayName: z.string()
|
|
374
|
+
})
|
|
375
|
+
)
|
|
376
|
+
}),
|
|
377
|
+
z.object({
|
|
378
|
+
success: z.literal(false),
|
|
379
|
+
error: z.string()
|
|
380
|
+
})
|
|
381
|
+
]);
|
|
382
|
+
var listAccountsTool = new ConnectorTool({
|
|
383
|
+
name: "listAccounts",
|
|
384
|
+
description: "List Google Analytics accounts accessible with the service account credentials. Returns account names and display names.",
|
|
385
|
+
inputSchema,
|
|
386
|
+
outputSchema,
|
|
387
|
+
async execute({ connectionId }, connections) {
|
|
388
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
389
|
+
if (!connection2) {
|
|
390
|
+
return {
|
|
391
|
+
success: false,
|
|
392
|
+
error: `Connection ${connectionId} not found`
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
console.log(
|
|
396
|
+
`[connector-request] google-analytics/${connection2.name}: listAccounts`
|
|
397
|
+
);
|
|
398
|
+
try {
|
|
399
|
+
const token = await getAccessToken(connection2);
|
|
400
|
+
const controller = new AbortController();
|
|
401
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
402
|
+
try {
|
|
403
|
+
const response = await fetch(`${ADMIN_BASE_URL}accounts`, {
|
|
404
|
+
method: "GET",
|
|
405
|
+
headers: {
|
|
406
|
+
Authorization: `Bearer ${token}`
|
|
407
|
+
},
|
|
408
|
+
signal: controller.signal
|
|
409
|
+
});
|
|
410
|
+
const data = await response.json();
|
|
411
|
+
if (!response.ok) {
|
|
412
|
+
const errorMessage = data?.error?.message ?? `HTTP ${response.status} ${response.statusText}`;
|
|
413
|
+
return { success: false, error: errorMessage };
|
|
414
|
+
}
|
|
415
|
+
const accounts = (data.accounts ?? []).map((a) => ({
|
|
416
|
+
name: a.name ?? "",
|
|
417
|
+
displayName: a.displayName ?? ""
|
|
418
|
+
}));
|
|
419
|
+
return { success: true, accounts };
|
|
420
|
+
} finally {
|
|
421
|
+
clearTimeout(timeout);
|
|
422
|
+
}
|
|
423
|
+
} catch (err) {
|
|
424
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
425
|
+
return { success: false, error: msg };
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// ../connectors/src/connectors/google-analytics/tools/list-properties.ts
|
|
431
|
+
import { z as z2 } from "zod";
|
|
432
|
+
var ADMIN_BASE_URL2 = "https://analyticsadmin.googleapis.com/v1beta/";
|
|
433
|
+
var REQUEST_TIMEOUT_MS2 = 6e4;
|
|
434
|
+
var inputSchema2 = z2.object({
|
|
435
|
+
toolUseIntent: z2.string().optional().describe(
|
|
436
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
437
|
+
),
|
|
438
|
+
connectionId: z2.string().describe("ID of the Google Analytics connection to use"),
|
|
439
|
+
accountName: z2.string().describe(
|
|
440
|
+
"The account resource name (e.g., 'accounts/123456'). Obtained from the listAccounts tool."
|
|
441
|
+
)
|
|
442
|
+
});
|
|
443
|
+
var outputSchema2 = z2.discriminatedUnion("success", [
|
|
444
|
+
z2.object({
|
|
445
|
+
success: z2.literal(true),
|
|
446
|
+
properties: z2.array(
|
|
447
|
+
z2.object({
|
|
448
|
+
name: z2.string(),
|
|
449
|
+
displayName: z2.string(),
|
|
450
|
+
propertyId: z2.string()
|
|
451
|
+
})
|
|
452
|
+
)
|
|
453
|
+
}),
|
|
454
|
+
z2.object({
|
|
455
|
+
success: z2.literal(false),
|
|
456
|
+
error: z2.string()
|
|
457
|
+
})
|
|
458
|
+
]);
|
|
459
|
+
var listPropertiesTool = new ConnectorTool({
|
|
460
|
+
name: "listProperties",
|
|
461
|
+
description: "List GA4 properties for a given Google Analytics account. Returns property names, display names, and property IDs.",
|
|
462
|
+
inputSchema: inputSchema2,
|
|
463
|
+
outputSchema: outputSchema2,
|
|
464
|
+
async execute({ connectionId, accountName }, connections) {
|
|
465
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
466
|
+
if (!connection2) {
|
|
467
|
+
return {
|
|
468
|
+
success: false,
|
|
469
|
+
error: `Connection ${connectionId} not found`
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
console.log(
|
|
473
|
+
`[connector-request] google-analytics/${connection2.name}: listProperties for ${accountName}`
|
|
474
|
+
);
|
|
475
|
+
try {
|
|
476
|
+
const token = await getAccessToken(connection2);
|
|
477
|
+
const controller = new AbortController();
|
|
478
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
479
|
+
try {
|
|
480
|
+
const filter = encodeURIComponent(`parent:${accountName}`);
|
|
481
|
+
const response = await fetch(
|
|
482
|
+
`${ADMIN_BASE_URL2}properties?filter=${filter}`,
|
|
483
|
+
{
|
|
484
|
+
method: "GET",
|
|
485
|
+
headers: {
|
|
486
|
+
Authorization: `Bearer ${token}`
|
|
487
|
+
},
|
|
488
|
+
signal: controller.signal
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
const data = await response.json();
|
|
492
|
+
if (!response.ok) {
|
|
493
|
+
const errorMessage = data?.error?.message ?? `HTTP ${response.status} ${response.statusText}`;
|
|
494
|
+
return { success: false, error: errorMessage };
|
|
495
|
+
}
|
|
496
|
+
const properties = (data.properties ?? []).map((p) => {
|
|
497
|
+
const name = p.name ?? "";
|
|
498
|
+
const propertyId = name.replace(/^properties\//, "");
|
|
499
|
+
return {
|
|
500
|
+
name,
|
|
501
|
+
displayName: p.displayName ?? "",
|
|
502
|
+
propertyId
|
|
503
|
+
};
|
|
504
|
+
});
|
|
505
|
+
return { success: true, properties };
|
|
506
|
+
} finally {
|
|
507
|
+
clearTimeout(timeout);
|
|
508
|
+
}
|
|
509
|
+
} catch (err) {
|
|
510
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
511
|
+
return { success: false, error: msg };
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
|
|
334
516
|
// ../connectors/src/connectors/google-analytics/setup.ts
|
|
517
|
+
var listAccountsToolName = `google-analytics_${listAccountsTool.name}`;
|
|
518
|
+
var listPropertiesToolName = `google-analytics_${listPropertiesTool.name}`;
|
|
335
519
|
var googleAnalyticsOnboarding = new ConnectorOnboarding({
|
|
520
|
+
connectionSetupInstructions: {
|
|
521
|
+
ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Analytics (Service Account) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
|
|
522
|
+
|
|
523
|
+
1. \`${listAccountsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001Service Account\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGoogle Analytics\u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
|
|
524
|
+
2. \u300C\u4F7F\u7528\u3059\u308B\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300D\u3068\u30E6\u30FC\u30B6\u30FC\u306B\u4F1D\u3048\u305F\u4E0A\u3067\u3001\`askUserQuestion\` \u3092\u547C\u3073\u51FA\u3059:
|
|
525
|
+
- \`options\`: \u30A2\u30AB\u30A6\u30F3\u30C8\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u8868\u793A\u540D (name)\` \u306E\u5F62\u5F0F
|
|
526
|
+
3. \`${listPropertiesToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u9078\u629E\u3055\u308C\u305F\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
|
|
527
|
+
4. \`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
528
|
+
- \`parameterSlug\`: \`"property-id"\`
|
|
529
|
+
- \`options\`: \u30D7\u30ED\u30D1\u30C6\u30A3\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u8868\u793A\u540D (id: \u30D7\u30ED\u30D1\u30C6\u30A3ID)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30D7\u30ED\u30D1\u30C6\u30A3ID
|
|
530
|
+
5. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\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
|
|
531
|
+
6. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3059:
|
|
532
|
+
- \`property\`: \u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u8868\u793A\u540D
|
|
533
|
+
- \`propertyId\`: \u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3ID
|
|
534
|
+
- \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
|
|
535
|
+
|
|
536
|
+
#### \u5236\u7D04
|
|
537
|
+
- **\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
|
|
538
|
+
- \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`,
|
|
539
|
+
en: `Follow these steps to set up the Google Analytics (Service Account) connection.
|
|
540
|
+
|
|
541
|
+
1. Call \`${listAccountsToolName}\` to get the list of Google Analytics accounts accessible with the service account credentials
|
|
542
|
+
2. Tell the user "Please select an account.", then call \`askUserQuestion\`:
|
|
543
|
+
- \`options\`: The account list. Each option's \`label\` should be \`Display Name (name)\`
|
|
544
|
+
3. Call \`${listPropertiesToolName}\` to get the list of properties for the selected account
|
|
545
|
+
4. Call \`updateConnectionParameters\`:
|
|
546
|
+
- \`parameterSlug\`: \`"property-id"\`
|
|
547
|
+
- \`options\`: The property list. Each option's \`label\` should be \`Display Name (id: propertyId)\`, \`value\` should be the property ID
|
|
548
|
+
5. The \`label\` of the user's selected property will arrive as a message. Proceed to the next step
|
|
549
|
+
6. Call \`updateConnectionContext\`:
|
|
550
|
+
- \`property\`: The selected property's display name
|
|
551
|
+
- \`propertyId\`: The selected property ID
|
|
552
|
+
- \`note\`: Brief description of the setup
|
|
553
|
+
|
|
554
|
+
#### Constraints
|
|
555
|
+
- **Do NOT fetch report data during setup**. Only the metadata requests specified in the steps above are allowed
|
|
556
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
557
|
+
},
|
|
336
558
|
dataOverviewInstructions: {
|
|
337
559
|
en: `1. Call google-analytics_request with GET properties/{propertyId}/metadata to list available dimensions and metrics
|
|
338
560
|
2. Call google-analytics_request with POST properties/{propertyId}:runReport using a small date range and basic metrics to verify data availability`,
|
|
@@ -342,25 +564,25 @@ var googleAnalyticsOnboarding = new ConnectorOnboarding({
|
|
|
342
564
|
});
|
|
343
565
|
|
|
344
566
|
// ../connectors/src/connectors/google-analytics/tools/request.ts
|
|
345
|
-
import { z } from "zod";
|
|
567
|
+
import { z as z3 } from "zod";
|
|
346
568
|
var BASE_URL2 = "https://analyticsdata.googleapis.com/v1beta/";
|
|
347
|
-
var
|
|
348
|
-
var
|
|
349
|
-
toolUseIntent:
|
|
350
|
-
connectionId:
|
|
351
|
-
method:
|
|
352
|
-
path:
|
|
353
|
-
body:
|
|
569
|
+
var REQUEST_TIMEOUT_MS3 = 6e4;
|
|
570
|
+
var inputSchema3 = z3.object({
|
|
571
|
+
toolUseIntent: z3.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
|
|
572
|
+
connectionId: z3.string().describe("ID of the Google Analytics connection to use"),
|
|
573
|
+
method: z3.enum(["GET", "POST"]).describe("HTTP method"),
|
|
574
|
+
path: z3.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."),
|
|
575
|
+
body: z3.record(z3.string(), z3.unknown()).optional().describe("POST request body (JSON)")
|
|
354
576
|
});
|
|
355
|
-
var
|
|
356
|
-
|
|
357
|
-
success:
|
|
358
|
-
status:
|
|
359
|
-
data:
|
|
577
|
+
var outputSchema3 = z3.discriminatedUnion("success", [
|
|
578
|
+
z3.object({
|
|
579
|
+
success: z3.literal(true),
|
|
580
|
+
status: z3.number(),
|
|
581
|
+
data: z3.record(z3.string(), z3.unknown())
|
|
360
582
|
}),
|
|
361
|
-
|
|
362
|
-
success:
|
|
363
|
-
error:
|
|
583
|
+
z3.object({
|
|
584
|
+
success: z3.literal(false),
|
|
585
|
+
error: z3.string()
|
|
364
586
|
})
|
|
365
587
|
]);
|
|
366
588
|
var requestTool = new ConnectorTool({
|
|
@@ -368,8 +590,8 @@ var requestTool = new ConnectorTool({
|
|
|
368
590
|
description: `Send authenticated requests to the Google Analytics Data API.
|
|
369
591
|
Authentication is handled automatically using a service account.
|
|
370
592
|
{propertyId} in the path is automatically replaced with the connection's property-id.`,
|
|
371
|
-
inputSchema,
|
|
372
|
-
outputSchema,
|
|
593
|
+
inputSchema: inputSchema3,
|
|
594
|
+
outputSchema: outputSchema3,
|
|
373
595
|
async execute({ connectionId, method, path: path2, body }, connections) {
|
|
374
596
|
const connection2 = connections.find((c) => c.id === connectionId);
|
|
375
597
|
if (!connection2) {
|
|
@@ -379,7 +601,7 @@ Authentication is handled automatically using a service account.
|
|
|
379
601
|
try {
|
|
380
602
|
const { GoogleAuth } = await import("google-auth-library");
|
|
381
603
|
const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
|
|
382
|
-
const propertyId = parameters.propertyId.
|
|
604
|
+
const propertyId = parameters.propertyId.tryGetValue(connection2);
|
|
383
605
|
const credentials = JSON.parse(
|
|
384
606
|
Buffer.from(keyJsonBase64, "base64").toString("utf-8")
|
|
385
607
|
);
|
|
@@ -391,10 +613,10 @@ Authentication is handled automatically using a service account.
|
|
|
391
613
|
if (!token) {
|
|
392
614
|
return { success: false, error: "Failed to obtain access token" };
|
|
393
615
|
}
|
|
394
|
-
const resolvedPath = path2.replace(/\{propertyId\}/g, propertyId);
|
|
616
|
+
const resolvedPath = propertyId ? path2.replace(/\{propertyId\}/g, propertyId) : path2;
|
|
395
617
|
const url = `${BASE_URL2}${resolvedPath}`;
|
|
396
618
|
const controller = new AbortController();
|
|
397
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
619
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS3);
|
|
398
620
|
try {
|
|
399
621
|
const response = await fetch(url, {
|
|
400
622
|
method,
|
|
@@ -425,7 +647,11 @@ Authentication is handled automatically using a service account.
|
|
|
425
647
|
});
|
|
426
648
|
|
|
427
649
|
// ../connectors/src/connectors/google-analytics/index.ts
|
|
428
|
-
var tools = {
|
|
650
|
+
var tools = {
|
|
651
|
+
request: requestTool,
|
|
652
|
+
listAccounts: listAccountsTool,
|
|
653
|
+
listProperties: listPropertiesTool
|
|
654
|
+
};
|
|
429
655
|
var googleAnalyticsConnector = new ConnectorPlugin({
|
|
430
656
|
slug: "google-analytics",
|
|
431
657
|
authType: AUTH_TYPES.SERVICE_ACCOUNT,
|
|
@@ -439,6 +665,8 @@ var googleAnalyticsConnector = new ConnectorPlugin({
|
|
|
439
665
|
en: `### Tools
|
|
440
666
|
|
|
441
667
|
- \`google-analytics_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.
|
|
668
|
+
- \`google-analytics_listAccounts\`: List accessible Google Analytics accounts. Use during setup to discover available accounts.
|
|
669
|
+
- \`google-analytics_listProperties\`: List GA4 properties for a given account. Use during setup to select the target property.
|
|
442
670
|
|
|
443
671
|
### Business Logic
|
|
444
672
|
|
|
@@ -507,6 +735,8 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
|
|
|
507
735
|
ja: `### \u30C4\u30FC\u30EB
|
|
508
736
|
|
|
509
737
|
- \`google-analytics_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
|
|
738
|
+
- \`google-analytics_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
|
|
739
|
+
- \`google-analytics_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
|
|
510
740
|
|
|
511
741
|
### Business Logic
|
|
512
742
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import * as _squadbase_connectors_sdk from '@squadbase/connectors/sdk';
|
|
2
|
+
import { GoogleCalendarClientOptions } from '@squadbase/connectors/sdk';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Create a Google Calendar SDK client for the given connection.
|
|
6
|
+
*
|
|
7
|
+
* @param connectionId - The connection ID from .squadbase/connections.json
|
|
8
|
+
* @param options - Optional configuration (e.g., subject for Domain-wide Delegation)
|
|
9
|
+
*/
|
|
10
|
+
declare const connection: (connectionId: string, options?: GoogleCalendarClientOptions) => _squadbase_connectors_sdk.GoogleCalendarConnectorSdk;
|
|
4
11
|
|
|
5
12
|
export { connection };
|
|
@@ -75,17 +75,19 @@ function base64url(input) {
|
|
|
75
75
|
const buf = typeof input === "string" ? Buffer.from(input) : input;
|
|
76
76
|
return buf.toString("base64url");
|
|
77
77
|
}
|
|
78
|
-
function buildJwt(clientEmail, privateKey, nowSec) {
|
|
78
|
+
function buildJwt(clientEmail, privateKey, nowSec, subject) {
|
|
79
79
|
const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
const claims = {
|
|
81
|
+
iss: clientEmail,
|
|
82
|
+
scope: SCOPE,
|
|
83
|
+
aud: TOKEN_URL,
|
|
84
|
+
iat: nowSec,
|
|
85
|
+
exp: nowSec + 3600
|
|
86
|
+
};
|
|
87
|
+
if (subject) {
|
|
88
|
+
claims.sub = subject;
|
|
89
|
+
}
|
|
90
|
+
const payload = base64url(JSON.stringify(claims));
|
|
89
91
|
const signingInput = `${header}.${payload}`;
|
|
90
92
|
const sign = crypto.createSign("RSA-SHA256");
|
|
91
93
|
sign.update(signingInput);
|
|
@@ -93,7 +95,7 @@ function buildJwt(clientEmail, privateKey, nowSec) {
|
|
|
93
95
|
const signature = base64url(sign.sign(privateKey));
|
|
94
96
|
return `${signingInput}.${signature}`;
|
|
95
97
|
}
|
|
96
|
-
function createClient(params) {
|
|
98
|
+
function createClient(params, options) {
|
|
97
99
|
const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
|
|
98
100
|
const defaultCalendarId = params[parameters.calendarId.slug] ?? "primary";
|
|
99
101
|
if (!serviceAccountKeyJsonBase64) {
|
|
@@ -118,6 +120,7 @@ function createClient(params) {
|
|
|
118
120
|
"google-calendar: service account key JSON must contain client_email and private_key"
|
|
119
121
|
);
|
|
120
122
|
}
|
|
123
|
+
const subject = options?.subject;
|
|
121
124
|
let cachedToken = null;
|
|
122
125
|
let tokenExpiresAt = 0;
|
|
123
126
|
async function getAccessToken() {
|
|
@@ -128,7 +131,8 @@ function createClient(params) {
|
|
|
128
131
|
const jwt = buildJwt(
|
|
129
132
|
serviceAccountKey.client_email,
|
|
130
133
|
serviceAccountKey.private_key,
|
|
131
|
-
nowSec
|
|
134
|
+
nowSec,
|
|
135
|
+
subject
|
|
132
136
|
);
|
|
133
137
|
const response = await fetch(TOKEN_URL, {
|
|
134
138
|
method: "POST",
|
|
@@ -177,18 +181,18 @@ function createClient(params) {
|
|
|
177
181
|
const data = await response.json();
|
|
178
182
|
return data.items ?? [];
|
|
179
183
|
},
|
|
180
|
-
async listEvents(
|
|
184
|
+
async listEvents(options2, calendarId) {
|
|
181
185
|
const cid = resolveCalendarId(calendarId);
|
|
182
186
|
const searchParams = new URLSearchParams();
|
|
183
|
-
if (
|
|
184
|
-
if (
|
|
185
|
-
if (
|
|
186
|
-
searchParams.set("maxResults", String(
|
|
187
|
-
if (
|
|
188
|
-
if (
|
|
189
|
-
searchParams.set("singleEvents", String(
|
|
190
|
-
if (
|
|
191
|
-
if (
|
|
187
|
+
if (options2?.timeMin) searchParams.set("timeMin", options2.timeMin);
|
|
188
|
+
if (options2?.timeMax) searchParams.set("timeMax", options2.timeMax);
|
|
189
|
+
if (options2?.maxResults)
|
|
190
|
+
searchParams.set("maxResults", String(options2.maxResults));
|
|
191
|
+
if (options2?.q) searchParams.set("q", options2.q);
|
|
192
|
+
if (options2?.singleEvents != null)
|
|
193
|
+
searchParams.set("singleEvents", String(options2.singleEvents));
|
|
194
|
+
if (options2?.orderBy) searchParams.set("orderBy", options2.orderBy);
|
|
195
|
+
if (options2?.pageToken) searchParams.set("pageToken", options2.pageToken);
|
|
192
196
|
const qs = searchParams.toString();
|
|
193
197
|
const path2 = `/calendars/${encodeURIComponent(cid)}/events${qs ? `?${qs}` : ""}`;
|
|
194
198
|
const response = await this.request(path2, { method: "GET" });
|
|
@@ -351,7 +355,10 @@ var inputSchema = z.object({
|
|
|
351
355
|
"API path appended to https://www.googleapis.com/calendar/v3 (e.g., '/calendars/{calendarId}/events'). {calendarId} is automatically replaced."
|
|
352
356
|
),
|
|
353
357
|
queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL"),
|
|
354
|
-
body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST/PUT/PATCH methods")
|
|
358
|
+
body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST/PUT/PATCH methods"),
|
|
359
|
+
subject: z.string().optional().describe(
|
|
360
|
+
"Email address of the user to impersonate via Domain-wide Delegation. When set, the service account acts on behalf of this user."
|
|
361
|
+
)
|
|
355
362
|
});
|
|
356
363
|
var outputSchema = z.discriminatedUnion("success", [
|
|
357
364
|
z.object({
|
|
@@ -371,7 +378,7 @@ Authentication is handled automatically using a service account.
|
|
|
371
378
|
{calendarId} in the path is automatically replaced with the connection's default calendar ID.`,
|
|
372
379
|
inputSchema,
|
|
373
380
|
outputSchema,
|
|
374
|
-
async execute({ connectionId, method, path: path2, queryParams, body }, connections) {
|
|
381
|
+
async execute({ connectionId, method, path: path2, queryParams, body, subject }, connections) {
|
|
375
382
|
const connection2 = connections.find((c) => c.id === connectionId);
|
|
376
383
|
if (!connection2) {
|
|
377
384
|
return {
|
|
@@ -394,7 +401,8 @@ Authentication is handled automatically using a service account.
|
|
|
394
401
|
scopes: [
|
|
395
402
|
"https://www.googleapis.com/auth/calendar.readonly",
|
|
396
403
|
"https://www.googleapis.com/auth/calendar.events.readonly"
|
|
397
|
-
]
|
|
404
|
+
],
|
|
405
|
+
...subject ? { clientOptions: { subject } } : {}
|
|
398
406
|
});
|
|
399
407
|
const token = await auth.getAccessToken();
|
|
400
408
|
if (!token) {
|
|
@@ -461,18 +469,26 @@ var googleCalendarConnector = new ConnectorPlugin({
|
|
|
461
469
|
systemPrompt: {
|
|
462
470
|
en: `### Tools
|
|
463
471
|
|
|
464
|
-
- \`google-calendar_request\`: The only way to call the Google Calendar API. Use it to list calendars, get events, and manage calendar data. Authentication is handled automatically using a service account. The {calendarId} placeholder in paths is automatically replaced with the configured default calendar ID.
|
|
472
|
+
- \`google-calendar_request\`: The only way to call the Google Calendar API. Use it to list calendars, get events, and manage calendar data. Authentication is handled automatically using a service account. The {calendarId} placeholder in paths is automatically replaced with the configured default calendar ID. Supports Domain-wide Delegation via the optional \`subject\` parameter to impersonate a user.
|
|
465
473
|
|
|
466
474
|
### Business Logic
|
|
467
475
|
|
|
468
476
|
The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
|
|
469
477
|
|
|
470
|
-
SDK methods (client created via \`connection(connectionId)\`):
|
|
478
|
+
SDK methods (client created via \`connection(connectionId)\` or \`connection(connectionId, { subject })\`):
|
|
471
479
|
- \`client.listCalendars()\` \u2014 list all accessible calendars
|
|
472
480
|
- \`client.listEvents(options?, calendarId?)\` \u2014 list events with optional filters
|
|
473
481
|
- \`client.getEvent(eventId, calendarId?)\` \u2014 get a single event by ID
|
|
474
482
|
- \`client.request(path, init?)\` \u2014 low-level authenticated fetch
|
|
475
483
|
|
|
484
|
+
#### Domain-wide Delegation
|
|
485
|
+
|
|
486
|
+
To access a user's calendar via Domain-wide Delegation, pass \`subject\` (the user's email) as the second argument to \`connection()\`:
|
|
487
|
+
|
|
488
|
+
\`\`\`ts
|
|
489
|
+
const calendar = connection("<connectionId>", { subject: "user@example.com" });
|
|
490
|
+
\`\`\`
|
|
491
|
+
|
|
476
492
|
\`\`\`ts
|
|
477
493
|
import type { Context } from "hono";
|
|
478
494
|
import { connection } from "@squadbase/vite-server/connectors/google-calendar";
|
|
@@ -524,18 +540,26 @@ export default async function handler(c: Context) {
|
|
|
524
540
|
- The default calendar ID is "primary" if not configured`,
|
|
525
541
|
ja: `### \u30C4\u30FC\u30EB
|
|
526
542
|
|
|
527
|
-
- \`google-calendar_request\`: Google Calendar API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7\u53D6\u5F97\u3001\u30A4\u30D9\u30F3\u30C8\u306E\u53D6\u5F97\u3001\u30AB\u30EC\u30F3\u30C0\u30FC\u30C7\u30FC\u30BF\u306E\u7BA1\u7406\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u4F7F\u7528\u3057\u3066\u8A8D\u8A3C\u306F\u81EA\u52D5\u7684\u306B\u51E6\u7406\u3055\u308C\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E{calendarId}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u8A2D\u5B9A\u6E08\u307F\u306E\u30C7\u30D5\u30A9\u30EB\u30C8\u30AB\u30EC\u30F3\u30C0\u30FCID\u3067\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002
|
|
543
|
+
- \`google-calendar_request\`: Google Calendar API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7\u53D6\u5F97\u3001\u30A4\u30D9\u30F3\u30C8\u306E\u53D6\u5F97\u3001\u30AB\u30EC\u30F3\u30C0\u30FC\u30C7\u30FC\u30BF\u306E\u7BA1\u7406\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u4F7F\u7528\u3057\u3066\u8A8D\u8A3C\u306F\u81EA\u52D5\u7684\u306B\u51E6\u7406\u3055\u308C\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E{calendarId}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u8A2D\u5B9A\u6E08\u307F\u306E\u30C7\u30D5\u30A9\u30EB\u30C8\u30AB\u30EC\u30F3\u30C0\u30FCID\u3067\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002Domain-wide Delegation\u3092\u4F7F\u7528\u3059\u308B\u5834\u5408\u3001\u30AA\u30D7\u30B7\u30E7\u30F3\u306E\`subject\`\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u30E6\u30FC\u30B6\u30FC\u3092\u507D\u88C5\u3067\u304D\u307E\u3059\u3002
|
|
528
544
|
|
|
529
545
|
### Business Logic
|
|
530
546
|
|
|
531
547
|
\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
|
|
532
548
|
|
|
533
|
-
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
549
|
+
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u307E\u305F\u306F \`connection(connectionId, { subject })\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
534
550
|
- \`client.listCalendars()\` \u2014 \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5168\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7\u53D6\u5F97
|
|
535
551
|
- \`client.listEvents(options?, calendarId?)\` \u2014 \u30D5\u30A3\u30EB\u30BF\u30FC\u4ED8\u304D\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7\u53D6\u5F97
|
|
536
552
|
- \`client.getEvent(eventId, calendarId?)\` \u2014 ID\u306B\u3088\u308B\u5358\u4E00\u30A4\u30D9\u30F3\u30C8\u53D6\u5F97
|
|
537
553
|
- \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
|
|
538
554
|
|
|
555
|
+
#### Domain-wide Delegation
|
|
556
|
+
|
|
557
|
+
Domain-wide Delegation\u3067\u30E6\u30FC\u30B6\u30FC\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u306B\u306F\u3001\`connection()\`\u306E\u7B2C2\u5F15\u6570\u306B\`subject\`\uFF08\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\uFF09\u3092\u6E21\u3057\u307E\u3059\uFF1A
|
|
558
|
+
|
|
559
|
+
\`\`\`ts
|
|
560
|
+
const calendar = connection("<connectionId>", { subject: "user@example.com" });
|
|
561
|
+
\`\`\`
|
|
562
|
+
|
|
539
563
|
\`\`\`ts
|
|
540
564
|
import type { Context } from "hono";
|
|
541
565
|
import { connection } from "@squadbase/vite-server/connectors/google-calendar";
|
|
@@ -649,7 +673,16 @@ function createConnectorSdk(plugin, createClient2) {
|
|
|
649
673
|
}
|
|
650
674
|
|
|
651
675
|
// src/connectors/entries/google-calendar.ts
|
|
652
|
-
var
|
|
676
|
+
var baseConnection = createConnectorSdk(googleCalendarConnector, createClient);
|
|
677
|
+
var connection = (connectionId, options) => {
|
|
678
|
+
if (options) {
|
|
679
|
+
return createConnectorSdk(
|
|
680
|
+
googleCalendarConnector,
|
|
681
|
+
(params) => createClient(params, options)
|
|
682
|
+
)(connectionId);
|
|
683
|
+
}
|
|
684
|
+
return baseConnection(connectionId);
|
|
685
|
+
};
|
|
653
686
|
export {
|
|
654
687
|
connection
|
|
655
688
|
};
|