@squadbase/vite-server 0.1.3-dev.1 → 0.1.3-dev.11

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.
Files changed (58) hide show
  1. package/dist/cli/index.js +71446 -6941
  2. package/dist/connectors/airtable-oauth.js +77 -3
  3. package/dist/connectors/airtable.js +85 -2
  4. package/dist/connectors/amplitude.js +85 -2
  5. package/dist/connectors/anthropic.js +85 -2
  6. package/dist/connectors/asana.js +86 -3
  7. package/dist/connectors/attio.js +85 -2
  8. package/dist/connectors/{microsoft-teams.d.ts → backlog-api-key.d.ts} +1 -1
  9. package/dist/connectors/backlog-api-key.js +592 -0
  10. package/dist/connectors/customerio.js +86 -3
  11. package/dist/connectors/dbt.js +85 -2
  12. package/dist/connectors/gemini.js +86 -3
  13. package/dist/connectors/gmail-oauth.js +78 -4
  14. package/dist/connectors/gmail.d.ts +5 -0
  15. package/dist/connectors/gmail.js +875 -0
  16. package/dist/connectors/google-ads-oauth.js +78 -4
  17. package/dist/connectors/google-ads.js +85 -2
  18. package/dist/connectors/google-analytics-oauth.js +90 -8
  19. package/dist/connectors/google-analytics.js +85 -2
  20. package/dist/connectors/google-calendar-oauth.d.ts +5 -0
  21. package/dist/connectors/google-calendar-oauth.js +817 -0
  22. package/dist/connectors/google-calendar.d.ts +5 -0
  23. package/dist/connectors/google-calendar.js +991 -0
  24. package/dist/connectors/google-sheets-oauth.js +144 -33
  25. package/dist/connectors/google-sheets.js +119 -10
  26. package/dist/connectors/{microsoft-teams-oauth.d.ts → grafana.d.ts} +1 -1
  27. package/dist/connectors/grafana.js +638 -0
  28. package/dist/connectors/hubspot-oauth.js +77 -3
  29. package/dist/connectors/hubspot.js +79 -5
  30. package/dist/connectors/intercom-oauth.js +78 -4
  31. package/dist/connectors/intercom.js +86 -3
  32. package/dist/connectors/jira-api-key.js +84 -9
  33. package/dist/connectors/kintone-api-token.js +77 -3
  34. package/dist/connectors/kintone.js +86 -3
  35. package/dist/connectors/linkedin-ads-oauth.js +78 -4
  36. package/dist/connectors/linkedin-ads.js +86 -3
  37. package/dist/connectors/mailchimp-oauth.js +77 -3
  38. package/dist/connectors/mailchimp.js +86 -3
  39. package/dist/connectors/notion-oauth.d.ts +5 -0
  40. package/dist/connectors/notion-oauth.js +567 -0
  41. package/dist/connectors/{slack.d.ts → notion.d.ts} +1 -1
  42. package/dist/connectors/notion.js +663 -0
  43. package/dist/connectors/openai.js +85 -2
  44. package/dist/connectors/shopify-oauth.js +77 -3
  45. package/dist/connectors/shopify.js +85 -2
  46. package/dist/connectors/stripe-api-key.d.ts +5 -0
  47. package/dist/connectors/stripe-api-key.js +600 -0
  48. package/dist/connectors/stripe-oauth.js +77 -3
  49. package/dist/connectors/wix-store.js +85 -2
  50. package/dist/connectors/zendesk-oauth.js +78 -4
  51. package/dist/connectors/zendesk.js +86 -3
  52. package/dist/index.js +75463 -8247
  53. package/dist/main.js +75191 -7975
  54. package/dist/vite-plugin.js +75300 -8121
  55. package/package.json +50 -2
  56. package/dist/connectors/microsoft-teams-oauth.js +0 -479
  57. package/dist/connectors/microsoft-teams.js +0 -381
  58. package/dist/connectors/slack.js +0 -362
