@squadbase/vite-server 0.1.8-dev.d378524 → 0.1.9-dev.08f5c5f
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 +78505 -64782
- package/dist/cli/{sshcrypto-VVJOJ3LR.node → sshcrypto-P3UBA7BP.node} +0 -0
- package/dist/connectors/airtable-oauth.js +3 -0
- package/dist/connectors/airtable.js +3 -0
- package/dist/connectors/amplitude.js +3 -0
- package/dist/connectors/anthropic.js +3 -0
- package/dist/connectors/asana.js +18 -2
- package/dist/connectors/attio.js +3 -0
- package/dist/connectors/aws-billing.d.ts +5 -0
- package/dist/connectors/aws-billing.js +29843 -0
- package/dist/connectors/azure-sql.d.ts +5 -0
- package/dist/connectors/azure-sql.js +657 -0
- package/dist/connectors/backlog-api-key.js +3 -0
- package/dist/connectors/clickup.d.ts +5 -0
- package/dist/connectors/clickup.js +850 -0
- package/dist/connectors/customerio.js +3 -0
- package/dist/connectors/dbt.js +3 -0
- package/dist/connectors/freshdesk.d.ts +5 -0
- package/dist/connectors/freshdesk.js +842 -0
- package/dist/connectors/freshsales.d.ts +5 -0
- package/dist/connectors/freshsales.js +867 -0
- package/dist/connectors/freshservice.d.ts +5 -0
- package/dist/connectors/freshservice.js +813 -0
- package/dist/connectors/gamma.js +3 -0
- package/dist/connectors/gemini.js +3 -0
- package/dist/connectors/github.d.ts +5 -0
- package/dist/connectors/github.js +963 -0
- package/dist/connectors/gmail-oauth.js +18 -2
- package/dist/connectors/gmail.js +236 -352
- package/dist/connectors/google-ads.js +3 -0
- package/dist/connectors/google-analytics-oauth.js +3 -0
- package/dist/connectors/google-analytics.js +3 -0
- package/dist/connectors/google-audit-log.d.ts +5 -0
- package/dist/connectors/google-audit-log.js +813 -0
- package/dist/connectors/google-calendar-oauth.js +21 -2
- package/dist/connectors/google-calendar.js +548 -453
- package/dist/connectors/google-docs.js +21 -2
- package/dist/connectors/google-drive.js +18 -2
- package/dist/connectors/google-search-console-oauth.d.ts +5 -0
- package/dist/connectors/google-search-console-oauth.js +923 -0
- package/dist/connectors/google-sheets.js +21 -2
- package/dist/connectors/google-slides.js +21 -2
- package/dist/connectors/grafana.js +3 -0
- package/dist/connectors/hubspot-oauth.js +3 -0
- package/dist/connectors/hubspot.js +3 -0
- package/dist/connectors/influxdb.js +3 -0
- package/dist/connectors/intercom-oauth.js +3 -0
- package/dist/connectors/intercom.js +3 -0
- package/dist/connectors/jdbc.d.ts +5 -0
- package/dist/connectors/jdbc.js +21097 -0
- package/dist/connectors/jira-api-key.js +3 -0
- package/dist/connectors/kintone-api-token.js +3 -0
- package/dist/connectors/kintone.js +3 -0
- package/dist/connectors/linear.js +3 -0
- package/dist/connectors/linkedin-ads.js +3 -0
- package/dist/connectors/mailchimp-oauth.js +3 -0
- package/dist/connectors/mailchimp.js +3 -0
- package/dist/connectors/meta-ads-oauth.js +3 -0
- package/dist/connectors/meta-ads.js +3 -0
- package/dist/connectors/mixpanel.js +3 -0
- package/dist/connectors/monday.d.ts +5 -0
- package/dist/connectors/monday.js +813 -0
- package/dist/connectors/notion-oauth.js +3 -0
- package/dist/connectors/notion.js +3 -0
- package/dist/connectors/openai.js +3 -0
- package/dist/connectors/oracle.d.ts +5 -0
- package/dist/connectors/oracle.js +665 -0
- package/dist/connectors/salesforce.js +3 -0
- package/dist/connectors/semrush.d.ts +5 -0
- package/dist/connectors/semrush.js +812 -0
- package/dist/connectors/sentry.js +3 -0
- package/dist/connectors/shopify-oauth.js +3 -0
- package/dist/connectors/shopify.js +3 -0
- package/dist/connectors/sqlserver.d.ts +5 -0
- package/dist/connectors/sqlserver.js +656 -0
- package/dist/connectors/stripe-api-key.js +3 -0
- package/dist/connectors/stripe-oauth.js +3 -0
- package/dist/connectors/supabase.d.ts +5 -0
- package/dist/connectors/supabase.js +582 -0
- package/dist/connectors/tiktok-ads.js +18 -2
- package/dist/connectors/wix-store.js +3 -0
- package/dist/connectors/zendesk-oauth.js +3 -0
- package/dist/connectors/zendesk.js +3 -0
- package/dist/index.js +71474 -57751
- package/dist/main.js +78053 -64330
- package/dist/{sshcrypto-VVJOJ3LR.node → sshcrypto-P3UBA7BP.node} +0 -0
- package/dist/vite-plugin.js +77960 -64237
- package/package.json +64 -2
|
@@ -42,82 +42,28 @@ var ParameterDefinition = class {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
// ../connectors/src/connectors/google-calendar/sdk/index.ts
|
|
46
|
-
import * as crypto from "crypto";
|
|
47
|
-
|
|
48
45
|
// ../connectors/src/connectors/google-calendar/parameters.ts
|
|
49
46
|
var parameters = {
|
|
50
47
|
serviceAccountKeyJsonBase64: new ParameterDefinition({
|
|
51
48
|
slug: "service-account-key-json-base64",
|
|
52
49
|
name: "Google Cloud Service Account JSON",
|
|
53
|
-
description: "The service account JSON key
|
|
50
|
+
description: "The service account JSON key. Used for both Domain-wide Delegation (impersonating a Workspace user) and direct service-account access (calendars explicitly shared with the SA email). The authentication path is selected per call by the tool used.",
|
|
54
51
|
envVarBaseKey: "GOOGLE_CALENDAR_SERVICE_ACCOUNT_JSON_BASE64",
|
|
55
52
|
type: "base64EncodedJson",
|
|
56
53
|
secret: true,
|
|
57
54
|
required: true
|
|
58
55
|
})
|
|
59
56
|
};
|
|
60
|
-
var impersonateEmailParameter = new ParameterDefinition({
|
|
61
|
-
slug: "impersonate-email",
|
|
62
|
-
name: "User Email Address(es)",
|
|
63
|
-
description: "The email address(es) of the Google Workspace user(s) whose calendar is accessed via Domain-wide Delegation. Collected during the setup flow.",
|
|
64
|
-
envVarBaseKey: "GOOGLE_CALENDAR_IMPERSONATE_EMAIL",
|
|
65
|
-
type: "text",
|
|
66
|
-
secret: false,
|
|
67
|
-
required: false
|
|
68
|
-
});
|
|
69
|
-
var calendarIdParameter = new ParameterDefinition({
|
|
70
|
-
slug: "calendar-id",
|
|
71
|
-
name: "Default Calendar ID",
|
|
72
|
-
description: "The default Google Calendar ID to use (e.g., 'primary' or an email address like 'user@example.com'). If not set, 'primary' is used.",
|
|
73
|
-
envVarBaseKey: "GOOGLE_CALENDAR_CALENDAR_ID",
|
|
74
|
-
type: "text",
|
|
75
|
-
secret: false,
|
|
76
|
-
required: false
|
|
77
|
-
});
|
|
78
57
|
|
|
79
58
|
// ../connectors/src/connectors/google-calendar/sdk/index.ts
|
|
80
|
-
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
81
59
|
var BASE_URL = "https://www.googleapis.com/calendar/v3";
|
|
82
|
-
var SCOPE = "https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.events.readonly";
|
|
83
|
-
function base64url(input) {
|
|
84
|
-
const buf = typeof input === "string" ? Buffer.from(input) : input;
|
|
85
|
-
return buf.toString("base64url");
|
|
86
|
-
}
|
|
87
|
-
function buildJwt(clientEmail, privateKey, nowSec, subject) {
|
|
88
|
-
const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
89
|
-
const claims = {
|
|
90
|
-
iss: clientEmail,
|
|
91
|
-
scope: SCOPE,
|
|
92
|
-
aud: TOKEN_URL,
|
|
93
|
-
iat: nowSec,
|
|
94
|
-
exp: nowSec + 3600
|
|
95
|
-
};
|
|
96
|
-
if (subject) {
|
|
97
|
-
claims.sub = subject;
|
|
98
|
-
}
|
|
99
|
-
const payload = base64url(JSON.stringify(claims));
|
|
100
|
-
const signingInput = `${header}.${payload}`;
|
|
101
|
-
const sign = crypto.createSign("RSA-SHA256");
|
|
102
|
-
sign.update(signingInput);
|
|
103
|
-
sign.end();
|
|
104
|
-
const signature = base64url(sign.sign(privateKey));
|
|
105
|
-
return `${signingInput}.${signature}`;
|
|
106
|
-
}
|
|
107
60
|
function createClient(params) {
|
|
108
61
|
const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
|
|
109
|
-
const impersonateEmail = params[impersonateEmailParameter.slug];
|
|
110
|
-
const defaultCalendarId = params[calendarIdParameter.slug] ?? "primary";
|
|
111
62
|
if (!serviceAccountKeyJsonBase64) {
|
|
112
63
|
throw new Error(
|
|
113
64
|
`google-calendar: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
|
|
114
65
|
);
|
|
115
66
|
}
|
|
116
|
-
if (!impersonateEmail) {
|
|
117
|
-
throw new Error(
|
|
118
|
-
`google-calendar: missing required parameter: ${impersonateEmailParameter.slug}`
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
67
|
let serviceAccountKey;
|
|
122
68
|
try {
|
|
123
69
|
const decoded = Buffer.from(
|
|
@@ -135,101 +81,48 @@ function createClient(params) {
|
|
|
135
81
|
"google-calendar: service account key JSON must contain client_email and private_key"
|
|
136
82
|
);
|
|
137
83
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
let tokenExpiresAt = 0;
|
|
141
|
-
async function getAccessToken2() {
|
|
142
|
-
const nowSec = Math.floor(Date.now() / 1e3);
|
|
143
|
-
if (cachedToken && nowSec < tokenExpiresAt - 60) {
|
|
144
|
-
return cachedToken;
|
|
145
|
-
}
|
|
146
|
-
const jwt = buildJwt(
|
|
147
|
-
serviceAccountKey.client_email,
|
|
148
|
-
serviceAccountKey.private_key,
|
|
149
|
-
nowSec,
|
|
150
|
-
subject
|
|
151
|
-
);
|
|
152
|
-
const response = await fetch(TOKEN_URL, {
|
|
153
|
-
method: "POST",
|
|
154
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
155
|
-
body: new URLSearchParams({
|
|
156
|
-
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
157
|
-
assertion: jwt
|
|
158
|
-
})
|
|
159
|
-
});
|
|
160
|
-
if (!response.ok) {
|
|
161
|
-
const text = await response.text();
|
|
162
|
-
throw new Error(
|
|
163
|
-
`google-calendar: token exchange failed (${response.status}): ${text}`
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
const data = await response.json();
|
|
167
|
-
cachedToken = data.access_token;
|
|
168
|
-
tokenExpiresAt = nowSec + data.expires_in;
|
|
169
|
-
return cachedToken;
|
|
170
|
-
}
|
|
171
|
-
function resolveCalendarId(override) {
|
|
172
|
-
return override ?? defaultCalendarId;
|
|
84
|
+
function buildUrl(path2) {
|
|
85
|
+
return `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
173
86
|
}
|
|
174
87
|
return {
|
|
175
|
-
async
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return fetch(url, { ...init, headers });
|
|
185
|
-
},
|
|
186
|
-
async listCalendars() {
|
|
187
|
-
const response = await this.request("/users/me/calendarList", {
|
|
188
|
-
method: "GET"
|
|
88
|
+
async requestWithDelegation(path2, { subject, scopes, init }) {
|
|
89
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
90
|
+
const auth = new GoogleAuth({
|
|
91
|
+
credentials: {
|
|
92
|
+
client_email: serviceAccountKey.client_email,
|
|
93
|
+
private_key: serviceAccountKey.private_key
|
|
94
|
+
},
|
|
95
|
+
scopes,
|
|
96
|
+
clientOptions: { subject }
|
|
189
97
|
});
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
throw new Error(
|
|
193
|
-
`google-calendar: listCalendars failed (${response.status}): ${text}`
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
const data = await response.json();
|
|
197
|
-
return data.items ?? [];
|
|
198
|
-
},
|
|
199
|
-
async listEvents(options, calendarId) {
|
|
200
|
-
const cid = resolveCalendarId(calendarId);
|
|
201
|
-
const searchParams = new URLSearchParams();
|
|
202
|
-
if (options?.timeMin) searchParams.set("timeMin", options.timeMin);
|
|
203
|
-
if (options?.timeMax) searchParams.set("timeMax", options.timeMax);
|
|
204
|
-
if (options?.maxResults)
|
|
205
|
-
searchParams.set("maxResults", String(options.maxResults));
|
|
206
|
-
if (options?.q) searchParams.set("q", options.q);
|
|
207
|
-
if (options?.singleEvents != null)
|
|
208
|
-
searchParams.set("singleEvents", String(options.singleEvents));
|
|
209
|
-
if (options?.orderBy) searchParams.set("orderBy", options.orderBy);
|
|
210
|
-
if (options?.pageToken) searchParams.set("pageToken", options.pageToken);
|
|
211
|
-
const qs = searchParams.toString();
|
|
212
|
-
const path2 = `/calendars/${encodeURIComponent(cid)}/events${qs ? `?${qs}` : ""}`;
|
|
213
|
-
const response = await this.request(path2, { method: "GET" });
|
|
214
|
-
if (!response.ok) {
|
|
215
|
-
const text = await response.text();
|
|
98
|
+
const token = await auth.getAccessToken();
|
|
99
|
+
if (!token) {
|
|
216
100
|
throw new Error(
|
|
217
|
-
`google-calendar:
|
|
101
|
+
`google-calendar: failed to obtain access token (subject=${subject})`
|
|
218
102
|
);
|
|
219
103
|
}
|
|
220
|
-
|
|
104
|
+
const headers = new Headers(init?.headers);
|
|
105
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
106
|
+
return fetch(buildUrl(path2), { ...init, headers });
|
|
221
107
|
},
|
|
222
|
-
async
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
108
|
+
async request(path2, { scopes, init }) {
|
|
109
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
110
|
+
const auth = new GoogleAuth({
|
|
111
|
+
credentials: {
|
|
112
|
+
client_email: serviceAccountKey.client_email,
|
|
113
|
+
private_key: serviceAccountKey.private_key
|
|
114
|
+
},
|
|
115
|
+
scopes
|
|
116
|
+
});
|
|
117
|
+
const token = await auth.getAccessToken();
|
|
118
|
+
if (!token) {
|
|
228
119
|
throw new Error(
|
|
229
|
-
|
|
120
|
+
"google-calendar: failed to obtain access token (no subject)"
|
|
230
121
|
);
|
|
231
122
|
}
|
|
232
|
-
|
|
123
|
+
const headers = new Headers(init?.headers);
|
|
124
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
125
|
+
return fetch(buildUrl(path2), { ...init, headers });
|
|
233
126
|
}
|
|
234
127
|
};
|
|
235
128
|
}
|
|
@@ -287,6 +180,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
287
180
|
releaseFlag;
|
|
288
181
|
proxyPolicy;
|
|
289
182
|
experimentalAttributes;
|
|
183
|
+
categories;
|
|
290
184
|
onboarding;
|
|
291
185
|
systemPrompt;
|
|
292
186
|
tools;
|
|
@@ -302,6 +196,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
|
|
|
302
196
|
this.releaseFlag = config.releaseFlag;
|
|
303
197
|
this.proxyPolicy = config.proxyPolicy;
|
|
304
198
|
this.experimentalAttributes = config.experimentalAttributes;
|
|
199
|
+
this.categories = config.categories ?? [];
|
|
305
200
|
this.onboarding = config.onboarding;
|
|
306
201
|
this.systemPrompt = config.systemPrompt;
|
|
307
202
|
this.tools = config.tools;
|
|
@@ -381,97 +276,62 @@ var AUTH_TYPES = {
|
|
|
381
276
|
USER_PASSWORD: "user-password"
|
|
382
277
|
};
|
|
383
278
|
|
|
384
|
-
// ../connectors/src/connectors/google-calendar/tools/
|
|
385
|
-
import * as crypto2 from "crypto";
|
|
279
|
+
// ../connectors/src/connectors/google-calendar/tools/request.ts
|
|
386
280
|
import { z } from "zod";
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
function buildJwt2(clientEmail, privateKey, nowSec, subject) {
|
|
396
|
-
const header = base64url2(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
397
|
-
const payload = base64url2(
|
|
398
|
-
JSON.stringify({
|
|
399
|
-
iss: clientEmail,
|
|
400
|
-
sub: subject,
|
|
401
|
-
scope: SCOPE2,
|
|
402
|
-
aud: TOKEN_URL2,
|
|
403
|
-
iat: nowSec,
|
|
404
|
-
exp: nowSec + 3600
|
|
405
|
-
})
|
|
406
|
-
);
|
|
407
|
-
const signingInput = `${header}.${payload}`;
|
|
408
|
-
const sign = crypto2.createSign("RSA-SHA256");
|
|
409
|
-
sign.update(signingInput);
|
|
410
|
-
sign.end();
|
|
411
|
-
const signature = base64url2(sign.sign(privateKey));
|
|
412
|
-
return `${signingInput}.${signature}`;
|
|
413
|
-
}
|
|
414
|
-
async function getAccessToken(serviceAccount, subject) {
|
|
415
|
-
const nowSec = Math.floor(Date.now() / 1e3);
|
|
416
|
-
const jwt = buildJwt2(
|
|
417
|
-
serviceAccount.client_email,
|
|
418
|
-
serviceAccount.private_key,
|
|
419
|
-
nowSec,
|
|
420
|
-
subject
|
|
421
|
-
);
|
|
422
|
-
const response = await fetch(TOKEN_URL2, {
|
|
423
|
-
method: "POST",
|
|
424
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
425
|
-
body: new URLSearchParams({
|
|
426
|
-
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
427
|
-
assertion: jwt
|
|
428
|
-
})
|
|
429
|
-
});
|
|
430
|
-
if (!response.ok) {
|
|
431
|
-
const text = await response.text();
|
|
432
|
-
throw new Error(
|
|
433
|
-
`token exchange failed for ${subject} (${response.status}): ${text}`
|
|
434
|
-
);
|
|
281
|
+
|
|
282
|
+
// ../connectors/src/lib/normalize-path.ts
|
|
283
|
+
function normalizeRequestPath(path2, basePathSegment) {
|
|
284
|
+
let p = path2.trim();
|
|
285
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
286
|
+
if (p === basePathSegment || p.startsWith(basePathSegment + "/")) {
|
|
287
|
+
p = p.slice(basePathSegment.length) || "/";
|
|
435
288
|
}
|
|
436
|
-
|
|
437
|
-
|
|
289
|
+
return p;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ../connectors/src/connectors/google-calendar/tools/request.ts
|
|
293
|
+
var BASE_HOST = "https://www.googleapis.com";
|
|
294
|
+
var BASE_PATH_SEGMENT = "/calendar/v3";
|
|
295
|
+
var BASE_URL2 = `${BASE_HOST}${BASE_PATH_SEGMENT}`;
|
|
296
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
297
|
+
function decodeServiceAccount(keyJsonBase64) {
|
|
298
|
+
const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
|
|
299
|
+
return JSON.parse(decoded);
|
|
438
300
|
}
|
|
439
301
|
var inputSchema = z.object({
|
|
440
302
|
toolUseIntent: z.string().optional().describe(
|
|
441
303
|
"Brief description of what you intend to accomplish with this tool call"
|
|
442
304
|
),
|
|
443
|
-
connectionId: z.string().describe("ID of the Google Calendar connection to use")
|
|
305
|
+
connectionId: z.string().describe("ID of the Google Calendar connection to use"),
|
|
306
|
+
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method"),
|
|
307
|
+
path: z.string().describe(
|
|
308
|
+
"API path appended to https://www.googleapis.com/calendar/v3 (e.g., '/users/me/calendarList', '/calendars/team@example.com/events'). Write the calendar ID directly into the path \u2014 there is no placeholder substitution."
|
|
309
|
+
),
|
|
310
|
+
scopes: z.array(z.string()).describe(
|
|
311
|
+
"OAuth scopes the token must include. This connector currently supports read-only operations only \u2014 pass one of ['https://www.googleapis.com/auth/calendar.readonly'] (calendars + events read), ['https://www.googleapis.com/auth/calendar.events.readonly'] (events read only), or ['https://www.googleapis.com/auth/calendar.freebusy'] (busy/free queries only). Per-endpoint scope reference: https://developers.google.com/calendar/api/auth"
|
|
312
|
+
),
|
|
313
|
+
queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL"),
|
|
314
|
+
body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PUT/PATCH")
|
|
444
315
|
});
|
|
445
316
|
var outputSchema = z.discriminatedUnion("success", [
|
|
446
317
|
z.object({
|
|
447
318
|
success: z.literal(true),
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
id: z.string(),
|
|
452
|
-
summary: z.string(),
|
|
453
|
-
primary: z.boolean().optional(),
|
|
454
|
-
accessRole: z.string()
|
|
455
|
-
})
|
|
456
|
-
),
|
|
457
|
-
errors: z.array(
|
|
458
|
-
z.object({
|
|
459
|
-
impersonateEmail: z.string(),
|
|
460
|
-
error: z.string()
|
|
461
|
-
})
|
|
462
|
-
)
|
|
319
|
+
status: z.number(),
|
|
320
|
+
data: z.record(z.string(), z.unknown()),
|
|
321
|
+
serviceAccountEmail: z.string()
|
|
463
322
|
}),
|
|
464
323
|
z.object({
|
|
465
324
|
success: z.literal(false),
|
|
466
|
-
error: z.string()
|
|
325
|
+
error: z.string(),
|
|
326
|
+
serviceAccountEmail: z.string().optional()
|
|
467
327
|
})
|
|
468
328
|
]);
|
|
469
|
-
var
|
|
470
|
-
name: "
|
|
471
|
-
description: "
|
|
329
|
+
var requestTool = new ConnectorTool({
|
|
330
|
+
name: "request",
|
|
331
|
+
description: "Call the Google Calendar API as the service account itself (no delegation). Read-only operations only. Only calendars explicitly shared with the service account email are accessible. Pass `scopes` as a read-only Calendar scope (e.g., ['https://www.googleapis.com/auth/calendar.readonly']). Use this tool when the project knowledge records the calendar with `(service-account, ...)` (no `subject`).",
|
|
472
332
|
inputSchema,
|
|
473
333
|
outputSchema,
|
|
474
|
-
async execute({ connectionId }, connections) {
|
|
334
|
+
async execute({ connectionId, method, path: path2, scopes, queryParams, body }, connections) {
|
|
475
335
|
const connection2 = connections.find((c) => c.id === connectionId);
|
|
476
336
|
if (!connection2) {
|
|
477
337
|
return {
|
|
@@ -479,144 +339,97 @@ var listCalendarsTool = new ConnectorTool({
|
|
|
479
339
|
error: `Connection ${connectionId} not found`
|
|
480
340
|
};
|
|
481
341
|
}
|
|
482
|
-
const
|
|
483
|
-
const emails = impersonateEmailRaw.split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
484
|
-
if (emails.length === 0) {
|
|
485
|
-
return {
|
|
486
|
-
success: false,
|
|
487
|
-
error: "impersonate-email parameter is empty"
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
console.log(
|
|
491
|
-
`[connector-request] google-calendar/${connection2.name}: listCalendars for ${emails.join(",")}`
|
|
492
|
-
);
|
|
342
|
+
const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
|
|
493
343
|
let serviceAccount;
|
|
494
344
|
try {
|
|
495
|
-
|
|
496
|
-
const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
|
|
497
|
-
serviceAccount = JSON.parse(decoded);
|
|
345
|
+
serviceAccount = decodeServiceAccount(keyJsonBase64);
|
|
498
346
|
} catch (err) {
|
|
499
347
|
const msg = err instanceof Error ? err.message : String(err);
|
|
500
348
|
return {
|
|
501
349
|
success: false,
|
|
502
|
-
error: `
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
if (!serviceAccount.client_email || !serviceAccount.private_key) {
|
|
506
|
-
return {
|
|
507
|
-
success: false,
|
|
508
|
-
error: "service account key JSON must contain client_email and private_key"
|
|
350
|
+
error: `Failed to decode service account key: ${msg}`
|
|
509
351
|
};
|
|
510
352
|
}
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
|
|
353
|
+
const serviceAccountEmail = serviceAccount.client_email;
|
|
354
|
+
console.log(
|
|
355
|
+
`[connector-request] google-calendar/${connection2.name}: ${method} ${path2} (service account)`
|
|
356
|
+
);
|
|
357
|
+
try {
|
|
358
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
359
|
+
const auth = new GoogleAuth({
|
|
360
|
+
credentials: {
|
|
361
|
+
client_email: serviceAccount.client_email,
|
|
362
|
+
private_key: serviceAccount.private_key
|
|
363
|
+
},
|
|
364
|
+
scopes
|
|
365
|
+
});
|
|
366
|
+
const token = await auth.getAccessToken();
|
|
367
|
+
if (!token) {
|
|
368
|
+
return {
|
|
369
|
+
success: false,
|
|
370
|
+
error: "Failed to obtain access token",
|
|
371
|
+
serviceAccountEmail
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT);
|
|
375
|
+
let url = `${BASE_URL2}${normalizedPath}`;
|
|
376
|
+
if (queryParams) {
|
|
377
|
+
const searchParams = new URLSearchParams(queryParams);
|
|
378
|
+
url += `?${searchParams.toString()}`;
|
|
379
|
+
}
|
|
514
380
|
const controller = new AbortController();
|
|
515
381
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
516
382
|
try {
|
|
517
|
-
const
|
|
518
|
-
const response = await fetch(
|
|
519
|
-
method
|
|
520
|
-
headers: {
|
|
383
|
+
const hasBody = body != null && ["POST", "PUT", "PATCH"].includes(method);
|
|
384
|
+
const response = await fetch(url, {
|
|
385
|
+
method,
|
|
386
|
+
headers: {
|
|
387
|
+
Authorization: `Bearer ${token}`,
|
|
388
|
+
"Content-Type": "application/json"
|
|
389
|
+
},
|
|
390
|
+
body: hasBody ? JSON.stringify(body) : void 0,
|
|
521
391
|
signal: controller.signal
|
|
522
392
|
});
|
|
523
|
-
const data = await response.json();
|
|
393
|
+
const data = await response.json().catch(() => ({}));
|
|
524
394
|
if (!response.ok) {
|
|
525
395
|
const errorObj = data?.error;
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const items = data.items ?? [];
|
|
533
|
-
for (const c of items) {
|
|
534
|
-
aggregated.push({
|
|
535
|
-
impersonateEmail: email,
|
|
536
|
-
id: c.id,
|
|
537
|
-
summary: c.summary,
|
|
538
|
-
primary: c.primary,
|
|
539
|
-
accessRole: c.accessRole
|
|
540
|
-
});
|
|
396
|
+
const errorMessage = errorObj?.message ?? (typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`);
|
|
397
|
+
return {
|
|
398
|
+
success: false,
|
|
399
|
+
error: errorMessage,
|
|
400
|
+
serviceAccountEmail
|
|
401
|
+
};
|
|
541
402
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
403
|
+
return {
|
|
404
|
+
success: true,
|
|
405
|
+
status: response.status,
|
|
406
|
+
data,
|
|
407
|
+
serviceAccountEmail
|
|
408
|
+
};
|
|
545
409
|
} finally {
|
|
546
410
|
clearTimeout(timeout);
|
|
547
411
|
}
|
|
412
|
+
} catch (err) {
|
|
413
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
414
|
+
return {
|
|
415
|
+
success: false,
|
|
416
|
+
error: msg,
|
|
417
|
+
serviceAccountEmail
|
|
418
|
+
};
|
|
548
419
|
}
|
|
549
|
-
return {
|
|
550
|
-
success: true,
|
|
551
|
-
calendars: aggregated,
|
|
552
|
-
errors
|
|
553
|
-
};
|
|
554
420
|
}
|
|
555
421
|
});
|
|
556
422
|
|
|
557
|
-
// ../connectors/src/connectors/google-calendar/
|
|
558
|
-
var listCalendarsToolName = `google-calendar-service-account_${listCalendarsTool.name}`;
|
|
559
|
-
var googleCalendarOnboarding = new ConnectorOnboarding({
|
|
560
|
-
connectionSetupInstructions: {
|
|
561
|
-
ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Calendar\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002\u63A5\u7D9A\u4F5C\u6210\u6642\u306B\u306F\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8JSON\u306E\u307F\u304C\u8A2D\u5B9A\u6E08\u307F\u3067\u3001\u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3084\u30AB\u30EC\u30F3\u30C0\u30FCID\u306F\u3053\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u53D6\u5F97\u3057\u307E\u3059\u3002
|
|
562
|
-
|
|
563
|
-
1. \`askUserQuestion\` \u3067\u30E6\u30FC\u30B6\u30FC\u306B\u3001\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u304CDomain-wide Delegation\u3067\u4EE3\u7406\u30A2\u30AF\u30BB\u30B9\u3059\u308BGoogle Workspace\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u30D2\u30A2\u30EA\u30F3\u30B0\u3059\u308B:
|
|
564
|
-
- \`type\`: \`"freeText"\`
|
|
565
|
-
- \`question\`: \u300C\u30A2\u30AF\u30BB\u30B9\u3057\u305F\u3044\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u6301\u3064\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u3042\u308B\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\u3067\u5165\u529B\u53EF\uFF09\u300D
|
|
566
|
-
- \`placeholder\`: \`"user@example.com, admin@example.com"\`
|
|
567
|
-
2. \u30E6\u30FC\u30B6\u30FC\u304B\u3089\u53D7\u3051\u53D6\u3063\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\u5BFE\u5FDC\uFF09\u3092 \`updateConnectionParameters\` \u3067\u4FDD\u5B58\u3059\u308B:
|
|
568
|
-
- \`parameterSlug\`: \`"impersonate-email"\`
|
|
569
|
-
- \`options\`: \`[{ value: <\u5165\u529B\u3055\u308C\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u6587\u5B57\u5217>, label: <\u540C\u3058\u5024> }]\`\uFF081\u4EF6\u306E\u307F\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u81EA\u52D5\u9078\u629E\u3055\u308C\u308B\uFF09
|
|
570
|
-
3. \`${listCalendarsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3001\u4FDD\u5B58\u3057\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B\u3002
|
|
571
|
-
- \`errors\` \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A \`calendars\` \u304C\u7A7A\u306E\u5834\u5408\uFF08\u3059\u3079\u3066\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3067\u5931\u6557\uFF09\u3001\u5165\u529B\u3055\u308C\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u5B58\u5728\u3057\u306A\u3044\u53EF\u80FD\u6027\u304C\u3042\u308B\u3002\`askUserQuestion\` \u3067\u300C{\u5165\u529B\u3057\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9} \u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30A2\u30C9\u30EC\u30B9\u306B\u8AA4\u308A\u304C\u3042\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u4F3C\u305F\u30A2\u30C9\u30EC\u30B9\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u304B\uFF1F\u300D\u3068\u805E\u304D\u8FD4\u3057\u3001\u30B9\u30C6\u30C3\u30D72\u304B\u3089\u518D\u5EA6\u5B9F\u884C\u3059\u308B
|
|
572
|
-
4. \u8FD4\u5374\u3055\u308C\u305F \`calendars\` \u914D\u5217\uFF08\u5404\u8981\u7D20: \`{ impersonateEmail, id, summary, primary, accessRole }\`\uFF09\u3092\u5143\u306B\u300C\u4F7F\u7528\u3059\u308B\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300D\u3068\u77ED\u304F\u4F1D\u3048\u305F\u4E0A\u3067\u3001\`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
|
|
573
|
-
- \`parameterSlug\`: \`"calendar-id"\`
|
|
574
|
-
- \`options\`: \u5404 option \u306E \`label\` \u306F \`\u30AB\u30EC\u30F3\u30C0\u30FC\u540D (owner: impersonateEmail)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30AB\u30EC\u30F3\u30C0\u30FCID
|
|
575
|
-
- \`errors\` \u306B\u5931\u6557\u3057\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u3042\u308B\u5834\u5408\u306F\u3001\u305D\u306E\u65E8\u3092\u77ED\u304F\u4F1D\u3048\u308B
|
|
576
|
-
5. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\u306E \`label\` \u304B\u3089 owner \u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u62BD\u51FA\u3057\u3001\`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3057\u3066 \`impersonate-email\` \u3092\u6700\u7D42\u5024\u3067\u4E0A\u66F8\u304D\u3059\u308B:
|
|
577
|
-
- \`parameterSlug\`: \`"impersonate-email"\`
|
|
578
|
-
- \`options\`: \`[{ value: <ownerEmail>, label: <ownerEmail> }]\`
|
|
579
|
-
|
|
580
|
-
#### \u5236\u7D04
|
|
581
|
-
- **\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u8A2D\u5B9A\u304C\u5FC5\u8981\u3067\u3059**\u3002\`${listCalendarsToolName}\` \u306E \`errors\` \u306B\u6A29\u9650\u30A8\u30E9\u30FC\u304C\u51FA\u308B\u5834\u5408\u3001Google Workspace\u7BA1\u7406\u8005\u306BDomain-wide Delegation\u306E\u8A2D\u5B9A\u78BA\u8A8D\u3092\u4FC3\u3057\u3066\u304F\u3060\u3055\u3044
|
|
582
|
-
- \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`,
|
|
583
|
-
en: `Follow these steps to set up the Google Calendar connection. Only the service account JSON is provided at connection creation time \u2014 the target user email and calendar ID are collected during this setup flow.
|
|
584
|
-
|
|
585
|
-
1. Call \`askUserQuestion\` to ask the user for the Google Workspace user email the service account will impersonate via Domain-wide Delegation:
|
|
586
|
-
- \`type\`: \`"freeText"\`
|
|
587
|
-
- \`question\`: "Please enter the email address of the user whose calendar you want to access (comma-separated list allowed for multiple users)"
|
|
588
|
-
- \`placeholder\`: \`"user@example.com, admin@example.com"\`
|
|
589
|
-
2. Save the email(s) the user provided (comma-separated supported) via \`updateConnectionParameters\`:
|
|
590
|
-
- \`parameterSlug\`: \`"impersonate-email"\`
|
|
591
|
-
- \`options\`: \`[{ value: <the email string entered>, label: <same value> }]\` (a single option is auto-selected)
|
|
592
|
-
3. Call \`${listCalendarsToolName}\` to list calendars accessible via the saved email(s).
|
|
593
|
-
- If \`errors\` is non-empty and \`calendars\` is empty (all emails failed), the entered address may not exist. Use \`askUserQuestion\` to ask: "Could not access the calendar for {entered email}. The address may be incorrect \u2014 did you mean a similar address?" Then re-run from step 2 with the new input
|
|
594
|
-
4. Using the returned \`calendars\` array (each item: \`{ impersonateEmail, id, summary, primary, accessRole }\`), briefly say "Please select a calendar." then call \`updateConnectionParameters\`:
|
|
595
|
-
- \`parameterSlug\`: \`"calendar-id"\`
|
|
596
|
-
- \`options\`: Each option's \`label\` should be \`Calendar Name (owner: impersonateEmail)\`, \`value\` should be the calendar ID
|
|
597
|
-
- If \`errors\` contains failing email addresses, briefly mention them
|
|
598
|
-
5. Extract the owner email from the \`label\` of the user's selected calendar, then call \`updateConnectionParameters\` to overwrite \`impersonate-email\` with the final value:
|
|
599
|
-
- \`parameterSlug\`: \`"impersonate-email"\`
|
|
600
|
-
- \`options\`: \`[{ value: <ownerEmail>, label: <ownerEmail> }]\`
|
|
601
|
-
|
|
602
|
-
#### Constraints
|
|
603
|
-
- **Domain-wide Delegation must be configured on the service account**. If \`${listCalendarsToolName}\` returns permission errors in the \`errors\` field, ask the user to verify the Domain-wide Delegation setup with their Google Workspace administrator
|
|
604
|
-
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
605
|
-
},
|
|
606
|
-
dataOverviewInstructions: {
|
|
607
|
-
en: `1. Call google-calendar-service-account_request with GET /calendars/{calendarId} to get the default calendar's metadata
|
|
608
|
-
2. Call google-calendar-service-account_request with GET /users/me/calendarList to list all accessible calendars
|
|
609
|
-
3. Call google-calendar-service-account_request with GET /calendars/{calendarId}/events with query params timeMin (RFC3339) and maxResults=10 to sample upcoming events`,
|
|
610
|
-
ja: `1. google-calendar-service-account_request \u3067 GET /calendars/{calendarId} \u3092\u547C\u3073\u51FA\u3057\u3001\u30C7\u30D5\u30A9\u30EB\u30C8\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
|
|
611
|
-
2. google-calendar-service-account_request \u3067 GET /users/me/calendarList \u3092\u547C\u3073\u51FA\u3057\u3001\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5168\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7\u3092\u53D6\u5F97
|
|
612
|
-
3. google-calendar-service-account_request \u3067 GET /calendars/{calendarId}/events \u3092\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF timeMin\uFF08RFC3339\u5F62\u5F0F\uFF09\u3068 maxResults=10 \u3067\u547C\u3073\u51FA\u3057\u3001\u76F4\u8FD1\u306E\u30A4\u30D9\u30F3\u30C8\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0`
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
// ../connectors/src/connectors/google-calendar/tools/request.ts
|
|
423
|
+
// ../connectors/src/connectors/google-calendar/tools/request-with-delegation.ts
|
|
617
424
|
import { z as z2 } from "zod";
|
|
618
|
-
var
|
|
425
|
+
var BASE_HOST2 = "https://www.googleapis.com";
|
|
426
|
+
var BASE_PATH_SEGMENT2 = "/calendar/v3";
|
|
427
|
+
var BASE_URL3 = `${BASE_HOST2}${BASE_PATH_SEGMENT2}`;
|
|
619
428
|
var REQUEST_TIMEOUT_MS2 = 6e4;
|
|
429
|
+
function decodeServiceAccount2(keyJsonBase64) {
|
|
430
|
+
const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
|
|
431
|
+
return JSON.parse(decoded);
|
|
432
|
+
}
|
|
620
433
|
var inputSchema2 = z2.object({
|
|
621
434
|
toolUseIntent: z2.string().optional().describe(
|
|
622
435
|
"Brief description of what you intend to accomplish with this tool call"
|
|
@@ -624,33 +437,38 @@ var inputSchema2 = z2.object({
|
|
|
624
437
|
connectionId: z2.string().describe("ID of the Google Calendar connection to use"),
|
|
625
438
|
method: z2.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method"),
|
|
626
439
|
path: z2.string().describe(
|
|
627
|
-
"API path appended to https://www.googleapis.com/calendar/v3 (e.g., '/calendars/
|
|
440
|
+
"API path appended to https://www.googleapis.com/calendar/v3 (e.g., '/users/me/calendarList', '/calendars/alice@example.com/events'). Write the calendar ID directly into the path \u2014 there is no placeholder substitution."
|
|
628
441
|
),
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
442
|
+
subject: z2.string().describe(
|
|
443
|
+
"Email of the Workspace user to impersonate via Domain-wide Delegation. The token will be issued as this user."
|
|
444
|
+
),
|
|
445
|
+
scopes: z2.array(z2.string()).describe(
|
|
446
|
+
"OAuth scopes the token must include. This connector currently supports read-only operations only \u2014 pass one of ['https://www.googleapis.com/auth/calendar.readonly'] (calendars + events read), ['https://www.googleapis.com/auth/calendar.events.readonly'] (events read only), or ['https://www.googleapis.com/auth/calendar.freebusy'] (busy/free queries only). Per-endpoint scope reference: https://developers.google.com/calendar/api/auth"
|
|
447
|
+
),
|
|
448
|
+
queryParams: z2.record(z2.string(), z2.string()).optional().describe(
|
|
449
|
+
"Query parameters to append to the URL (e.g., { timeMin: '2025-01-01T00:00:00Z', maxResults: '10' })"
|
|
450
|
+
),
|
|
451
|
+
body: z2.record(z2.string(), z2.unknown()).optional().describe("JSON request body for POST/PUT/PATCH")
|
|
634
452
|
});
|
|
635
453
|
var outputSchema2 = z2.discriminatedUnion("success", [
|
|
636
454
|
z2.object({
|
|
637
455
|
success: z2.literal(true),
|
|
638
456
|
status: z2.number(),
|
|
639
|
-
data: z2.record(z2.string(), z2.unknown())
|
|
457
|
+
data: z2.record(z2.string(), z2.unknown()),
|
|
458
|
+
serviceAccountEmail: z2.string()
|
|
640
459
|
}),
|
|
641
460
|
z2.object({
|
|
642
461
|
success: z2.literal(false),
|
|
643
|
-
error: z2.string()
|
|
462
|
+
error: z2.string(),
|
|
463
|
+
serviceAccountEmail: z2.string().optional()
|
|
644
464
|
})
|
|
645
465
|
]);
|
|
646
|
-
var
|
|
647
|
-
name: "
|
|
648
|
-
description: `
|
|
649
|
-
Authentication is handled automatically using a service account.
|
|
650
|
-
{calendarId} in the path is automatically replaced with the connection's default calendar ID.`,
|
|
466
|
+
var requestWithDelegationTool = new ConnectorTool({
|
|
467
|
+
name: "request_with_delegation",
|
|
468
|
+
description: "Call the Google Calendar API on behalf of the specified Workspace user via Domain-wide Delegation. Read-only operations only. Pass `subject` as the target user email and `scopes` as a read-only Calendar scope (e.g., ['https://www.googleapis.com/auth/calendar.readonly']). Use this tool when the project knowledge records the calendar with `(delegation, subject: <email>, ...)`. Requires Domain-wide Delegation to be authorized for the service account in the Workspace admin console.",
|
|
651
469
|
inputSchema: inputSchema2,
|
|
652
470
|
outputSchema: outputSchema2,
|
|
653
|
-
async execute({ connectionId, method, path: path2, queryParams, body
|
|
471
|
+
async execute({ connectionId, method, path: path2, subject, scopes, queryParams, body }, connections) {
|
|
654
472
|
const connection2 = connections.find((c) => c.id === connectionId);
|
|
655
473
|
if (!connection2) {
|
|
656
474
|
return {
|
|
@@ -658,41 +476,41 @@ Authentication is handled automatically using a service account.
|
|
|
658
476
|
error: `Connection ${connectionId} not found`
|
|
659
477
|
};
|
|
660
478
|
}
|
|
479
|
+
const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
|
|
480
|
+
let serviceAccount;
|
|
481
|
+
try {
|
|
482
|
+
serviceAccount = decodeServiceAccount2(keyJsonBase64);
|
|
483
|
+
} catch (err) {
|
|
484
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
485
|
+
return {
|
|
486
|
+
success: false,
|
|
487
|
+
error: `Failed to decode service account key: ${msg}`
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
const serviceAccountEmail = serviceAccount.client_email;
|
|
661
491
|
console.log(
|
|
662
|
-
`[connector-request] google-calendar/${connection2.name}: ${method} ${path2}`
|
|
492
|
+
`[connector-request] google-calendar/${connection2.name}: ${method} ${path2} subject=${subject}`
|
|
663
493
|
);
|
|
664
494
|
try {
|
|
665
495
|
const { GoogleAuth } = await import("google-auth-library");
|
|
666
|
-
const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
|
|
667
|
-
const impersonateEmail = impersonateEmailParameter.tryGetValue(connection2);
|
|
668
|
-
const calendarId = calendarIdParameter.tryGetValue(connection2) ?? "primary";
|
|
669
|
-
const resolvedSubject = subject ?? impersonateEmail;
|
|
670
|
-
if (!resolvedSubject) {
|
|
671
|
-
return {
|
|
672
|
-
success: false,
|
|
673
|
-
error: `Missing required parameter: ${impersonateEmailParameter.slug}. Configure the user email for this connection.`
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
const credentials = JSON.parse(
|
|
677
|
-
Buffer.from(keyJsonBase64, "base64").toString("utf-8")
|
|
678
|
-
);
|
|
679
496
|
const auth = new GoogleAuth({
|
|
680
|
-
credentials
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
clientOptions: { subject
|
|
497
|
+
credentials: {
|
|
498
|
+
client_email: serviceAccount.client_email,
|
|
499
|
+
private_key: serviceAccount.private_key
|
|
500
|
+
},
|
|
501
|
+
scopes,
|
|
502
|
+
clientOptions: { subject }
|
|
686
503
|
});
|
|
687
504
|
const token = await auth.getAccessToken();
|
|
688
505
|
if (!token) {
|
|
689
506
|
return {
|
|
690
507
|
success: false,
|
|
691
|
-
error: "Failed to obtain access token"
|
|
508
|
+
error: "Failed to obtain access token",
|
|
509
|
+
serviceAccountEmail
|
|
692
510
|
};
|
|
693
511
|
}
|
|
694
|
-
const
|
|
695
|
-
let url = `${BASE_URL3}${
|
|
512
|
+
const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT2);
|
|
513
|
+
let url = `${BASE_URL3}${normalizedPath}`;
|
|
696
514
|
if (queryParams) {
|
|
697
515
|
const searchParams = new URLSearchParams(queryParams);
|
|
698
516
|
url += `?${searchParams.toString()}`;
|
|
@@ -700,43 +518,265 @@ Authentication is handled automatically using a service account.
|
|
|
700
518
|
const controller = new AbortController();
|
|
701
519
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
702
520
|
try {
|
|
521
|
+
const hasBody = body != null && ["POST", "PUT", "PATCH"].includes(method);
|
|
703
522
|
const response = await fetch(url, {
|
|
704
523
|
method,
|
|
705
524
|
headers: {
|
|
706
525
|
Authorization: `Bearer ${token}`,
|
|
707
526
|
"Content-Type": "application/json"
|
|
708
527
|
},
|
|
709
|
-
body:
|
|
528
|
+
body: hasBody ? JSON.stringify(body) : void 0,
|
|
710
529
|
signal: controller.signal
|
|
711
530
|
});
|
|
712
|
-
|
|
713
|
-
return {
|
|
714
|
-
success: true,
|
|
715
|
-
status: 204,
|
|
716
|
-
data: { message: "Deleted successfully" }
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
const data = await response.json();
|
|
531
|
+
const data = await response.json().catch(() => ({}));
|
|
720
532
|
if (!response.ok) {
|
|
721
533
|
const errorObj = data?.error;
|
|
534
|
+
const errorMessage = errorObj?.message ?? (typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`);
|
|
722
535
|
return {
|
|
723
536
|
success: false,
|
|
724
|
-
error:
|
|
537
|
+
error: errorMessage,
|
|
538
|
+
serviceAccountEmail
|
|
725
539
|
};
|
|
726
540
|
}
|
|
727
|
-
return {
|
|
541
|
+
return {
|
|
542
|
+
success: true,
|
|
543
|
+
status: response.status,
|
|
544
|
+
data,
|
|
545
|
+
serviceAccountEmail
|
|
546
|
+
};
|
|
728
547
|
} finally {
|
|
729
548
|
clearTimeout(timeout);
|
|
730
549
|
}
|
|
731
550
|
} catch (err) {
|
|
732
551
|
const msg = err instanceof Error ? err.message : String(err);
|
|
733
|
-
return {
|
|
552
|
+
return {
|
|
553
|
+
success: false,
|
|
554
|
+
error: msg,
|
|
555
|
+
serviceAccountEmail
|
|
556
|
+
};
|
|
734
557
|
}
|
|
735
558
|
}
|
|
736
559
|
});
|
|
737
560
|
|
|
561
|
+
// ../connectors/src/connectors/google-calendar/setup.ts
|
|
562
|
+
var requestToolName = `google-calendar-service-account_${requestTool.name}`;
|
|
563
|
+
var requestWithDelegationToolName = `google-calendar-service-account_${requestWithDelegationTool.name}`;
|
|
564
|
+
var READONLY_SCOPES = '["https://www.googleapis.com/auth/calendar.readonly"]';
|
|
565
|
+
var SERVICE_ACCOUNT_KEY_PARAM_SLUG = parameters.serviceAccountKeyJsonBase64.slug;
|
|
566
|
+
var googleCalendarOnboarding = new ConnectorOnboarding({
|
|
567
|
+
connectionSetupInstructions: {
|
|
568
|
+
ja: `Google Calendar \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u3092\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3057\u307E\u3059\u3002\u30A2\u30AF\u30BB\u30B9\u65B9\u6CD5\u3092\u9078\u3093\u3067\u3082\u3089\u3044\u3001\u5BFE\u8C61\u30AB\u30EC\u30F3\u30C0\u30FC\u3092 Project Knowledge \u306B\u8A18\u9332\u3057\u307E\u3059\u3002
|
|
569
|
+
|
|
570
|
+
## \u30B9\u30C6\u30C3\u30D7 0: \u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u5F97
|
|
571
|
+
|
|
572
|
+
\u4EE5\u964D\u306E\u30B9\u30C6\u30C3\u30D7\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u6848\u5185\u3059\u308B\u305F\u3081\u306B\u3001\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002
|
|
573
|
+
|
|
574
|
+
\`${requestToolName}\` \u3092\u4EE5\u4E0B\u306E\u5F15\u6570\u3067 1 \u56DE\u547C\u3073\u3001\u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`serviceAccountEmail\` \u3092\u4FDD\u6301\u3059\u308B:
|
|
575
|
+
- \`method\`: \`"GET"\`
|
|
576
|
+
- \`path\`: \`"/users/me/calendarList"\`
|
|
577
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
578
|
+
|
|
579
|
+
\u6210\u529F\u30FB\u5931\u6557\u3069\u3061\u3089\u3067\u3082 \`serviceAccountEmail\` \u306F\u8FD4\u3063\u3066\u304F\u308B\u306E\u3067\u3001\u7D50\u679C\u306E\u30EA\u30B9\u30C8\u306F\u3053\u306E\u30B9\u30C6\u30C3\u30D7\u3067\u306F\u7121\u8996\u3057\u3066\u3088\u3044\u3002\u4EE5\u964D\u3053\u306E\u5024\u3092 \`<serviceAccountEmail>\` \u3068\u3057\u3066\u53C2\u7167\u3059\u308B\u3002
|
|
580
|
+
|
|
581
|
+
## \u30B9\u30C6\u30C3\u30D7 1: \u30A2\u30AF\u30BB\u30B9\u65B9\u6CD5\u3092\u9078\u629E
|
|
582
|
+
|
|
583
|
+
\`askUserQuestion\` \u3067\u6B21\u306E 3 \u629E\u3092\u63D0\u793A\u3059\u308B:
|
|
584
|
+
- \`type\`: \`"select"\`
|
|
585
|
+
- \`question\`: \u300C\u3069\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u307E\u3059\u304B\uFF1F\u300D
|
|
586
|
+
- \`options\`:
|
|
587
|
+
- \`{ label: "\u3053\u306E\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306B\u5171\u6709\u3055\u308C\u3066\u3044\u308B\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u4F7F\u3046", value: "service-account" }\`
|
|
588
|
+
- \`{ label: "\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u3067\u7D44\u7E54\u306E\u30E6\u30FC\u30B6\u30FC\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B", value: "delegation" }\`
|
|
589
|
+
- \`{ label: "\u4E21\u65B9\u3092\u7D44\u307F\u5408\u308F\u305B\u308B", value: "both" }\`
|
|
590
|
+
|
|
591
|
+
## \u30B9\u30C6\u30C3\u30D7 2: \u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u7D4C\u8DEF (\`"service-account"\` \u307E\u305F\u306F \`"both"\` \u306E\u5834\u5408)
|
|
592
|
+
|
|
593
|
+
\u30E6\u30FC\u30B6\u30FC\u304C\u3042\u3089\u304B\u3058\u3081\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8 \`<serviceAccountEmail>\` \u306B\u5171\u6709\u8A2D\u5B9A\u3057\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\u306E ID \u3092\u76F4\u63A5\u53D7\u3051\u53D6\u308A\u3001\u758E\u901A\u78BA\u8A8D\u3057\u307E\u3059\u3002multiSelect \u306F\u51FA\u3055\u306A\u3044 (\u30E6\u30FC\u30B6\u30FC\u304C\u5165\u529B\u3057\u305F\u6642\u70B9\u3067\u5BFE\u8C61\u304C\u78BA\u5B9A\u3057\u3066\u3044\u308B\u305F\u3081)\u3002
|
|
594
|
+
|
|
595
|
+
1. \`askUserQuestion\` \u3067\u30AB\u30EC\u30F3\u30C0\u30FC ID \u3092\u805E\u304F:
|
|
596
|
+
- \`type\`: \`"freeText"\`
|
|
597
|
+
- \`question\`: \u300C\u30A2\u30AF\u30BB\u30B9\u3057\u305F\u3044\u30AB\u30EC\u30F3\u30C0\u30FC\u306E ID \u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u53EF\u3001\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09\u3002\u3042\u3089\u304B\u3058\u3081 \`<serviceAccountEmail>\` \u306B\u5171\u6709\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u30E1\u30A4\u30F3\u30AB\u30EC\u30F3\u30C0\u30FC\u306F\u6240\u6709\u8005\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u305D\u306E\u307E\u307E\u5165\u529B\u3067\u304D\u307E\u3059\u3002\u305D\u308C\u4EE5\u5916\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\uFF08\u30C1\u30FC\u30E0\u30AB\u30EC\u30F3\u30C0\u30FC\u7B49\uFF09\u306F Google Calendar \u306E\u8A2D\u5B9A\u304B\u3089\u300C\u30AB\u30EC\u30F3\u30C0\u30FC ID\u300D\u3092\u30B3\u30D4\u30FC\u3057\u3066\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300D
|
|
598
|
+
- \`placeholder\`: \`"alice@example.com, c_xxx@group.calendar.google.com"\`
|
|
599
|
+
|
|
600
|
+
2. \u5165\u529B\u3055\u308C\u305F\u5404\u30AB\u30EC\u30F3\u30C0\u30FC ID \`<id>\` \u306B\u3064\u3044\u3066 \`${requestToolName}\` \u3067\u758E\u901A\u78BA\u8A8D:
|
|
601
|
+
- \`method\`: \`"GET"\`
|
|
602
|
+
- \`path\`: \`"/calendars/<id>"\`
|
|
603
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
604
|
+
- \u6210\u529F\u3059\u308C\u3070\u3001\u30EC\u30B9\u30DD\u30F3\u30B9 \`data.summary\` \u3092\u30AB\u30EC\u30F3\u30C0\u30FC\u540D\u3068\u3057\u3066\u4FDD\u6301
|
|
605
|
+
- \u5931\u6557 (404 / 403 \u7B49) \u306F\u30A2\u30AF\u30BB\u30B9\u4E0D\u53EF\u3068\u3057\u3066\u8A18\u9332
|
|
606
|
+
|
|
607
|
+
3. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
|
|
608
|
+
- **\u5168 ID \u5931\u6557**: \u30A2\u30AF\u30BB\u30B9\u65B9\u6CD5\u304C \`"service-account"\` \u3060\u3051\u306A\u3089\u30B9\u30C6\u30C3\u30D7 5 \u3078\u3002\`"both"\` \u306E\u5834\u5408\u306F\u305D\u306E\u307E\u307E\u30B9\u30C6\u30C3\u30D7 3 \u3078\u9032\u3080
|
|
609
|
+
- **\u4E00\u90E8\u307E\u305F\u306F\u5168\u4EF6\u6210\u529F**: \u6210\u529F\u3057\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u305D\u306E\u307E\u307E\u30B9\u30C6\u30C3\u30D7 4 \u7528\u306E\u9078\u629E\u7D50\u679C\u3068\u3057\u3066\u78BA\u5B9A\u3059\u308B\u3002\u5931\u6557\u304C\u3042\u308C\u3070\u3001\u305D\u306E\u65E8\u3092 1 \u6587\u3067\u77ED\u304F\u4F1D\u3048\u308B
|
|
610
|
+
|
|
611
|
+
## \u30B9\u30C6\u30C3\u30D7 3: \u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u7D4C\u8DEF (\`"delegation"\` \u307E\u305F\u306F \`"both"\` \u306E\u5834\u5408)
|
|
612
|
+
|
|
613
|
+
\u5404 Workspace \u30E6\u30FC\u30B6\u30FC\u304C\u6301\u3063\u3066\u3044\u308B\u591A\u6570\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u304B\u3089\u3001\u5BFE\u8C61\u3092\u7D5E\u308A\u8FBC\u307F\u307E\u3059\u3002
|
|
614
|
+
|
|
615
|
+
1. \`askUserQuestion\` \u3067\u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u805E\u304F:
|
|
616
|
+
- \`type\`: \`"freeText"\`
|
|
617
|
+
- \`question\`: \u300C\u30A2\u30AF\u30BB\u30B9\u3057\u305F\u3044\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u6240\u6709\u3059\u308B Google Workspace \u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u53EF\u3001\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09\u3002Workspace \u7BA1\u7406\u8005\u304C\u3042\u3089\u304B\u3058\u3081\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8 \`<serviceAccountEmail>\` \u306B\u5BFE\u3057\u3066\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u3092\u627F\u8A8D\u3057\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08[\u7BA1\u7406\u8005\u5411\u3051\u8A2D\u5B9A\u30AC\u30A4\u30C9](https://support.google.com/a/answer/162106)\uFF09\u3002\u300D
|
|
618
|
+
- \`placeholder\`: \`"alice@example.com, bob@example.com"\`
|
|
619
|
+
|
|
620
|
+
2. \u5165\u529B\u3055\u308C\u305F\u5404\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9 \`<email>\` \u306B\u3064\u3044\u3066 \`${requestWithDelegationToolName}\` \u3092\u547C\u3073\u3001\u305D\u306E\u30E6\u30FC\u30B6\u30FC\u304C\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u308B\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7\u3092\u53D6\u5F97:
|
|
621
|
+
- \`method\`: \`"GET"\`
|
|
622
|
+
- \`path\`: \`"/users/me/calendarList"\`
|
|
623
|
+
- \`subject\`: \`<email>\`
|
|
624
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
625
|
+
|
|
626
|
+
3. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
|
|
627
|
+
- **\u5168 email \u3067\u5931\u6557**: \u30A2\u30AF\u30BB\u30B9\u65B9\u6CD5\u304C \`"delegation"\` \u3060\u3051\u3001\u307E\u305F\u306F \`"both"\` \u3067\u30B9\u30C6\u30C3\u30D7 2 \u3067\u3082 0 \u4EF6\u306E\u3068\u304D\u306F\u30B9\u30C6\u30C3\u30D7 5 \u3078\u3002\`"both"\` \u3067\u30B9\u30C6\u30C3\u30D7 2 \u306B\u30AB\u30EC\u30F3\u30C0\u30FC\u304C\u3042\u308C\u3070\u3001\u305D\u306E\u307E\u307E\u30B9\u30C6\u30C3\u30D7 4 \u3078\u9032\u3080
|
|
628
|
+
- **\u4E00\u90E8\u307E\u305F\u306F\u5168\u4EF6\u6210\u529F**: \`askUserQuestion\` \u3067\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u7D5E\u308A\u8FBC\u307E\u305B\u308B
|
|
629
|
+
- \`type\`: \`"multiSelect"\`
|
|
630
|
+
- \`question\`: \u300C\u4F7F\u7528\u3059\u308B\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u53EF\uFF09\u300D
|
|
631
|
+
- \`options\`: \u767A\u898B\u3057\u305F\u5404\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u3064\u3044\u3066 \`label\`: \`"<\u30AB\u30EC\u30F3\u30C0\u30FC\u540D> (\u6240\u6709\u8005: <\u305D\u306E\u3068\u304D\u306E subject>)"\`\u3001\`value\`: \`"<calendarId>"\`
|
|
632
|
+
- \u4E00\u90E8\u5931\u6557\u304C\u3042\u308C\u3070\u3001\u305D\u306E\u65E8\u3092 1 \u6587\u3067\u77ED\u304F\u4F1D\u3048\u308B
|
|
633
|
+
|
|
634
|
+
## \u30B9\u30C6\u30C3\u30D7 4: Project Knowledge \u306B\u8A18\u9332
|
|
635
|
+
|
|
636
|
+
\u30B9\u30C6\u30C3\u30D7 2 \u3068 3 \u3067\u78BA\u5B9A\u3057\u305F calendarId \u96C6\u5408\u3092\u7D71\u5408\u3059\u308B\u3002\u5404 calendarId \u306B\u3064\u3044\u3066\u3001\u30B9\u30C6\u30C3\u30D7 2 \u3067\u758E\u901A\u78BA\u8A8D\u3057\u305F\u7D50\u679C\u304B\u3001\u30B9\u30C6\u30C3\u30D7 3 \u306E\u30C7\u30A3\u30B9\u30AB\u30D0\u30EA\u7D50\u679C\u304B\u3089\u7D4C\u8DEF\u3068 (delegation \u306E\u5834\u5408\u306F) subject \u3092\u7279\u5B9A\u3059\u308B\u3002\`finalizeSetup\` \u3092\u547C\u3073\u3001\u5404\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u300C\u30AB\u30EC\u30F3\u30C0\u30FC\u540D\u30FB\u30AB\u30EC\u30F3\u30C0\u30FC ID\u30FB\u30A2\u30AF\u30BB\u30B9\u7D4C\u8DEF\uFF08delegation \u304B service-account \u304B\uFF09\u30FBdelegation \u306E\u5834\u5408\u306F subject\u300D\u3068\u3068\u3082\u306B\u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30B9\u30B3\u30FC\u30D7\u60C5\u5831\u3068\u3057\u3066\u8A18\u9332\u3059\u308B\u3002
|
|
637
|
+
|
|
638
|
+
## \u30B9\u30C6\u30C3\u30D7 5: \u6700\u7D42\u7684\u306B\u30AB\u30EC\u30F3\u30C0\u30FC\u304C 0 \u4EF6\u306E\u3068\u304D\u306E\u30A8\u30B9\u30AB\u30EC\u30FC\u30B7\u30E7\u30F3
|
|
639
|
+
|
|
640
|
+
\u6700\u7D42\u7684\u306B\u5BFE\u8C61\u30AB\u30EC\u30F3\u30C0\u30FC\u304C 1 \u4EF6\u3082\u306A\u3044\u5834\u5408\u3001\`askUserQuestion\` \u3067\u6B21\u306E\u3088\u3046\u306B\u6848\u5185\u3059\u308B:
|
|
641
|
+
|
|
642
|
+
- \`question\`: \u300C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30AB\u30EC\u30F3\u30C0\u30FC\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8 \`<serviceAccountEmail>\` \u3067\u6B21\u306E\u3044\u305A\u308C\u304B\u3092\u884C\u3063\u3066\u304B\u3089\u7D9A\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300D
|
|
643
|
+
- \`options\`: \u3053\u3053\u307E\u3067\u306B\u8A66\u3057\u305F\u7D4C\u8DEF\u306B\u5FDC\u3058\u3066\u4EE5\u4E0B\u3092\u7D44\u307F\u5408\u308F\u305B\u308B:
|
|
644
|
+
- \u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u7D4C\u8DEF\u3092\u8A66\u3057\u305F\u5834\u5408: \`{ label: "\u5BFE\u8C61\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306B\u5171\u6709\u3057\u305F\u306E\u3067\u30EA\u30C8\u30E9\u30A4", value: "retry" }\`
|
|
645
|
+
- \u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u7D4C\u8DEF\u3092\u8A66\u3057\u305F\u5834\u5408: \`{ label: "\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u3092\u627F\u8A8D\u3057\u305F\u306E\u3067\u30EA\u30C8\u30E9\u30A4", value: "retry" }\`
|
|
646
|
+
- \u5E38\u306B: \`{ label: "\u30A2\u30AF\u30BB\u30B9\u65B9\u6CD5\u3092\u5909\u66F4\u3059\u308B", value: "restart" }\`
|
|
647
|
+
- \u5E38\u306B: \`{ label: "\u5225\u306E\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u3067\u8A2D\u5B9A\u3057\u76F4\u3059", value: "change-service-account" }\`
|
|
648
|
+
|
|
649
|
+
\u9078\u629E\u7D50\u679C\u306B\u5FDC\u3058\u305F\u6319\u52D5:
|
|
650
|
+
- "retry": \u76F4\u524D\u306E\u7D4C\u8DEF\u3092\u518D probe (\u30EA\u30C8\u30E9\u30A4\u306E\u4ED5\u65B9\u306F\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u304C\u6587\u8108\u306B\u5FDC\u3058\u3066\u5224\u65AD)
|
|
651
|
+
- "restart": \u30B9\u30C6\u30C3\u30D7 1 \u304B\u3089\u518D\u5B9F\u884C
|
|
652
|
+
- "change-service-account": \`updateConnectionParameters\` \u3092\u547C\u3093\u3067\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8 JSON \u3092\u518D\u5165\u529B\u3055\u305B\u308B:
|
|
653
|
+
- \`parameterSlug\`: \`"${SERVICE_ACCOUNT_KEY_PARAM_SLUG}"\`
|
|
654
|
+
- \u5B8C\u4E86\u5F8C\u3001\u30B9\u30C6\u30C3\u30D7 0 \u304B\u3089\u518D\u5B9F\u884C
|
|
655
|
+
|
|
656
|
+
## \u5236\u7D04
|
|
657
|
+
|
|
658
|
+
- \u4E0A\u8A18\u4EE5\u5916\u306E API \u547C\u3073\u51FA\u3057\u3092 setup \u4E2D\u306B\u884C\u308F\u306A\u3044
|
|
659
|
+
- \u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u306E\u9593\u306F 1 \u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057`,
|
|
660
|
+
en: `Set up the Google Calendar connection. Ask the user how they want to access calendars and record the target calendars in Project Knowledge.
|
|
661
|
+
|
|
662
|
+
## Step 0: Get the service account email
|
|
663
|
+
|
|
664
|
+
We need the service account email so we can show it to the user in the next steps.
|
|
665
|
+
|
|
666
|
+
Call \`${requestToolName}\` once and remember the \`serviceAccountEmail\` from the response:
|
|
667
|
+
- \`method\`: \`"GET"\`
|
|
668
|
+
- \`path\`: \`"/users/me/calendarList"\`
|
|
669
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
670
|
+
|
|
671
|
+
\`serviceAccountEmail\` is returned regardless of success or failure, so the list payload itself can be ignored at this stage. Refer to the captured value as \`<serviceAccountEmail>\` in the steps below.
|
|
672
|
+
|
|
673
|
+
## Step 1: Choose the access method
|
|
674
|
+
|
|
675
|
+
Call \`askUserQuestion\`:
|
|
676
|
+
- \`type\`: \`"select"\`
|
|
677
|
+
- \`question\`: "Which calendars do you want to access?"
|
|
678
|
+
- \`options\`:
|
|
679
|
+
- \`{ label: "Calendars shared with this service account", value: "service-account" }\`
|
|
680
|
+
- \`{ label: "Calendars of users in your organization (via Domain-wide Delegation)", value: "delegation" }\`
|
|
681
|
+
- \`{ label: "Both", value: "both" }\`
|
|
682
|
+
|
|
683
|
+
## Step 2: Service-account path (when \`"service-account"\` or \`"both"\`)
|
|
684
|
+
|
|
685
|
+
Take calendar IDs that the user has already shared with \`<serviceAccountEmail>\`, and verify each one. No multiSelect step (the user has already specified which calendars to use by entering their IDs).
|
|
686
|
+
|
|
687
|
+
1. Ask the user for calendar IDs:
|
|
688
|
+
- \`type\`: \`"freeText"\`
|
|
689
|
+
- \`question\`: "Enter the IDs of the calendars you want to access (comma-separated for multiple). Each calendar must already be shared with \`<serviceAccountEmail>\`. For someone's primary calendar you can enter their email address directly. For other calendars (such as team calendars), copy the 'Calendar ID' from the calendar settings in Google Calendar."
|
|
690
|
+
- \`placeholder\`: \`"alice@example.com, c_xxx@group.calendar.google.com"\`
|
|
691
|
+
|
|
692
|
+
2. For each calendar ID \`<id>\`, verify access by calling \`${requestToolName}\`:
|
|
693
|
+
- \`method\`: \`"GET"\`
|
|
694
|
+
- \`path\`: \`"/calendars/<id>"\`
|
|
695
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
696
|
+
- On success, capture \`data.summary\` as the calendar name
|
|
697
|
+
- On failure (404 / 403 / etc.), record the ID as inaccessible
|
|
698
|
+
|
|
699
|
+
3. Branch on the results:
|
|
700
|
+
- **All IDs failed**: if the access method is \`"service-account"\` only, jump to Step 5. If \`"both"\`, continue to Step 3.
|
|
701
|
+
- **Any success**: take the verified calendars as the selection for Step 4. If some failed, mention them briefly in one sentence.
|
|
702
|
+
|
|
703
|
+
## Step 3: Domain-wide Delegation path (when \`"delegation"\` or \`"both"\`)
|
|
704
|
+
|
|
705
|
+
Discover calendars from each Workspace user and let the user narrow them down.
|
|
706
|
+
|
|
707
|
+
1. Ask the user for the target Workspace user emails:
|
|
708
|
+
- \`type\`: \`"freeText"\`
|
|
709
|
+
- \`question\`: "Enter the email addresses of the Google Workspace users whose calendars you want to access (comma-separated for multiple). Your Workspace admin must have authorized Domain-wide Delegation for service account \`<serviceAccountEmail>\` in advance ([admin setup guide](https://support.google.com/a/answer/162106))."
|
|
710
|
+
- \`placeholder\`: \`"alice@example.com, bob@example.com"\`
|
|
711
|
+
|
|
712
|
+
2. For each email \`<email>\`, list calendars accessible to that user via \`${requestWithDelegationToolName}\`:
|
|
713
|
+
- \`method\`: \`"GET"\`
|
|
714
|
+
- \`path\`: \`"/users/me/calendarList"\`
|
|
715
|
+
- \`subject\`: \`<email>\`
|
|
716
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
717
|
+
|
|
718
|
+
3. Branch on the results:
|
|
719
|
+
- **All emails failed**: if the access method is \`"delegation"\` only, or \`"both"\` with no calendars from Step 2, jump to Step 5. If \`"both"\` and Step 2 had calendars, continue to Step 4.
|
|
720
|
+
- **Any success**: ask the user to narrow down via \`askUserQuestion\`:
|
|
721
|
+
- \`type\`: \`"multiSelect"\`
|
|
722
|
+
- \`question\`: "Select the calendars to use (multiple allowed)"
|
|
723
|
+
- \`options\`: For each discovered calendar, \`label\`: \`"<calendar name> (owner: <the subject used>)"\`, \`value\`: \`"<calendarId>"\`
|
|
724
|
+
- If some emails failed, mention them briefly in one sentence.
|
|
725
|
+
|
|
726
|
+
## Step 4: Record in Project Knowledge
|
|
727
|
+
|
|
728
|
+
Aggregate the calendarIds from Steps 2 and 3. Cross-reference each calendarId against the verification result (Step 2) or the discovery result (Step 3) to recover its access path and, for delegation, the subject. Call \`finalizeSetup\` and record each calendar with its name, calendar ID, access path (delegation or service-account), and (for delegation) the subject as this connection's scope info.
|
|
729
|
+
|
|
730
|
+
## Step 5: Escalation when zero calendars are selected
|
|
731
|
+
|
|
732
|
+
When no calendars end up selected, call \`askUserQuestion\`:
|
|
733
|
+
|
|
734
|
+
- \`question\`: "No accessible calendars found. Please do one of the following before continuing. Service account: \`<serviceAccountEmail>\`."
|
|
735
|
+
- \`options\`: Combine these based on which paths were attempted:
|
|
736
|
+
- Service-account path attempted: \`{ label: "Shared the calendar with the service account \u2014 retry", value: "retry" }\`
|
|
737
|
+
- Domain-wide Delegation path attempted: \`{ label: "Authorized Domain-wide Delegation \u2014 retry", value: "retry" }\`
|
|
738
|
+
- Always: \`{ label: "Change the access method", value: "restart" }\`
|
|
739
|
+
- Always: \`{ label: "Use a different service account", value: "change-service-account" }\`
|
|
740
|
+
|
|
741
|
+
Behavior per selection:
|
|
742
|
+
- "retry": re-probe the path that was just attempted (the agent decides the exact retry plan)
|
|
743
|
+
- "restart": re-run from Step 1
|
|
744
|
+
- "change-service-account": call \`updateConnectionParameters\` to have the user re-upload the service account JSON:
|
|
745
|
+
- \`parameterSlug\`: \`"${SERVICE_ACCOUNT_KEY_PARAM_SLUG}"\`
|
|
746
|
+
- After it completes, re-run from Step 0
|
|
747
|
+
|
|
748
|
+
## Constraints
|
|
749
|
+
|
|
750
|
+
- Do not call any other API endpoints during setup
|
|
751
|
+
- Write at most 1 sentence between tool calls`
|
|
752
|
+
},
|
|
753
|
+
dataOverviewInstructions: {
|
|
754
|
+
en: `For each calendar configured for this connection, fetch metadata and a small sample of upcoming events. Pick the tool that matches the calendar's access path:
|
|
755
|
+
- Calendars accessed via delegation \u2192 \`${requestWithDelegationToolName}\` with the user's email as \`subject\`
|
|
756
|
+
- Calendars shared directly with the service account \u2192 \`${requestToolName}\`
|
|
757
|
+
|
|
758
|
+
Pass \`scopes: ${READONLY_SCOPES}\` for every call.
|
|
759
|
+
|
|
760
|
+
For each calendar:
|
|
761
|
+
1. \`method=GET\`, \`path=/calendars/<id>\` to fetch metadata.
|
|
762
|
+
2. \`method=GET\`, \`path=/calendars/<id>/events\`, \`queryParams={ timeMin: <RFC3339 now>, maxResults: "10", singleEvents: "true", orderBy: "startTime" }\`.`,
|
|
763
|
+
ja: `\u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u3067\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u5404\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u3064\u3044\u3066\u3001\u30E1\u30BF\u30C7\u30FC\u30BF\u3068\u76F4\u8FD1\u306E\u30A4\u30D9\u30F3\u30C8\u3092\u5C11\u91CF\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30A2\u30AF\u30BB\u30B9\u7D4C\u8DEF\u306B\u5FDC\u3058\u3066\u30C4\u30FC\u30EB\u3092\u9078\u3073\u307E\u3059:
|
|
764
|
+
- delegation \u7D4C\u7531\u306E\u30AB\u30EC\u30F3\u30C0\u30FC \u2192 \`${requestWithDelegationToolName}\` \u3092\u3001\u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 \`subject\` \u3068\u3057\u3066\u547C\u3076
|
|
765
|
+
- service account \u306B\u76F4\u63A5\u5171\u6709\u3055\u308C\u305F\u30AB\u30EC\u30F3\u30C0\u30FC \u2192 \`${requestToolName}\` \u3092\u547C\u3076
|
|
766
|
+
|
|
767
|
+
\`scopes\` \u306F\u6BCE\u56DE \`${READONLY_SCOPES}\` \u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
768
|
+
|
|
769
|
+
\u5404\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u3064\u3044\u3066:
|
|
770
|
+
1. \`method=GET\`\u3001\`path=/calendars/<id>\` \u3067\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
|
|
771
|
+
2. \`method=GET\`\u3001\`path=/calendars/<id>/events\`\u3001\`queryParams={ timeMin: <RFC3339 \u306E\u73FE\u5728\u6642\u523B>, maxResults: "10", singleEvents: "true", orderBy: "startTime" }\``
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
|
|
738
775
|
// ../connectors/src/connectors/google-calendar/index.ts
|
|
739
|
-
var tools = {
|
|
776
|
+
var tools = {
|
|
777
|
+
request: requestTool,
|
|
778
|
+
request_with_delegation: requestWithDelegationTool
|
|
779
|
+
};
|
|
740
780
|
var googleCalendarConnector = new ConnectorPlugin({
|
|
741
781
|
slug: "google-calendar",
|
|
742
782
|
authType: AUTH_TYPES.SERVICE_ACCOUNT,
|
|
@@ -745,62 +785,50 @@ var googleCalendarConnector = new ConnectorPlugin({
|
|
|
745
785
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/2YsqoBEpdELmfDeFcyGHyE/4494c633b5ae15e562cb739cd85442c1/google-calendar.png",
|
|
746
786
|
parameters,
|
|
747
787
|
releaseFlag: { dev1: true, dev2: true, prod: true },
|
|
788
|
+
categories: ["productivity"],
|
|
748
789
|
onboarding: googleCalendarOnboarding,
|
|
749
790
|
systemPrompt: {
|
|
750
791
|
en: `### Tools
|
|
751
792
|
|
|
752
|
-
|
|
793
|
+
This connector exposes two request tools that correspond to the two ways a Service Account can authenticate against the Google Calendar API:
|
|
753
794
|
|
|
754
|
-
|
|
795
|
+
- \`google-calendar-service-account_request_with_delegation\`: Call the Calendar API on behalf of the specified Workspace user via Domain-wide Delegation. Pass \`subject\` as the target user email. Requires Domain-wide Delegation to be authorized for the service account in the Workspace admin console.
|
|
796
|
+
- \`google-calendar-service-account_request\`: Call the Calendar API as the service account itself (no delegation). Only calendars explicitly shared with the service account email are accessible.
|
|
755
797
|
|
|
756
|
-
|
|
798
|
+
Both tools require a \`scopes\` argument.
|
|
757
799
|
|
|
758
|
-
|
|
759
|
-
- \`client.listCalendars()\` \u2014 list all accessible calendars
|
|
760
|
-
- \`client.listEvents(options?, calendarId?)\` \u2014 list events with optional filters
|
|
761
|
-
- \`client.getEvent(eventId, calendarId?)\` \u2014 get a single event by ID
|
|
762
|
-
- \`client.request(path, init?)\` \u2014 low-level authenticated fetch
|
|
800
|
+
### OAuth Scopes (pass as \`scopes\` argument)
|
|
763
801
|
|
|
764
|
-
|
|
802
|
+
This connector is currently read-only. Pass one of:
|
|
765
803
|
|
|
766
|
-
|
|
804
|
+
- \`https://www.googleapis.com/auth/calendar.readonly\` \u2014 read-only on calendars and events
|
|
805
|
+
- \`https://www.googleapis.com/auth/calendar.events.readonly\` \u2014 read-only on events (no calendar metadata)
|
|
806
|
+
- \`https://www.googleapis.com/auth/calendar.freebusy\` \u2014 busy/free time queries only
|
|
767
807
|
|
|
768
|
-
|
|
769
|
-
const calendar = connection("<connectionId>", { subject: "other-user@example.com" });
|
|
770
|
-
\`\`\`
|
|
808
|
+
For \`request_with_delegation\`, the Workspace admin must have authorized the requested scope for the service account in the Domain-wide Delegation settings, otherwise token issuance will fail with \`unauthorized_client\`.
|
|
771
809
|
|
|
772
|
-
|
|
773
|
-
import type { Context } from "hono";
|
|
774
|
-
import { connection } from "@squadbase/vite-server/connectors/google-calendar";
|
|
810
|
+
Per-endpoint scope reference: https://developers.google.com/calendar/api/auth
|
|
775
811
|
|
|
776
|
-
|
|
812
|
+
### Choosing the right tool
|
|
777
813
|
|
|
778
|
-
|
|
779
|
-
const now = new Date().toISOString();
|
|
780
|
-
const { items } = await calendar.listEvents({
|
|
781
|
-
timeMin: now,
|
|
782
|
-
maxResults: 10,
|
|
783
|
-
singleEvents: true,
|
|
784
|
-
orderBy: "startTime",
|
|
785
|
-
});
|
|
814
|
+
Each calendar configured for this connection has an access path. Match the path to the tool:
|
|
786
815
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
\`\`\`
|
|
816
|
+
- A Workspace user's calendar accessed via Domain-wide Delegation \u2192 use \`request_with_delegation\` and pass that user's email as \`subject\`
|
|
817
|
+
- A calendar shared directly with the service account \u2192 use \`request\` (no \`subject\`)
|
|
818
|
+
|
|
819
|
+
### Path conventions
|
|
820
|
+
|
|
821
|
+
Write the calendar ID directly into the path \u2014 there is no placeholder substitution. Examples:
|
|
822
|
+
|
|
823
|
+
- \`/users/me/calendarList\` \u2014 list calendars accessible to the authenticated identity
|
|
824
|
+
- \`/calendars/alice@example.com/events\` \u2014 events on alice's primary calendar
|
|
825
|
+
- \`/calendars/c_abc123@group.calendar.google.com/events\` \u2014 events on a secondary calendar
|
|
798
826
|
|
|
799
827
|
### Google Calendar API v3 Reference
|
|
800
828
|
|
|
801
829
|
#### Available Endpoints
|
|
802
830
|
- GET \`/calendars/{calendarId}\` \u2014 Get calendar metadata
|
|
803
|
-
- GET \`/users/me/calendarList\` \u2014 List all calendars accessible by the authenticated
|
|
831
|
+
- GET \`/users/me/calendarList\` \u2014 List all calendars accessible by the authenticated identity
|
|
804
832
|
- GET \`/calendars/{calendarId}/events\` \u2014 List events on a calendar
|
|
805
833
|
- GET \`/calendars/{calendarId}/events/{eventId}\` \u2014 Get a single event
|
|
806
834
|
|
|
@@ -812,66 +840,93 @@ export default async function handler(c: Context) {
|
|
|
812
840
|
- \`orderBy=startTime\` \u2014 Order by start time (requires singleEvents=true)
|
|
813
841
|
- \`q\` \u2014 Free text search terms
|
|
814
842
|
|
|
815
|
-
#### Tips
|
|
816
|
-
- Use \`{calendarId}\` placeholder in paths \u2014 it is automatically replaced with the configured default calendar ID
|
|
817
|
-
- Set \`singleEvents=true\` to expand recurring events into individual instances
|
|
818
|
-
- When using \`orderBy=startTime\`, you must also set \`singleEvents=true\`
|
|
819
|
-
- Use RFC3339 format for time parameters (e.g., "2024-01-15T09:00:00Z" or "2024-01-15T09:00:00+09:00")
|
|
820
|
-
- The default calendar ID is "primary" if not configured`,
|
|
821
|
-
ja: `### \u30C4\u30FC\u30EB
|
|
822
|
-
|
|
823
|
-
- \`google-calendar-service-account_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\uFF0BDomain-wide Delegation\u3067\u8A8D\u8A3C\u304C\u81EA\u52D5\u7684\u306B\u51E6\u7406\u3055\u308C\u3001\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306B\u8A2D\u5B9A\u3055\u308C\u305F\u30E6\u30FC\u30B6\u30FC\uFF08\`impersonate-email\`\u30D1\u30E9\u30E1\u30FC\u30BF\uFF09\u3068\u3057\u3066\u52D5\u4F5C\u3057\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\u7279\u5B9A\u30EA\u30AF\u30A8\u30B9\u30C8\u3067\u8A2D\u5B9A\u30E6\u30FC\u30B6\u30FC\u3092\u4E0A\u66F8\u304D\u3057\u305F\u3044\u5834\u5408\u306E\u307F\u3001\u30AA\u30D7\u30B7\u30E7\u30F3\u306E\`subject\`\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
824
|
-
|
|
825
843
|
### Business Logic
|
|
826
844
|
|
|
827
|
-
|
|
845
|
+
The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
|
|
828
846
|
|
|
829
|
-
SDK
|
|
830
|
-
- \`client.listCalendars()\` \u2014 \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5168\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7\u53D6\u5F97
|
|
831
|
-
- \`client.listEvents(options?, calendarId?)\` \u2014 \u30D5\u30A3\u30EB\u30BF\u30FC\u4ED8\u304D\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7\u53D6\u5F97
|
|
832
|
-
- \`client.getEvent(eventId, calendarId?)\` \u2014 ID\u306B\u3088\u308B\u5358\u4E00\u30A4\u30D9\u30F3\u30C8\u53D6\u5F97
|
|
833
|
-
- \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
|
|
847
|
+
SDK methods (client created via \`connection(connectionId)\`):
|
|
834
848
|
|
|
835
|
-
|
|
849
|
+
- \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 call the API as the impersonated Workspace user via Domain-wide Delegation
|
|
850
|
+
- \`client.request(path, { scopes, init? })\` \u2014 call the API as the service account itself (only calendars shared with the SA email are accessible)
|
|
836
851
|
|
|
837
|
-
|
|
852
|
+
Both methods take \`scopes\` \u2014 pass the minimum scope(s) for the endpoint. Both return a standard \`Response\`. Read the body with \`.json()\`. Same path conventions as the tools.
|
|
838
853
|
|
|
839
|
-
|
|
840
|
-
const calendar = connection("<connectionId>", { subject: "other-user@example.com" });
|
|
841
|
-
\`\`\`
|
|
854
|
+
#### Example
|
|
842
855
|
|
|
843
856
|
\`\`\`ts
|
|
844
857
|
import type { Context } from "hono";
|
|
845
858
|
import { connection } from "@squadbase/vite-server/connectors/google-calendar";
|
|
846
859
|
|
|
847
860
|
const calendar = connection("<connectionId>");
|
|
861
|
+
const READ = ["https://www.googleapis.com/auth/calendar.readonly"];
|
|
848
862
|
|
|
849
863
|
export default async function handler(c: Context) {
|
|
850
864
|
const now = new Date().toISOString();
|
|
851
|
-
const
|
|
865
|
+
const qs = new URLSearchParams({
|
|
852
866
|
timeMin: now,
|
|
853
|
-
maxResults: 10,
|
|
854
|
-
singleEvents: true,
|
|
867
|
+
maxResults: "10",
|
|
868
|
+
singleEvents: "true",
|
|
855
869
|
orderBy: "startTime",
|
|
856
870
|
});
|
|
857
871
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
start: event.start.dateTime ?? event.start.date,
|
|
863
|
-
end: event.end.dateTime ?? event.end.date,
|
|
864
|
-
location: event.location,
|
|
865
|
-
})),
|
|
872
|
+
// alice@example.com is accessed via delegation
|
|
873
|
+
const aliceRes = await calendar.requestWithDelegation(
|
|
874
|
+
\`/calendars/alice@example.com/events?\${qs}\`,
|
|
875
|
+
{ subject: "alice@example.com", scopes: READ },
|
|
866
876
|
);
|
|
877
|
+
const alice = await aliceRes.json();
|
|
878
|
+
|
|
879
|
+
// team@example.com is shared directly with the service account
|
|
880
|
+
const teamRes = await calendar.request(
|
|
881
|
+
\`/calendars/team@example.com/events?\${qs}\`,
|
|
882
|
+
{ scopes: READ },
|
|
883
|
+
);
|
|
884
|
+
const team = await teamRes.json();
|
|
885
|
+
|
|
886
|
+
return c.json({ alice: alice.items, team: team.items });
|
|
867
887
|
}
|
|
868
|
-
|
|
888
|
+
\`\`\``,
|
|
889
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
890
|
+
|
|
891
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u30FC\u306F\u3001Service Account \u304C Google Calendar API \u306B\u8A8D\u8A3C\u3059\u308B 2 \u3064\u306E\u65B9\u6CD5\u306B\u5BFE\u5FDC\u3059\u308B 2 \u3064\u306E request \u30C4\u30FC\u30EB\u3092\u516C\u958B\u3057\u307E\u3059:
|
|
892
|
+
|
|
893
|
+
- \`google-calendar-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 Calendar 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\u3002Workspace \u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u3067 Service Account \u306E Domain-wide Delegation \u304C\u627F\u8A8D\u3055\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002
|
|
894
|
+
- \`google-calendar-service-account_request\`: Service Account \u81EA\u8EAB\u3068\u3057\u3066 Calendar API \u3092\u547C\u3073\u51FA\u3057\u307E\u3059 (Domain-wide Delegation \u3092\u4F7F\u308F\u306A\u3044\u7D4C\u8DEF)\u3002Service Account \u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306B\u660E\u793A\u7684\u306B\u5171\u6709\u3055\u308C\u3066\u3044\u308B\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u307F\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u3067\u3059\u3002
|
|
895
|
+
|
|
896
|
+
\u4E21\u30C4\u30FC\u30EB\u3068\u3082 \`scopes\` \u5F15\u6570\u304C\u5FC5\u9808\u3067\u3059\u3002
|
|
897
|
+
|
|
898
|
+
### OAuth \u30B9\u30B3\u30FC\u30D7 (\`scopes\` \u5F15\u6570\u3067\u6E21\u3059)
|
|
899
|
+
|
|
900
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u30FC\u306F\u73FE\u72B6\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u3059\u3002\u6B21\u306E\u3044\u305A\u308C\u304B\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044:
|
|
901
|
+
|
|
902
|
+
- \`https://www.googleapis.com/auth/calendar.readonly\` \u2014 \u30AB\u30EC\u30F3\u30C0\u30FC\u3068\u30A4\u30D9\u30F3\u30C8\u306E\u8AAD\u307F\u53D6\u308A
|
|
903
|
+
- \`https://www.googleapis.com/auth/calendar.events.readonly\` \u2014 \u30A4\u30D9\u30F3\u30C8\u306E\u307F\u8AAD\u307F\u53D6\u308A\uFF08\u30AB\u30EC\u30F3\u30C0\u30FC\u30E1\u30BF\u30C7\u30FC\u30BF\u4E0D\u53EF\uFF09
|
|
904
|
+
- \`https://www.googleapis.com/auth/calendar.freebusy\` \u2014 \u7A7A\u304D\u72B6\u6CC1\u30AF\u30A8\u30EA\u306E\u307F
|
|
905
|
+
|
|
906
|
+
\`request_with_delegation\` \u306E\u5834\u5408\u3001\u8981\u6C42\u3059\u308B scope \u306F Workspace \u7BA1\u7406\u8005\u304C Domain-wide Delegation \u8A2D\u5B9A\u3067\u5F53\u8A72 Service Account \u306B\u5BFE\u3057\u3066\u627F\u8A8D\u3057\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u627F\u8A8D\u3055\u308C\u3066\u3044\u306A\u3044\u5834\u5408\u30C8\u30FC\u30AF\u30F3\u767A\u884C\u304C \`unauthorized_client\` \u3067\u5931\u6557\u3057\u307E\u3059\u3002
|
|
907
|
+
|
|
908
|
+
\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u5225\u306E\u6B63\u78BA\u306A scope \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9: https://developers.google.com/calendar/api/auth
|
|
909
|
+
|
|
910
|
+
### \u9069\u5207\u306A\u30C4\u30FC\u30EB\u306E\u9078\u3073\u65B9
|
|
911
|
+
|
|
912
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u3067\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u5404\u30AB\u30EC\u30F3\u30C0\u30FC\u306B\u306F\u30A2\u30AF\u30BB\u30B9\u7D4C\u8DEF\u304C\u3042\u308A\u307E\u3059\u3002\u7D4C\u8DEF\u306B\u5FDC\u3058\u3066\u30C4\u30FC\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044:
|
|
913
|
+
|
|
914
|
+
- delegation \u7D4C\u7531\uFF08Workspace \u30E6\u30FC\u30B6\u30FC\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u306B Domain-wide Delegation \u3067\u30A2\u30AF\u30BB\u30B9\uFF09\u2192 \`request_with_delegation\` \u3092\u4F7F\u3044\u3001\u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 \`subject\` \u3068\u3057\u3066\u6E21\u3059
|
|
915
|
+
- service account \u7D4C\u7531\uFF08\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306B\u76F4\u63A5\u5171\u6709\u3055\u308C\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\uFF09\u2192 \`request\` \u3092\u4F7F\u3046\uFF08\`subject\` \u4E0D\u8981\uFF09
|
|
916
|
+
|
|
917
|
+
### \u30D1\u30B9\u306E\u66F8\u304D\u65B9
|
|
918
|
+
|
|
919
|
+
calendar ID \u3092\u30D1\u30B9\u306B\u76F4\u63A5\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\u3002\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306E\u7F6E\u63DB\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u4F8B:
|
|
920
|
+
|
|
921
|
+
- \`/users/me/calendarList\` \u2014 \u8A8D\u8A3C\u3055\u308C\u305F\u8B58\u5225\u5B50\u304C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7
|
|
922
|
+
- \`/calendars/alice@example.com/events\` \u2014 alice \u306E\u30D7\u30E9\u30A4\u30DE\u30EA\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30A4\u30D9\u30F3\u30C8
|
|
923
|
+
- \`/calendars/c_abc123@group.calendar.google.com/events\` \u2014 \u4E8C\u6B21\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30A4\u30D9\u30F3\u30C8
|
|
869
924
|
|
|
870
925
|
### Google Calendar API v3 \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
871
926
|
|
|
872
927
|
#### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
873
928
|
- GET \`/calendars/{calendarId}\` \u2014 \u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
|
|
874
|
-
- GET \`/users/me/calendarList\` \u2014 \u8A8D\u8A3C\
|
|
929
|
+
- GET \`/users/me/calendarList\` \u2014 \u8A8D\u8A3C\u3055\u308C\u305F\u8B58\u5225\u5B50\u304C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5168\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7
|
|
875
930
|
- GET \`/calendars/{calendarId}/events\` \u2014 \u30AB\u30EC\u30F3\u30C0\u30FC\u4E0A\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7
|
|
876
931
|
- GET \`/calendars/{calendarId}/events/{eventId}\` \u2014 \u5358\u4E00\u30A4\u30D9\u30F3\u30C8\u306E\u53D6\u5F97
|
|
877
932
|
|
|
@@ -883,12 +938,52 @@ export default async function handler(c: Context) {
|
|
|
883
938
|
- \`orderBy=startTime\` \u2014 \u958B\u59CB\u6642\u9593\u9806\u306B\u4E26\u3079\u66FF\u3048\uFF08singleEvents=true\u304C\u5FC5\u8981\uFF09
|
|
884
939
|
- \`q\` \u2014 \u30D5\u30EA\u30FC\u30C6\u30AD\u30B9\u30C8\u691C\u7D22\u8A9E
|
|
885
940
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
941
|
+
### Business Logic
|
|
942
|
+
|
|
943
|
+
\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
|
|
944
|
+
|
|
945
|
+
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
946
|
+
|
|
947
|
+
- \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 Domain-wide Delegation \u3067\u6307\u5B9A Workspace \u30E6\u30FC\u30B6\u30FC\u306B\u4EE3\u308F\u3063\u3066 API \u3092\u547C\u3076
|
|
948
|
+
- \`client.request(path, { scopes, init? })\` \u2014 SA \u81EA\u8EAB\u3068\u3057\u3066 API \u3092\u547C\u3076\uFF08SA \u306B\u5171\u6709\u3055\u308C\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u307F\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\uFF09
|
|
949
|
+
|
|
950
|
+
\u4E21\u30E1\u30BD\u30C3\u30C9\u3068\u3082 \`scopes\` \u3092\u53D7\u3051\u53D6\u308A\u307E\u3059\u3002\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306B\u5FC5\u8981\u306A\u6700\u5C0F scope \u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u6A19\u6E96\u306E \`Response\` \u3092\u8FD4\u3059\u306E\u3067 \`response.json()\` \u3067\u30DC\u30C7\u30A3\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30D1\u30B9\u306E\u66F8\u304D\u65B9\u306F\u30C4\u30FC\u30EB\u3068\u540C\u3058\u3002
|
|
951
|
+
|
|
952
|
+
#### Example
|
|
953
|
+
|
|
954
|
+
\`\`\`ts
|
|
955
|
+
import type { Context } from "hono";
|
|
956
|
+
import { connection } from "@squadbase/vite-server/connectors/google-calendar";
|
|
957
|
+
|
|
958
|
+
const calendar = connection("<connectionId>");
|
|
959
|
+
const READ = ["https://www.googleapis.com/auth/calendar.readonly"];
|
|
960
|
+
|
|
961
|
+
export default async function handler(c: Context) {
|
|
962
|
+
const now = new Date().toISOString();
|
|
963
|
+
const qs = new URLSearchParams({
|
|
964
|
+
timeMin: now,
|
|
965
|
+
maxResults: "10",
|
|
966
|
+
singleEvents: "true",
|
|
967
|
+
orderBy: "startTime",
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
// alice@example.com \u306F delegation \u7D4C\u8DEF\u3067\u30A2\u30AF\u30BB\u30B9
|
|
971
|
+
const aliceRes = await calendar.requestWithDelegation(
|
|
972
|
+
\`/calendars/alice@example.com/events?\${qs}\`,
|
|
973
|
+
{ subject: "alice@example.com", scopes: READ },
|
|
974
|
+
);
|
|
975
|
+
const alice = await aliceRes.json();
|
|
976
|
+
|
|
977
|
+
// team@example.com \u306F SA \u306B\u76F4\u63A5\u5171\u6709
|
|
978
|
+
const teamRes = await calendar.request(
|
|
979
|
+
\`/calendars/team@example.com/events?\${qs}\`,
|
|
980
|
+
{ scopes: READ },
|
|
981
|
+
);
|
|
982
|
+
const team = await teamRes.json();
|
|
983
|
+
|
|
984
|
+
return c.json({ alice: alice.items, team: team.items });
|
|
985
|
+
}
|
|
986
|
+
\`\`\``
|
|
892
987
|
},
|
|
893
988
|
tools
|
|
894
989
|
});
|