@@ -0,0 +1,991 @@
1
+ // ../connectors/src/parameter-definition.ts
2
+ var ParameterDefinition = class {
3
+ slug;
4
+ name;
5
+ description;
6
+ envVarBaseKey;
7
+ type;
8
+ secret;
9
+ required;
10
+ constructor(config) {
11
+ this.slug = config.slug;
12
+ this.name = config.name;
13
+ this.description = config.description;
14
+ this.envVarBaseKey = config.envVarBaseKey;
15
+ this.type = config.type;
16
+ this.secret = config.secret;
17
+ this.required = config.required;
18
+ }
19
+ /**
20
+ * Get the parameter value from a ConnectorConnectionObject.
21
+ */
22
+ getValue(connection2) {
23
+ const param = connection2.parameters.find(
24
+ (p) => p.parameterSlug === this.slug
25
+ );
26
+ if (!param || param.value == null) {
27
+ throw new Error(
28
+ `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
29
+ );
30
+ }
31
+ return param.value;
32
+ }
33
+ /**
34
+ * Try to get the parameter value. Returns undefined if not found (for optional params).
35
+ */
36
+ tryGetValue(connection2) {
37
+ const param = connection2.parameters.find(
38
+ (p) => p.parameterSlug === this.slug
39
+ );
40
+ if (!param || param.value == null) return void 0;
41
+ return param.value;
42
+ }
43
+ };
44
+
45
+ // ../connectors/src/connectors/google-calendar/sdk/index.ts
46
+ import * as crypto from "crypto";
47
+
48
+ // ../connectors/src/connectors/google-calendar/parameters.ts
49
+ var parameters = {
50
+ serviceAccountKeyJsonBase64: new ParameterDefinition({
51
+ slug: "service-account-key-json-base64",
52
+ name: "Google Cloud Service Account JSON",
53
+ description: "The service account JSON key used to authenticate with Google Cloud Platform. Ensure that the service account has the necessary permissions to access Google Calendar, and that calendars are shared with the service account email.",
54
+ envVarBaseKey: "GOOGLE_CALENDAR_SERVICE_ACCOUNT_JSON_BASE64",
55
+ type: "base64EncodedJson",
56
+ secret: true,
57
+ required: true
58
+ }),
59
+ impersonateEmail: new ParameterDefinition({
60
+ slug: "impersonate-email",
61
+ name: "User Email Address(es)",
62
+ description: "The email address(es) of the Google Workspace user(s) whose calendar will be accessed via Domain-wide Delegation. Multiple addresses can be provided as a comma-separated list (e.g., 'user1@example.com, user2@example.com') to aggregate accessible calendars across users during setup. After setup completes, this value is overwritten with the owner email of the selected calendar.",
63
+ envVarBaseKey: "GOOGLE_CALENDAR_IMPERSONATE_EMAIL",
64
+ type: "text",
65
+ secret: false,
66
+ required: true
67
+ }),
68
+ calendarId: new ParameterDefinition({
69
+ slug: "calendar-id",
70
+ name: "Default Calendar ID",
71
+ 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.",
72
+ envVarBaseKey: "GOOGLE_CALENDAR_CALENDAR_ID",
73
+ type: "text",
74
+ secret: false,
75
+ required: false
76
+ })
77
+ };
78
+
79
+ // ../connectors/src/connectors/google-calendar/sdk/index.ts
80
+ var TOKEN_URL = "https://oauth2.googleapis.com/token";
81
+ 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
+ function createClient(params) {
108
+ const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
109
+ const impersonateEmail = params[parameters.impersonateEmail.slug];
110
+ const defaultCalendarId = params[parameters.calendarId.slug] ?? "primary";
111
+ if (!serviceAccountKeyJsonBase64) {
112
+ throw new Error(
113
+ `google-calendar: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
114
+ );
115
+ }
116
+ if (!impersonateEmail) {
117
+ throw new Error(
118
+ `google-calendar: missing required parameter: ${parameters.impersonateEmail.slug}`
119
+ );
120
+ }
121
+ let serviceAccountKey;
122
+ try {
123
+ const decoded = Buffer.from(
124
+ serviceAccountKeyJsonBase64,
125
+ "base64"
126
+ ).toString("utf-8");
127
+ serviceAccountKey = JSON.parse(decoded);
128
+ } catch {
129
+ throw new Error(
130
+ "google-calendar: failed to decode service account key JSON from base64"
131
+ );
132
+ }
133
+ if (!serviceAccountKey.client_email || !serviceAccountKey.private_key) {
134
+ throw new Error(
135
+ "google-calendar: service account key JSON must contain client_email and private_key"
136
+ );
137
+ }
138
+ const subject = impersonateEmail;
139
+ let cachedToken = null;
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;
173
+ }
174
+ return {
175
+ async request(path2, init) {
176
+ const accessToken = await getAccessToken2();
177
+ const resolvedPath = path2.replace(
178
+ /\{calendarId\}/g,
179
+ defaultCalendarId
180
+ );
181
+ const url = `${BASE_URL}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
182
+ const headers = new Headers(init?.headers);
183
+ headers.set("Authorization", `Bearer ${accessToken}`);
184
+ return fetch(url, { ...init, headers });
185
+ },
186
+ async listCalendars() {
187
+ const response = await this.request("/users/me/calendarList", {
188
+ method: "GET"
189
+ });
190
+ if (!response.ok) {
191
+ const text = await response.text();
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();
216
+ throw new Error(
217
+ `google-calendar: listEvents failed (${response.status}): ${text}`
218
+ );
219
+ }
220
+ return await response.json();
221
+ },
222
+ async getEvent(eventId, calendarId) {
223
+ const cid = resolveCalendarId(calendarId);
224
+ const path2 = `/calendars/${encodeURIComponent(cid)}/events/${encodeURIComponent(eventId)}`;
225
+ const response = await this.request(path2, { method: "GET" });
226
+ if (!response.ok) {
227
+ const text = await response.text();
228
+ throw new Error(
229
+ `google-calendar: getEvent failed (${response.status}): ${text}`
230
+ );
231
+ }
232
+ return await response.json();
233
+ }
234
+ };
235
+ }
236
+
237
+ // ../connectors/src/connector-onboarding.ts
238
+ var ConnectorOnboarding = class {
239
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
240
+ connectionSetupInstructions;
241
+ /** Phase 2: Data overview instructions */
242
+ dataOverviewInstructions;
243
+ constructor(config) {
244
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
245
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
246
+ }
247
+ getConnectionSetupPrompt(language) {
248
+ return this.connectionSetupInstructions?.[language] ?? null;
249
+ }
250
+ getDataOverviewInstructions(language) {
251
+ return this.dataOverviewInstructions[language];
252
+ }
253
+ };
254
+
255
+ // ../connectors/src/connector-tool.ts
256
+ var ConnectorTool = class {
257
+ name;
258
+ description;
259
+ inputSchema;
260
+ outputSchema;
261
+ _execute;
262
+ constructor(config) {
263
+ this.name = config.name;
264
+ this.description = config.description;
265
+ this.inputSchema = config.inputSchema;
266
+ this.outputSchema = config.outputSchema;
267
+ this._execute = config.execute;
268
+ }
269
+ createTool(connections, config) {
270
+ return {
271
+ description: this.description,
272
+ inputSchema: this.inputSchema,
273
+ outputSchema: this.outputSchema,
274
+ execute: (input) => this._execute(input, connections, config)
275
+ };
276
+ }
277
+ };
278
+
279
+ // ../connectors/src/connector-plugin.ts
280
+ var ConnectorPlugin = class _ConnectorPlugin {
281
+ slug;
282
+ authType;
283
+ name;
284
+ description;
285
+ iconUrl;
286
+ parameters;
287
+ releaseFlag;
288
+ proxyPolicy;
289
+ experimentalAttributes;
290
+ onboarding;
291
+ systemPrompt;
292
+ tools;
293
+ query;
294
+ checkConnection;
295
+ constructor(config) {
296
+ this.slug = config.slug;
297
+ this.authType = config.authType;
298
+ this.name = config.name;
299
+ this.description = config.description;
300
+ this.iconUrl = config.iconUrl;
301
+ this.parameters = config.parameters;
302
+ this.releaseFlag = config.releaseFlag;
303
+ this.proxyPolicy = config.proxyPolicy;
304
+ this.experimentalAttributes = config.experimentalAttributes;
305
+ this.onboarding = config.onboarding;
306
+ this.systemPrompt = config.systemPrompt;
307
+ this.tools = config.tools;
308
+ this.query = config.query;
309
+ this.checkConnection = config.checkConnection;
310
+ }
311
+ get connectorKey() {
312
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
313
+ }
314
+ /**
315
+ * Create tools for connections that belong to this connector.
316
+ * Filters connections by connectorKey internally.
317
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
318
+ */
319
+ createTools(connections, config) {
320
+ const myConnections = connections.filter(
321
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
322
+ );
323
+ const result = {};
324
+ for (const t of Object.values(this.tools)) {
325
+ result[`${this.connectorKey}_${t.name}`] = t.createTool(
326
+ myConnections,
327
+ config
328
+ );
329
+ }
330
+ return result;
331
+ }
332
+ static deriveKey(slug, authType) {
333
+ return authType ? `${slug}-${authType}` : slug;
334
+ }
335
+ };
336
+
337
+ // ../connectors/src/auth-types.ts
338
+ var AUTH_TYPES = {
339
+ OAUTH: "oauth",
340
+ API_KEY: "api-key",
341
+ JWT: "jwt",
342
+ SERVICE_ACCOUNT: "service-account",
343
+ PAT: "pat",
344
+ USER_PASSWORD: "user-password"
345
+ };
346
+
347
+ // ../connectors/src/connectors/google-calendar/tools/list-calendars.ts
348
+ import * as crypto2 from "crypto";
349
+ import { z } from "zod";
350
+ var TOKEN_URL2 = "https://oauth2.googleapis.com/token";
351
+ var BASE_URL2 = "https://www.googleapis.com/calendar/v3";
352
+ var SCOPE2 = "https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.events.readonly";
353
+ var REQUEST_TIMEOUT_MS = 6e4;
354
+ function base64url2(input) {
355
+ const buf = typeof input === "string" ? Buffer.from(input) : input;
356
+ return buf.toString("base64url");
357
+ }
358
+ function buildJwt2(clientEmail, privateKey, nowSec, subject) {
359
+ const header = base64url2(JSON.stringify({ alg: "RS256", typ: "JWT" }));
360
+ const payload = base64url2(
361
+ JSON.stringify({
362
+ iss: clientEmail,
363
+ sub: subject,
364
+ scope: SCOPE2,
365
+ aud: TOKEN_URL2,
366
+ iat: nowSec,
367
+ exp: nowSec + 3600
368
+ })
369
+ );
370
+ const signingInput = `${header}.${payload}`;
371
+ const sign = crypto2.createSign("RSA-SHA256");
372
+ sign.update(signingInput);
373
+ sign.end();
374
+ const signature = base64url2(sign.sign(privateKey));
375
+ return `${signingInput}.${signature}`;
376
+ }
377
+ async function getAccessToken(serviceAccount, subject) {
378
+ const nowSec = Math.floor(Date.now() / 1e3);
379
+ const jwt = buildJwt2(
380
+ serviceAccount.client_email,
381
+ serviceAccount.private_key,
382
+ nowSec,
383
+ subject
384
+ );
385
+ const response = await fetch(TOKEN_URL2, {
386
+ method: "POST",
387
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
388
+ body: new URLSearchParams({
389
+ grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
390
+ assertion: jwt
391
+ })
392
+ });
393
+ if (!response.ok) {
394
+ const text = await response.text();
395
+ throw new Error(
396
+ `token exchange failed for ${subject} (${response.status}): ${text}`
397
+ );
398
+ }
399
+ const data = await response.json();
400
+ return data.access_token;
401
+ }
402
+ var inputSchema = z.object({
403
+ toolUseIntent: z.string().optional().describe(
404
+ "Brief description of what you intend to accomplish with this tool call"
405
+ ),
406
+ connectionId: z.string().describe("ID of the Google Calendar connection to use")
407
+ });
408
+ var outputSchema = z.discriminatedUnion("success", [
409
+ z.object({
410
+ success: z.literal(true),
411
+ calendars: z.array(
412
+ z.object({
413
+ impersonateEmail: z.string(),
414
+ id: z.string(),
415
+ summary: z.string(),
416
+ primary: z.boolean().optional(),
417
+ accessRole: z.string()
418
+ })
419
+ ),
420
+ errors: z.array(
421
+ z.object({
422
+ impersonateEmail: z.string(),
423
+ error: z.string()
424
+ })
425
+ )
426
+ }),
427
+ z.object({
428
+ success: z.literal(false),
429
+ error: z.string()
430
+ })
431
+ ]);
432
+ var listCalendarsTool = new ConnectorTool({
433
+ name: "listCalendars",
434
+ description: "List Google Calendars accessible via Domain-wide Delegation by impersonating the Google Workspace user(s) configured on the connection's `impersonate-email` parameter (comma-separated list supported). Use during setup to aggregate calendars across the configured emails.",
435
+ inputSchema,
436
+ outputSchema,
437
+ async execute({ connectionId }, connections) {
438
+ const connection2 = connections.find((c) => c.id === connectionId);
439
+ if (!connection2) {
440
+ return {
441
+ success: false,
442
+ error: `Connection ${connectionId} not found`
443
+ };
444
+ }
445
+ const impersonateEmailRaw = parameters.impersonateEmail.getValue(connection2);
446
+ const emails = impersonateEmailRaw.split(",").map((e) => e.trim()).filter((e) => e.length > 0);
447
+ if (emails.length === 0) {
448
+ return {
449
+ success: false,
450
+ error: "impersonate-email parameter is empty"
451
+ };
452
+ }
453
+ console.log(
454
+ `[connector-request] google-calendar/${connection2.name}: listCalendars for ${emails.join(",")}`
455
+ );
456
+ let serviceAccount;
457
+ try {
458
+ const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
459
+ const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
460
+ serviceAccount = JSON.parse(decoded);
461
+ } catch (err) {
462
+ const msg = err instanceof Error ? err.message : String(err);
463
+ return {
464
+ success: false,
465
+ error: `failed to decode service account key: ${msg}`
466
+ };
467
+ }
468
+ if (!serviceAccount.client_email || !serviceAccount.private_key) {
469
+ return {
470
+ success: false,
471
+ error: "service account key JSON must contain client_email and private_key"
472
+ };
473
+ }
474
+ const aggregated = [];
475
+ const errors = [];
476
+ for (const email of emails) {
477
+ const controller = new AbortController();
478
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
479
+ try {
480
+ const token = await getAccessToken(serviceAccount, email);
481
+ const response = await fetch(`${BASE_URL2}/users/me/calendarList`, {
482
+ method: "GET",
483
+ headers: { Authorization: `Bearer ${token}` },
484
+ signal: controller.signal
485
+ });
486
+ const data = await response.json();
487
+ if (!response.ok) {
488
+ const errorObj = data?.error;
489
+ errors.push({
490
+ impersonateEmail: email,
491
+ error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
492
+ });
493
+ continue;
494
+ }
495
+ const items = data.items ?? [];
496
+ for (const c of items) {
497
+ aggregated.push({
498
+ impersonateEmail: email,
499
+ id: c.id,
500
+ summary: c.summary,
501
+ primary: c.primary,
502
+ accessRole: c.accessRole
503
+ });
504
+ }
505
+ } catch (err) {
506
+ const msg = err instanceof Error ? err.message : String(err);
507
+ errors.push({ impersonateEmail: email, error: msg });
508
+ } finally {
509
+ clearTimeout(timeout);
510
+ }
511
+ }
512
+ return {
513
+ success: true,
514
+ calendars: aggregated,
515
+ errors
516
+ };
517
+ }
518
+ });
519
+
520
+ // ../connectors/src/connectors/google-calendar/setup.ts
521
+ var listCalendarsToolName = `google-calendar_${listCalendarsTool.name}`;
522
+ var googleCalendarOnboarding = new ConnectorOnboarding({
523
+ connectionSetupInstructions: {
524
+ 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
525
+
526
+ 1. \`${listCalendarsToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E \`impersonate-email\` \u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u8A2D\u5B9A\u3055\u308C\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\u5BFE\u5FDC\uFF09\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
527
+ 2. \u8FD4\u5374\u3055\u308C\u305F \`calendars\` \u914D\u5217\uFF08\u5404\u8981\u7D20: \`{ impersonateEmail, id, summary, primary, accessRole }\`\uFF09\u3092\u5143\u306B\u3001\u300C\u4F7F\u7528\u3059\u308B\u30AB\u30EC\u30F3\u30C0\u30FC\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300D\u3068\u30E6\u30FC\u30B6\u30FC\u306B\u4F1D\u3048\u305F\u4E0A\u3067\u3001\`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
528
+ - \`parameterSlug\`: \`"calendar-id"\`
529
+ - \`options\`: \u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7\u3002\u5404 option \u306E \`label\` \u306F \`\u30AB\u30EC\u30F3\u30C0\u30FC\u540D (owner: impersonateEmail)\` \u306E\u5F62\u5F0F\u3001\`value\` \u306F\u30AB\u30EC\u30F3\u30C0\u30FCID
530
+ - \`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
531
+ 3. \u30E6\u30FC\u30B6\u30FC\u304C\u9078\u629E\u3057\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\u306E \`label\` \u304C\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u3057\u3066\u5C4A\u304F\u3002\u305D\u306E label \u304B\u3089 owner \u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u62BD\u51FA\u3057\u3001\`updateConnectionParameters\` \u3092\u547C\u3073\u51FA\u3059:
532
+ - \`parameterSlug\`: \`"impersonate-email"\`
533
+ - \`options\`: \`[{ value: <ownerEmail>, label: <ownerEmail> }]\`\uFF08\u9078\u629E\u6E08\u307F\u30AB\u30EC\u30F3\u30C0\u30FC\u306E owner email \u3092\u5358\u4E00\u30AA\u30D7\u30B7\u30E7\u30F3\u3068\u3057\u3066\u6E21\u3059\uFF09
534
+ 4. \`updateConnectionContext\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u5BFE\u8C61\u60C5\u5831\u3092\u8A18\u9332\u3059\u308B:
535
+ - \`user\`: \u8A2D\u5B9A\u3057\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9
536
+ - \`calendar\`: \u9078\u629E\u3055\u308C\u305F\u30AB\u30EC\u30F3\u30C0\u30FC\u540D
537
+ - \`calendarId\`: \u9078\u629E\u3055\u308C\u305F\u30AB\u30EC\u30F3\u30C0\u30FCID
538
+ - \`note\`: \u300CDomain-wide Delegation\u3067 {email} \u306E {calendar} \u306B\u30A2\u30AF\u30BB\u30B9\u300D\u306A\u3069\u306E\u8AAC\u660E
539
+
540
+ #### \u5236\u7D04
541
+ - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30E6\u30FC\u30B6\u30FC\u3078\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u7B49\u306E\u5165\u529B\u3092\u6C42\u3081\u306A\u3044\u3053\u3068**\u3002\u5FC5\u8981\u306A\u5024\u306F\u63A5\u7D9A\u4F5C\u6210\u6642\u306E\u30D1\u30E9\u30E1\u30FC\u30BF\uFF08\`impersonate-email\`\uFF09\u304B\u3089\u53D6\u5F97\u3059\u308B
542
+ - **\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
543
+ - \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`,
544
+ en: `Follow these steps to set up the Google Calendar connection.
545
+
546
+ 1. Call \`${listCalendarsToolName}\` to list calendars accessible via the email address(es) configured in the connection's \`impersonate-email\` parameter (comma-separated list supported)
547
+ 2. Using the returned \`calendars\` array (each item: \`{ impersonateEmail, id, summary, primary, accessRole }\`), tell the user "Please select a calendar.", then call \`updateConnectionParameters\`:
548
+ - \`parameterSlug\`: \`"calendar-id"\`
549
+ - \`options\`: The calendar list. Each option's \`label\` should be \`Calendar Name (owner: impersonateEmail)\`, \`value\` should be the calendar ID
550
+ - If \`errors\` contains failing email addresses, briefly mention them
551
+ 3. The \`label\` of the user's selected calendar will arrive as a message. Extract the owner email from that label and call \`updateConnectionParameters\`:
552
+ - \`parameterSlug\`: \`"impersonate-email"\`
553
+ - \`options\`: \`[{ value: <ownerEmail>, label: <ownerEmail> }]\` (pass the selected calendar's owner email as a single option)
554
+ 4. Call \`updateConnectionContext\` to record the target:
555
+ - \`user\`: The configured email address
556
+ - \`calendar\`: The selected calendar's name
557
+ - \`calendarId\`: The selected calendar ID
558
+ - \`note\`: A description such as "Accessing {email}'s {calendar} via Domain-wide Delegation"
559
+
560
+ #### Constraints
561
+ - **Do NOT prompt the user for any input (e.g., email addresses) during setup**. The required values come from the connection parameters (\`impersonate-email\`) filled in at connection creation time
562
+ - **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
563
+ - Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
564
+ },
565
+ dataOverviewInstructions: {
566
+ en: `1. Call google-calendar_request with GET /calendars/{calendarId} to get the default calendar's metadata
567
+ 2. Call google-calendar_request with GET /users/me/calendarList to list all accessible calendars
568
+ 3. Call google-calendar_request with GET /calendars/{calendarId}/events with query params timeMin (RFC3339) and maxResults=10 to sample upcoming events`,
569
+ ja: `1. google-calendar_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
570
+ 2. google-calendar_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
571
+ 3. google-calendar_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`
572
+ }
573
+ });
574
+
575
+ // ../connectors/src/connectors/google-calendar/tools/request.ts
576
+ import { z as z2 } from "zod";
577
+ var BASE_URL3 = "https://www.googleapis.com/calendar/v3";
578
+ var REQUEST_TIMEOUT_MS2 = 6e4;
579
+ var inputSchema2 = z2.object({
580
+ toolUseIntent: z2.string().optional().describe(
581
+ "Brief description of what you intend to accomplish with this tool call"
582
+ ),
583
+ connectionId: z2.string().describe("ID of the Google Calendar connection to use"),
584
+ method: z2.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method"),
585
+ path: z2.string().describe(
586
+ "API path appended to https://www.googleapis.com/calendar/v3 (e.g., '/calendars/{calendarId}/events'). {calendarId} is automatically replaced."
587
+ ),
588
+ queryParams: z2.record(z2.string(), z2.string()).optional().describe("Query parameters to append to the URL"),
589
+ body: z2.record(z2.string(), z2.unknown()).optional().describe("Request body (JSON) for POST/PUT/PATCH methods"),
590
+ subject: z2.string().optional().describe(
591
+ "Override the email address of the user to impersonate via Domain-wide Delegation. If omitted, the connection's configured user email is used."
592
+ )
593
+ });
594
+ var outputSchema2 = z2.discriminatedUnion("success", [
595
+ z2.object({
596
+ success: z2.literal(true),
597
+ status: z2.number(),
598
+ data: z2.record(z2.string(), z2.unknown())
599
+ }),
600
+ z2.object({
601
+ success: z2.literal(false),
602
+ error: z2.string()
603
+ })
604
+ ]);
605
+ var requestTool = new ConnectorTool({
606
+ name: "request",
607
+ description: `Send authenticated requests to the Google Calendar API v3.
608
+ Authentication is handled automatically using a service account.
609
+ {calendarId} in the path is automatically replaced with the connection's default calendar ID.`,
610
+ inputSchema: inputSchema2,
611
+ outputSchema: outputSchema2,
612
+ async execute({ connectionId, method, path: path2, queryParams, body, subject }, connections) {
613
+ const connection2 = connections.find((c) => c.id === connectionId);
614
+ if (!connection2) {
615
+ return {
616
+ success: false,
617
+ error: `Connection ${connectionId} not found`
618
+ };
619
+ }
620
+ console.log(
621
+ `[connector-request] google-calendar/${connection2.name}: ${method} ${path2}`
622
+ );
623
+ try {
624
+ const { GoogleAuth } = await import("google-auth-library");
625
+ const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
626
+ const impersonateEmail = parameters.impersonateEmail.tryGetValue(connection2);
627
+ const calendarId = parameters.calendarId.tryGetValue(connection2) ?? "primary";
628
+ const resolvedSubject = subject ?? impersonateEmail;
629
+ if (!resolvedSubject) {
630
+ return {
631
+ success: false,
632
+ error: `Missing required parameter: ${parameters.impersonateEmail.slug}. Configure the user email for this connection.`
633
+ };
634
+ }
635
+ const credentials = JSON.parse(
636
+ Buffer.from(keyJsonBase64, "base64").toString("utf-8")
637
+ );
638
+ const auth = new GoogleAuth({
639
+ credentials,
640
+ scopes: [
641
+ "https://www.googleapis.com/auth/calendar.readonly",
642
+ "https://www.googleapis.com/auth/calendar.events.readonly"
643
+ ],
644
+ clientOptions: { subject: resolvedSubject }
645
+ });
646
+ const token = await auth.getAccessToken();
647
+ if (!token) {
648
+ return {
649
+ success: false,
650
+ error: "Failed to obtain access token"
651
+ };
652
+ }
653
+ const resolvedPath = path2.replace(/\{calendarId\}/g, calendarId);
654
+ let url = `${BASE_URL3}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
655
+ if (queryParams) {
656
+ const searchParams = new URLSearchParams(queryParams);
657
+ url += `?${searchParams.toString()}`;
658
+ }
659
+ const controller = new AbortController();
660
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
661
+ try {
662
+ const response = await fetch(url, {
663
+ method,
664
+ headers: {
665
+ Authorization: `Bearer ${token}`,
666
+ "Content-Type": "application/json"
667
+ },
668
+ body: body && ["POST", "PUT", "PATCH"].includes(method) ? JSON.stringify(body) : void 0,
669
+ signal: controller.signal
670
+ });
671
+ if (method === "DELETE" && response.status === 204) {
672
+ return {
673
+ success: true,
674
+ status: 204,
675
+ data: { message: "Deleted successfully" }
676
+ };
677
+ }
678
+ const data = await response.json();
679
+ if (!response.ok) {
680
+ const errorObj = data?.error;
681
+ return {
682
+ success: false,
683
+ error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
684
+ };
685
+ }
686
+ return { success: true, status: response.status, data };
687
+ } finally {
688
+ clearTimeout(timeout);
689
+ }
690
+ } catch (err) {
691
+ const msg = err instanceof Error ? err.message : String(err);
692
+ return { success: false, error: msg };
693
+ }
694
+ }
695
+ });
696
+
697
+ // ../connectors/src/connectors/google-calendar/index.ts
698
+ var tools = { request: requestTool, listCalendars: listCalendarsTool };
699
+ var googleCalendarConnector = new ConnectorPlugin({
700
+ slug: "google-calendar",
701
+ authType: AUTH_TYPES.SERVICE_ACCOUNT,
702
+ name: "Google Calendar",
703
+ description: "Connect to Google Calendar for calendar and event data access using a service account.",
704
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/2YsqoBEpdELmfDeFcyGHyE/4494c633b5ae15e562cb739cd85442c1/google-calendar.png",
705
+ parameters,
706
+ releaseFlag: { dev1: true, dev2: true, prod: true },
707
+ onboarding: googleCalendarOnboarding,
708
+ systemPrompt: {
709
+ en: `### Tools
710
+
711
+ - \`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 with Domain-wide Delegation \u2014 the service account impersonates the user configured on the connection (\`impersonate-email\` parameter). The {calendarId} placeholder in paths is automatically replaced with the configured default calendar ID. Pass an optional \`subject\` only if you need to override the configured user for a specific request.
712
+
713
+ ### Business Logic
714
+
715
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
716
+
717
+ SDK methods (client created via \`connection(connectionId)\` \u2014 the connection's \`impersonate-email\` parameter is used automatically for Domain-wide Delegation):
718
+ - \`client.listCalendars()\` \u2014 list all accessible calendars
719
+ - \`client.listEvents(options?, calendarId?)\` \u2014 list events with optional filters
720
+ - \`client.getEvent(eventId, calendarId?)\` \u2014 get a single event by ID
721
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
722
+
723
+ #### Domain-wide Delegation
724
+
725
+ The target user email is configured on the connection (\`impersonate-email\` parameter), so \`connection()\` automatically uses it. Pass \`subject\` only to override it:
726
+
727
+ \`\`\`ts
728
+ const calendar = connection("<connectionId>", { subject: "other-user@example.com" });
729
+ \`\`\`
730
+
731
+ \`\`\`ts
732
+ import type { Context } from "hono";
733
+ import { connection } from "@squadbase/vite-server/connectors/google-calendar";
734
+
735
+ const calendar = connection("<connectionId>");
736
+
737
+ export default async function handler(c: Context) {
738
+ const now = new Date().toISOString();
739
+ const { items } = await calendar.listEvents({
740
+ timeMin: now,
741
+ maxResults: 10,
742
+ singleEvents: true,
743
+ orderBy: "startTime",
744
+ });
745
+
746
+ return c.json(
747
+ items.map((event) => ({
748
+ id: event.id,
749
+ summary: event.summary,
750
+ start: event.start.dateTime ?? event.start.date,
751
+ end: event.end.dateTime ?? event.end.date,
752
+ location: event.location,
753
+ })),
754
+ );
755
+ }
756
+ \`\`\`
757
+
758
+ ### Google Calendar API v3 Reference
759
+
760
+ #### Available Endpoints
761
+ - GET \`/calendars/{calendarId}\` \u2014 Get calendar metadata
762
+ - GET \`/users/me/calendarList\` \u2014 List all calendars accessible by the authenticated user
763
+ - GET \`/calendars/{calendarId}/events\` \u2014 List events on a calendar
764
+ - GET \`/calendars/{calendarId}/events/{eventId}\` \u2014 Get a single event
765
+
766
+ #### Common Query Parameters for Event Listing
767
+ - \`timeMin\` \u2014 Lower bound (RFC3339 timestamp, e.g., "2024-01-01T00:00:00Z")
768
+ - \`timeMax\` \u2014 Upper bound (RFC3339 timestamp)
769
+ - \`maxResults\` \u2014 Maximum number of events (default 250, max 2500)
770
+ - \`singleEvents=true\` \u2014 Expand recurring events into individual instances
771
+ - \`orderBy=startTime\` \u2014 Order by start time (requires singleEvents=true)
772
+ - \`q\` \u2014 Free text search terms
773
+
774
+ #### Tips
775
+ - Use \`{calendarId}\` placeholder in paths \u2014 it is automatically replaced with the configured default calendar ID
776
+ - Set \`singleEvents=true\` to expand recurring events into individual instances
777
+ - When using \`orderBy=startTime\`, you must also set \`singleEvents=true\`
778
+ - Use RFC3339 format for time parameters (e.g., "2024-01-15T09:00:00Z" or "2024-01-15T09:00:00+09:00")
779
+ - The default calendar ID is "primary" if not configured`,
780
+ ja: `### \u30C4\u30FC\u30EB
781
+
782
+ - \`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\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
783
+
784
+ ### Business Logic
785
+
786
+ \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
787
+
788
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8 \u2014 \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\`impersonate-email\`\u30D1\u30E9\u30E1\u30FC\u30BF\u304C\u81EA\u52D5\u7684\u306BDomain-wide Delegation\u306Esubject\u3068\u3057\u3066\u4F7F\u308F\u308C\u307E\u3059):
789
+ - \`client.listCalendars()\` \u2014 \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5168\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7\u53D6\u5F97
790
+ - \`client.listEvents(options?, calendarId?)\` \u2014 \u30D5\u30A3\u30EB\u30BF\u30FC\u4ED8\u304D\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7\u53D6\u5F97
791
+ - \`client.getEvent(eventId, calendarId?)\` \u2014 ID\u306B\u3088\u308B\u5358\u4E00\u30A4\u30D9\u30F3\u30C8\u53D6\u5F97
792
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
793
+
794
+ #### Domain-wide Delegation
795
+
796
+ \u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\uFF08\`impersonate-email\`\u30D1\u30E9\u30E1\u30FC\u30BF\uFF09\u306B\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u305F\u3081\u3001\`connection()\`\u306F\u81EA\u52D5\u7684\u306B\u305D\u308C\u3092\u4F7F\u3044\u307E\u3059\u3002\u4E0A\u66F8\u304D\u3057\u305F\u3044\u5834\u5408\u306E\u307F\`subject\`\u3092\u6E21\u3057\u307E\u3059\uFF1A
797
+
798
+ \`\`\`ts
799
+ const calendar = connection("<connectionId>", { subject: "other-user@example.com" });
800
+ \`\`\`
801
+
802
+ \`\`\`ts
803
+ import type { Context } from "hono";
804
+ import { connection } from "@squadbase/vite-server/connectors/google-calendar";
805
+
806
+ const calendar = connection("<connectionId>");
807
+
808
+ export default async function handler(c: Context) {
809
+ const now = new Date().toISOString();
810
+ const { items } = await calendar.listEvents({
811
+ timeMin: now,
812
+ maxResults: 10,
813
+ singleEvents: true,
814
+ orderBy: "startTime",
815
+ });
816
+
817
+ return c.json(
818
+ items.map((event) => ({
819
+ id: event.id,
820
+ summary: event.summary,
821
+ start: event.start.dateTime ?? event.start.date,
822
+ end: event.end.dateTime ?? event.end.date,
823
+ location: event.location,
824
+ })),
825
+ );
826
+ }
827
+ \`\`\`
828
+
829
+ ### Google Calendar API v3 \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
830
+
831
+ #### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
832
+ - GET \`/calendars/{calendarId}\` \u2014 \u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
833
+ - GET \`/users/me/calendarList\` \u2014 \u8A8D\u8A3C\u30E6\u30FC\u30B6\u30FC\u304C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u5168\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u4E00\u89A7
834
+ - GET \`/calendars/{calendarId}/events\` \u2014 \u30AB\u30EC\u30F3\u30C0\u30FC\u4E0A\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7
835
+ - GET \`/calendars/{calendarId}/events/{eventId}\` \u2014 \u5358\u4E00\u30A4\u30D9\u30F3\u30C8\u306E\u53D6\u5F97
836
+
837
+ #### \u30A4\u30D9\u30F3\u30C8\u4E00\u89A7\u306E\u4E3B\u8981\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF
838
+ - \`timeMin\` \u2014 \u4E0B\u9650\uFF08RFC3339\u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7\u3001\u4F8B: "2024-01-01T00:00:00Z"\uFF09
839
+ - \`timeMax\` \u2014 \u4E0A\u9650\uFF08RFC3339\u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7\uFF09
840
+ - \`maxResults\` \u2014 \u6700\u5927\u30A4\u30D9\u30F3\u30C8\u6570\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8250\u3001\u6700\u59272500\uFF09
841
+ - \`singleEvents=true\` \u2014 \u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u3092\u500B\u5225\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306B\u5C55\u958B
842
+ - \`orderBy=startTime\` \u2014 \u958B\u59CB\u6642\u9593\u9806\u306B\u4E26\u3079\u66FF\u3048\uFF08singleEvents=true\u304C\u5FC5\u8981\uFF09
843
+ - \`q\` \u2014 \u30D5\u30EA\u30FC\u30C6\u30AD\u30B9\u30C8\u691C\u7D22\u8A9E
844
+
845
+ #### \u30D2\u30F3\u30C8
846
+ - \u30D1\u30B9\u306B \`{calendarId}\` \u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u3092\u4F7F\u7528 \u2014 \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
847
+ - \`singleEvents=true\` \u3092\u8A2D\u5B9A\u3059\u308B\u3068\u3001\u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u304C\u500B\u5225\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306B\u5C55\u958B\u3055\u308C\u307E\u3059
848
+ - \`orderBy=startTime\` \u3092\u4F7F\u7528\u3059\u308B\u5834\u5408\u3001\`singleEvents=true\` \u3082\u8A2D\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
849
+ - \u6642\u9593\u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u306FRFC3339\u5F62\u5F0F\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: "2024-01-15T09:00:00Z" \u3084 "2024-01-15T09:00:00+09:00"\uFF09
850
+ - \u30C7\u30D5\u30A9\u30EB\u30C8\u30AB\u30EC\u30F3\u30C0\u30FCID\u306F\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u306A\u3044\u5834\u5408 "primary" \u304C\u4F7F\u7528\u3055\u308C\u307E\u3059`
851
+ },
852
+ tools
853
+ });
854
+
855
+ // src/connectors/create-connector-sdk.ts
856
+ import { readFileSync } from "fs";
857
+ import path from "path";
858
+
859
+ // src/connector-client/env.ts
860
+ function resolveEnvVar(entry, key, connectionId) {
861
+ const envVarName = entry.envVars[key];
862
+ if (!envVarName) {
863
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
864
+ }
865
+ const value = process.env[envVarName];
866
+ if (!value) {
867
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
868
+ }
869
+ return value;
870
+ }
871
+ function resolveEnvVarOptional(entry, key) {
872
+ const envVarName = entry.envVars[key];
873
+ if (!envVarName) return void 0;
874
+ return process.env[envVarName] || void 0;
875
+ }
876
+
877
+ // src/connector-client/proxy-fetch.ts
878
+ import { getContext } from "hono/context-storage";
879
+ import { getCookie } from "hono/cookie";
880
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
881
+ function createSandboxProxyFetch(connectionId) {
882
+ return async (input, init) => {
883
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
884
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
885
+ if (!token || !sandboxId) {
886
+ throw new Error(
887
+ "Connection proxy is not configured. Please check your deployment settings."
888
+ );
889
+ }
890
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
891
+ const originalMethod = init?.method ?? "GET";
892
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
893
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
894
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
895
+ return fetch(proxyUrl, {
896
+ method: "POST",
897
+ headers: {
898
+ "Content-Type": "application/json",
899
+ Authorization: `Bearer ${token}`
900
+ },
901
+ body: JSON.stringify({
902
+ url: originalUrl,
903
+ method: originalMethod,
904
+ body: originalBody
905
+ })
906
+ });
907
+ };
908
+ }
909
+ function createDeployedAppProxyFetch(connectionId) {
910
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
911
+ if (!projectId) {
912
+ throw new Error(
913
+ "Connection proxy is not configured. Please check your deployment settings."
914
+ );
915
+ }
916
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
917
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
918
+ return async (input, init) => {
919
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
920
+ const originalMethod = init?.method ?? "GET";
921
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
922
+ const c = getContext();
923
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
924
+ if (!appSession) {
925
+ throw new Error(
926
+ "No authentication method available for connection proxy."
927
+ );
928
+ }
929
+ return fetch(proxyUrl, {
930
+ method: "POST",
931
+ headers: {
932
+ "Content-Type": "application/json",
933
+ Authorization: `Bearer ${appSession}`
934
+ },
935
+ body: JSON.stringify({
936
+ url: originalUrl,
937
+ method: originalMethod,
938
+ body: originalBody
939
+ })
940
+ });
941
+ };
942
+ }
943
+ function createProxyFetch(connectionId) {
944
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
945
+ return createSandboxProxyFetch(connectionId);
946
+ }
947
+ return createDeployedAppProxyFetch(connectionId);
948
+ }
949
+
950
+ // src/connectors/create-connector-sdk.ts
951
+ function loadConnectionsSync() {
952
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
953
+ try {
954
+ const raw = readFileSync(filePath, "utf-8");
955
+ return JSON.parse(raw);
956
+ } catch {
957
+ return {};
958
+ }
959
+ }
960
+ function createConnectorSdk(plugin, createClient2) {
961
+ return (connectionId) => {
962
+ const connections = loadConnectionsSync();
963
+ const entry = connections[connectionId];
964
+ if (!entry) {
965
+ throw new Error(
966
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
967
+ );
968
+ }
969
+ if (entry.connector.slug !== plugin.slug) {
970
+ throw new Error(
971
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
972
+ );
973
+ }
974
+ const params = {};
975
+ for (const param of Object.values(plugin.parameters)) {
976
+ if (param.required) {
977
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
978
+ } else {
979
+ const val = resolveEnvVarOptional(entry, param.slug);
980
+ if (val !== void 0) params[param.slug] = val;
981
+ }
982
+ }
983
+ return createClient2(params, createProxyFetch(connectionId));
984
+ };
985
+ }
986
+
987
+ // src/connectors/entries/google-calendar.ts
988
+ var connection = createConnectorSdk(googleCalendarConnector, createClient);
989
+ export {
990
+ connection
991
+ };