@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.
Files changed (88) hide show
  1. package/dist/cli/index.js +78505 -64782
  2. package/dist/cli/{sshcrypto-VVJOJ3LR.node → sshcrypto-P3UBA7BP.node} +0 -0
  3. package/dist/connectors/airtable-oauth.js +3 -0
  4. package/dist/connectors/airtable.js +3 -0
  5. package/dist/connectors/amplitude.js +3 -0
  6. package/dist/connectors/anthropic.js +3 -0
  7. package/dist/connectors/asana.js +18 -2
  8. package/dist/connectors/attio.js +3 -0
  9. package/dist/connectors/aws-billing.d.ts +5 -0
  10. package/dist/connectors/aws-billing.js +29843 -0
  11. package/dist/connectors/azure-sql.d.ts +5 -0
  12. package/dist/connectors/azure-sql.js +657 -0
  13. package/dist/connectors/backlog-api-key.js +3 -0
  14. package/dist/connectors/clickup.d.ts +5 -0
  15. package/dist/connectors/clickup.js +850 -0
  16. package/dist/connectors/customerio.js +3 -0
  17. package/dist/connectors/dbt.js +3 -0
  18. package/dist/connectors/freshdesk.d.ts +5 -0
  19. package/dist/connectors/freshdesk.js +842 -0
  20. package/dist/connectors/freshsales.d.ts +5 -0
  21. package/dist/connectors/freshsales.js +867 -0
  22. package/dist/connectors/freshservice.d.ts +5 -0
  23. package/dist/connectors/freshservice.js +813 -0
  24. package/dist/connectors/gamma.js +3 -0
  25. package/dist/connectors/gemini.js +3 -0
  26. package/dist/connectors/github.d.ts +5 -0
  27. package/dist/connectors/github.js +963 -0
  28. package/dist/connectors/gmail-oauth.js +18 -2
  29. package/dist/connectors/gmail.js +236 -352
  30. package/dist/connectors/google-ads.js +3 -0
  31. package/dist/connectors/google-analytics-oauth.js +3 -0
  32. package/dist/connectors/google-analytics.js +3 -0
  33. package/dist/connectors/google-audit-log.d.ts +5 -0
  34. package/dist/connectors/google-audit-log.js +813 -0
  35. package/dist/connectors/google-calendar-oauth.js +21 -2
  36. package/dist/connectors/google-calendar.js +548 -453
  37. package/dist/connectors/google-docs.js +21 -2
  38. package/dist/connectors/google-drive.js +18 -2
  39. package/dist/connectors/google-search-console-oauth.d.ts +5 -0
  40. package/dist/connectors/google-search-console-oauth.js +923 -0
  41. package/dist/connectors/google-sheets.js +21 -2
  42. package/dist/connectors/google-slides.js +21 -2
  43. package/dist/connectors/grafana.js +3 -0
  44. package/dist/connectors/hubspot-oauth.js +3 -0
  45. package/dist/connectors/hubspot.js +3 -0
  46. package/dist/connectors/influxdb.js +3 -0
  47. package/dist/connectors/intercom-oauth.js +3 -0
  48. package/dist/connectors/intercom.js +3 -0
  49. package/dist/connectors/jdbc.d.ts +5 -0
  50. package/dist/connectors/jdbc.js +21097 -0
  51. package/dist/connectors/jira-api-key.js +3 -0
  52. package/dist/connectors/kintone-api-token.js +3 -0
  53. package/dist/connectors/kintone.js +3 -0
  54. package/dist/connectors/linear.js +3 -0
  55. package/dist/connectors/linkedin-ads.js +3 -0
  56. package/dist/connectors/mailchimp-oauth.js +3 -0
  57. package/dist/connectors/mailchimp.js +3 -0
  58. package/dist/connectors/meta-ads-oauth.js +3 -0
  59. package/dist/connectors/meta-ads.js +3 -0
  60. package/dist/connectors/mixpanel.js +3 -0
  61. package/dist/connectors/monday.d.ts +5 -0
  62. package/dist/connectors/monday.js +813 -0
  63. package/dist/connectors/notion-oauth.js +3 -0
  64. package/dist/connectors/notion.js +3 -0
  65. package/dist/connectors/openai.js +3 -0
  66. package/dist/connectors/oracle.d.ts +5 -0
  67. package/dist/connectors/oracle.js +665 -0
  68. package/dist/connectors/salesforce.js +3 -0
  69. package/dist/connectors/semrush.d.ts +5 -0
  70. package/dist/connectors/semrush.js +812 -0
  71. package/dist/connectors/sentry.js +3 -0
  72. package/dist/connectors/shopify-oauth.js +3 -0
  73. package/dist/connectors/shopify.js +3 -0
  74. package/dist/connectors/sqlserver.d.ts +5 -0
  75. package/dist/connectors/sqlserver.js +656 -0
  76. package/dist/connectors/stripe-api-key.js +3 -0
  77. package/dist/connectors/stripe-oauth.js +3 -0
  78. package/dist/connectors/supabase.d.ts +5 -0
  79. package/dist/connectors/supabase.js +582 -0
  80. package/dist/connectors/tiktok-ads.js +18 -2
  81. package/dist/connectors/wix-store.js +3 -0
  82. package/dist/connectors/zendesk-oauth.js +3 -0
  83. package/dist/connectors/zendesk.js +3 -0
  84. package/dist/index.js +71474 -57751
  85. package/dist/main.js +78053 -64330
  86. package/dist/{sshcrypto-VVJOJ3LR.node → sshcrypto-P3UBA7BP.node} +0 -0
  87. package/dist/vite-plugin.js +77960 -64237
  88. package/package.json +64 -2
@@ -42,71 +42,28 @@ var ParameterDefinition = class {
42
42
  }
43
43
  };
44
44
 
45
- // ../connectors/src/connectors/gmail/sdk/index.ts
46
- import * as crypto from "crypto";
47
-
48
45
  // ../connectors/src/connectors/gmail/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 used to authenticate with Google Cloud Platform. The service account must have domain-wide delegation enabled and be granted the Gmail API scope in Google Workspace admin.",
50
+ description: "The service account JSON key. Domain-wide Delegation must be authorized in the Google Workspace admin console for the Gmail API scope. The user to impersonate is supplied per call as the `subject` argument.",
54
51
  envVarBaseKey: "GMAIL_SERVICE_ACCOUNT_JSON_BASE64",
55
52
  type: "base64EncodedJson",
56
53
  secret: true,
57
54
  required: true
58
55
  })
59
56
  };
60
- var delegatedUserEmailParameter = new ParameterDefinition({
61
- slug: "delegated-user-email",
62
- name: "Delegated User Email",
63
- description: "The email address of the Google Workspace user whose Gmail mailbox the service account will access via domain-wide delegation. Collected during the setup flow.",
64
- envVarBaseKey: "GMAIL_DELEGATED_USER_EMAIL",
65
- type: "text",
66
- secret: false,
67
- required: false
68
- });
69
57
 
70
58
  // ../connectors/src/connectors/gmail/sdk/index.ts
71
- var TOKEN_URL = "https://oauth2.googleapis.com/token";
72
59
  var BASE_URL = "https://gmail.googleapis.com/gmail/v1/users";
73
- var SCOPE = "https://www.googleapis.com/auth/gmail.readonly";
74
- function base64url(input) {
75
- const buf = typeof input === "string" ? Buffer.from(input) : input;
76
- return buf.toString("base64url");
77
- }
78
- function buildJwt(clientEmail, privateKey, subject, nowSec) {
79
- const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
80
- const payload = base64url(
81
- JSON.stringify({
82
- iss: clientEmail,
83
- sub: subject,
84
- scope: SCOPE,
85
- aud: TOKEN_URL,
86
- iat: nowSec,
87
- exp: nowSec + 3600
88
- })
89
- );
90
- const signingInput = `${header}.${payload}`;
91
- const sign = crypto.createSign("RSA-SHA256");
92
- sign.update(signingInput);
93
- sign.end();
94
- const signature = base64url(sign.sign(privateKey));
95
- return `${signingInput}.${signature}`;
96
- }
97
60
  function createClient(params) {
98
61
  const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
99
- const delegatedUserEmail = params[delegatedUserEmailParameter.slug];
100
62
  if (!serviceAccountKeyJsonBase64) {
101
63
  throw new Error(
102
64
  `gmail: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
103
65
  );
104
66
  }
105
- if (!delegatedUserEmail) {
106
- throw new Error(
107
- `gmail: missing required parameter: ${delegatedUserEmailParameter.slug}`
108
- );
109
- }
110
67
  let serviceAccountKey;
111
68
  try {
112
69
  const decoded = Buffer.from(
@@ -124,143 +81,28 @@ function createClient(params) {
124
81
  "gmail: service account key JSON must contain client_email and private_key"
125
82
  );
126
83
  }
127
- let cachedToken = null;
128
- let tokenExpiresAt = 0;
129
- async function getAccessToken() {
130
- const nowSec = Math.floor(Date.now() / 1e3);
131
- if (cachedToken && nowSec < tokenExpiresAt - 60) {
132
- return cachedToken;
133
- }
134
- const jwt = buildJwt(
135
- serviceAccountKey.client_email,
136
- serviceAccountKey.private_key,
137
- delegatedUserEmail,
138
- nowSec
139
- );
140
- const response = await fetch(TOKEN_URL, {
141
- method: "POST",
142
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
143
- body: new URLSearchParams({
144
- grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
145
- assertion: jwt
146
- })
147
- });
148
- if (!response.ok) {
149
- const text = await response.text();
150
- throw new Error(
151
- `gmail: token exchange failed (${response.status}): ${text}`
152
- );
153
- }
154
- const data = await response.json();
155
- cachedToken = data.access_token;
156
- tokenExpiresAt = nowSec + data.expires_in;
157
- return cachedToken;
158
- }
159
- async function request(path2, init) {
160
- const accessToken = await getAccessToken();
161
- const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
162
- const headers = new Headers(init?.headers);
163
- headers.set("Authorization", `Bearer ${accessToken}`);
164
- return fetch(url, { ...init, headers });
165
- }
166
- async function getProfile() {
167
- const response = await request("/me/profile");
168
- if (!response.ok) {
169
- const body = await response.text();
170
- throw new Error(
171
- `gmail: getProfile failed (${response.status}): ${body}`
172
- );
173
- }
174
- return await response.json();
175
- }
176
- async function listLabels() {
177
- const response = await request("/me/labels");
178
- if (!response.ok) {
179
- const body = await response.text();
180
- throw new Error(
181
- `gmail: listLabels failed (${response.status}): ${body}`
182
- );
183
- }
184
- return await response.json();
185
- }
186
- async function listMessages(options) {
187
- const params2 = new URLSearchParams();
188
- if (options?.q) params2.set("q", options.q);
189
- if (options?.maxResults) params2.set("maxResults", String(options.maxResults));
190
- if (options?.pageToken) params2.set("pageToken", options.pageToken);
191
- if (options?.labelIds) {
192
- for (const labelId of options.labelIds) {
193
- params2.append("labelIds", labelId);
194
- }
195
- }
196
- const qs = params2.toString();
197
- const response = await request(`/me/messages${qs ? `?${qs}` : ""}`);
198
- if (!response.ok) {
199
- const body = await response.text();
200
- throw new Error(
201
- `gmail: listMessages failed (${response.status}): ${body}`
202
- );
203
- }
204
- return await response.json();
205
- }
206
- async function getMessage(messageId, format) {
207
- const p = new URLSearchParams();
208
- if (format) p.set("format", format);
209
- const qs = p.toString();
210
- const response = await request(
211
- `/me/messages/${encodeURIComponent(messageId)}${qs ? `?${qs}` : ""}`
212
- );
213
- if (!response.ok) {
214
- const body = await response.text();
215
- throw new Error(
216
- `gmail: getMessage failed (${response.status}): ${body}`
217
- );
218
- }
219
- return await response.json();
220
- }
221
- async function listThreads(options) {
222
- const params2 = new URLSearchParams();
223
- if (options?.q) params2.set("q", options.q);
224
- if (options?.maxResults) params2.set("maxResults", String(options.maxResults));
225
- if (options?.pageToken) params2.set("pageToken", options.pageToken);
226
- if (options?.labelIds) {
227
- for (const labelId of options.labelIds) {
228
- params2.append("labelIds", labelId);
84
+ return {
85
+ async requestWithDelegation(path2, { subject, scopes, init }) {
86
+ const { GoogleAuth } = await import("google-auth-library");
87
+ const auth = new GoogleAuth({
88
+ credentials: {
89
+ client_email: serviceAccountKey.client_email,
90
+ private_key: serviceAccountKey.private_key
91
+ },
92
+ scopes,
93
+ clientOptions: { subject }
94
+ });
95
+ const token = await auth.getAccessToken();
96
+ if (!token) {
97
+ throw new Error(
98
+ `gmail: failed to obtain access token for ${subject}`
99
+ );
229
100
  }
101
+ const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
102
+ const headers = new Headers(init?.headers);
103
+ headers.set("Authorization", `Bearer ${token}`);
104
+ return fetch(url, { ...init, headers });
230
105
  }
231
- const qs = params2.toString();
232
- const response = await request(`/me/threads${qs ? `?${qs}` : ""}`);
233
- if (!response.ok) {
234
- const body = await response.text();
235
- throw new Error(
236
- `gmail: listThreads failed (${response.status}): ${body}`
237
- );
238
- }
239
- return await response.json();
240
- }
241
- async function getThread(threadId, format) {
242
- const p = new URLSearchParams();
243
- if (format) p.set("format", format);
244
- const qs = p.toString();
245
- const response = await request(
246
- `/me/threads/${encodeURIComponent(threadId)}${qs ? `?${qs}` : ""}`
247
- );
248
- if (!response.ok) {
249
- const body = await response.text();
250
- throw new Error(
251
- `gmail: getThread failed (${response.status}): ${body}`
252
- );
253
- }
254
- return await response.json();
255
- }
256
- return {
257
- request,
258
- getProfile,
259
- listLabels,
260
- listMessages,
261
- getMessage,
262
- listThreads,
263
- getThread
264
106
  };
265
107
  }
266
108
 
@@ -317,6 +159,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
317
159
  releaseFlag;
318
160
  proxyPolicy;
319
161
  experimentalAttributes;
162
+ categories;
320
163
  onboarding;
321
164
  systemPrompt;
322
165
  tools;
@@ -332,6 +175,7 @@ var ConnectorPlugin = class _ConnectorPlugin {
332
175
  this.releaseFlag = config.releaseFlag;
333
176
  this.proxyPolicy = config.proxyPolicy;
334
177
  this.experimentalAttributes = config.experimentalAttributes;
178
+ this.categories = config.categories ?? [];
335
179
  this.onboarding = config.onboarding;
336
180
  this.systemPrompt = config.systemPrompt;
337
181
  this.tools = config.tools;
@@ -411,42 +255,65 @@ var AUTH_TYPES = {
411
255
  USER_PASSWORD: "user-password"
412
256
  };
413
257
 
414
- // ../connectors/src/connectors/gmail/tools/request.ts
258
+ // ../connectors/src/lib/normalize-path.ts
259
+ function normalizeRequestPath(path2, basePathSegment) {
260
+ let p = path2.trim();
261
+ if (!p.startsWith("/")) p = "/" + p;
262
+ if (p === basePathSegment || p.startsWith(basePathSegment + "/")) {
263
+ p = p.slice(basePathSegment.length) || "/";
264
+ }
265
+ return p;
266
+ }
267
+
268
+ // ../connectors/src/connectors/gmail/tools/request-with-delegation.ts
415
269
  import { z } from "zod";
416
- var BASE_URL2 = "https://gmail.googleapis.com/gmail/v1/users";
270
+ var BASE_HOST = "https://gmail.googleapis.com";
271
+ var BASE_PATH_SEGMENT = "/gmail/v1/users";
272
+ var BASE_URL2 = `${BASE_HOST}${BASE_PATH_SEGMENT}`;
417
273
  var REQUEST_TIMEOUT_MS = 6e4;
274
+ function decodeServiceAccount(keyJsonBase64) {
275
+ const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
276
+ return JSON.parse(decoded);
277
+ }
418
278
  var inputSchema = z.object({
419
279
  toolUseIntent: z.string().optional().describe(
420
280
  "Brief description of what you intend to accomplish with this tool call"
421
281
  ),
422
282
  connectionId: z.string().describe("ID of the Gmail service account connection to use"),
423
- method: z.enum(["GET"]).describe("HTTP method (read-only, GET only)"),
283
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method"),
424
284
  path: z.string().describe(
425
- "API path appended to https://gmail.googleapis.com/gmail/v1/users (e.g., '/me/messages', '/me/messages/{id}', '/me/labels'). Use '/me' as the userId."
285
+ "API path appended to https://gmail.googleapis.com/gmail/v1/users (e.g., '/me/messages', '/me/messages/{id}', '/me/labels'). Use '/me' as the userId \u2014 the impersonated user."
286
+ ),
287
+ subject: z.string().describe(
288
+ "Email of the Workspace user to impersonate via Domain-wide Delegation. The token will be issued as this user."
289
+ ),
290
+ scopes: z.array(z.string()).describe(
291
+ "OAuth scopes the token must include. This connector currently supports read-only operations only \u2014 pass ['https://www.googleapis.com/auth/gmail.readonly']. Per-endpoint scope reference: https://developers.google.com/gmail/api/auth/scopes"
426
292
  ),
427
293
  queryParams: z.record(z.string(), z.string()).optional().describe(
428
294
  "Query parameters to append to the URL (e.g., { q: 'from:example@gmail.com', maxResults: '10' })"
429
- )
295
+ ),
296
+ body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PUT/PATCH")
430
297
  });
431
298
  var outputSchema = z.discriminatedUnion("success", [
432
299
  z.object({
433
300
  success: z.literal(true),
434
301
  status: z.number(),
435
- data: z.record(z.string(), z.unknown())
302
+ data: z.record(z.string(), z.unknown()),
303
+ serviceAccountEmail: z.string()
436
304
  }),
437
305
  z.object({
438
306
  success: z.literal(false),
439
- error: z.string()
307
+ error: z.string(),
308
+ serviceAccountEmail: z.string().optional()
440
309
  })
441
310
  ]);
442
- var requestTool = new ConnectorTool({
443
- name: "request",
444
- description: `Send authenticated GET requests to the Gmail API v1.
445
- Authentication is handled automatically using a service account with domain-wide delegation.
446
- All paths are relative to https://gmail.googleapis.com/gmail/v1/users. Use '/me' as the userId prefix (e.g., '/me/messages').`,
311
+ var requestWithDelegationTool = new ConnectorTool({
312
+ name: "request_with_delegation",
313
+ description: "Call the Gmail 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 ['https://www.googleapis.com/auth/gmail.readonly']. Paths are relative to https://gmail.googleapis.com/gmail/v1/users \u2014 use '/me' as the userId prefix (e.g., '/me/messages'). Requires Domain-wide Delegation to be authorized for the service account in the Workspace admin console.",
447
314
  inputSchema,
448
315
  outputSchema,
449
- async execute({ connectionId, method, path: path2, queryParams }, connections) {
316
+ async execute({ connectionId, method, path: path2, subject, scopes, queryParams, body }, connections) {
450
317
  const connection2 = connections.find((c) => c.id === connectionId);
451
318
  if (!connection2) {
452
319
  return {
@@ -454,31 +321,41 @@ All paths are relative to https://gmail.googleapis.com/gmail/v1/users. Use '/me'
454
321
  error: `Connection ${connectionId} not found`
455
322
  };
456
323
  }
324
+ const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
325
+ let serviceAccount;
326
+ try {
327
+ serviceAccount = decodeServiceAccount(keyJsonBase64);
328
+ } catch (err) {
329
+ const msg = err instanceof Error ? err.message : String(err);
330
+ return {
331
+ success: false,
332
+ error: `Failed to decode service account key: ${msg}`
333
+ };
334
+ }
335
+ const serviceAccountEmail = serviceAccount.client_email;
457
336
  console.log(
458
- `[connector-request] gmail/${connection2.name}: ${method} ${path2}`
337
+ `[connector-request] gmail/${connection2.name}: ${method} ${path2} subject=${subject}`
459
338
  );
460
339
  try {
461
340
  const { GoogleAuth } = await import("google-auth-library");
462
- const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
463
- const delegatedUserEmail = delegatedUserEmailParameter.getValue(connection2);
464
- const credentials = JSON.parse(
465
- Buffer.from(keyJsonBase64, "base64").toString("utf-8")
466
- );
467
341
  const auth = new GoogleAuth({
468
- credentials,
469
- scopes: ["https://www.googleapis.com/auth/gmail.readonly"],
470
- clientOptions: {
471
- subject: delegatedUserEmail
472
- }
342
+ credentials: {
343
+ client_email: serviceAccount.client_email,
344
+ private_key: serviceAccount.private_key
345
+ },
346
+ scopes,
347
+ clientOptions: { subject }
473
348
  });
474
349
  const token = await auth.getAccessToken();
475
350
  if (!token) {
476
351
  return {
477
352
  success: false,
478
- error: "Failed to obtain access token"
353
+ error: "Failed to obtain access token",
354
+ serviceAccountEmail
479
355
  };
480
356
  }
481
- let url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
357
+ const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT);
358
+ let url = `${BASE_URL2}${normalizedPath}`;
482
359
  if (queryParams) {
483
360
  const searchParams = new URLSearchParams(queryParams);
484
361
  url += `?${searchParams.toString()}`;
@@ -486,111 +363,143 @@ All paths are relative to https://gmail.googleapis.com/gmail/v1/users. Use '/me'
486
363
  const controller = new AbortController();
487
364
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
488
365
  try {
366
+ const hasBody = body != null && ["POST", "PUT", "PATCH"].includes(method);
489
367
  const response = await fetch(url, {
490
368
  method,
491
369
  headers: {
492
370
  Authorization: `Bearer ${token}`,
493
371
  "Content-Type": "application/json"
494
372
  },
373
+ body: hasBody ? JSON.stringify(body) : void 0,
495
374
  signal: controller.signal
496
375
  });
497
- const data = await response.json();
376
+ const data = await response.json().catch(() => ({}));
498
377
  if (!response.ok) {
499
- const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
500
- return { success: false, error: errorMessage };
378
+ const errorObj = data?.error;
379
+ const errorMessage = errorObj?.message ?? (typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`);
380
+ return {
381
+ success: false,
382
+ error: errorMessage,
383
+ serviceAccountEmail
384
+ };
501
385
  }
502
- return { success: true, status: response.status, data };
386
+ return {
387
+ success: true,
388
+ status: response.status,
389
+ data,
390
+ serviceAccountEmail
391
+ };
503
392
  } finally {
504
393
  clearTimeout(timeout);
505
394
  }
506
395
  } catch (err) {
507
396
  const msg = err instanceof Error ? err.message : String(err);
508
- return { success: false, error: msg };
397
+ return {
398
+ success: false,
399
+ error: msg,
400
+ serviceAccountEmail
401
+ };
509
402
  }
510
403
  }
511
404
  });
512
405
 
513
406
  // ../connectors/src/connectors/gmail/setup.ts
514
- var requestToolName = `gmail-service-account_${requestTool.name}`;
407
+ var requestWithDelegationToolName = `gmail-service-account_${requestWithDelegationTool.name}`;
408
+ var READONLY_SCOPES = '["https://www.googleapis.com/auth/gmail.readonly"]';
515
409
  var gmailOnboarding = new ConnectorOnboarding({
516
410
  connectionSetupInstructions: {
517
- ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Gmail\uFF08\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\uFF09\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\u59D4\u4EFB\u5BFE\u8C61\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u3053\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u53D6\u5F97\u3057\u307E\u3059\u3002
411
+ ja: `Gmail\uFF08\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\uFF09\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3044\u307E\u3059\u3002\u30A2\u30AF\u30BB\u30B9\u5BFE\u8C61\u306E Workspace \u30E6\u30FC\u30B6\u30FC\u3092\u30E6\u30FC\u30B6\u30FC\u304B\u3089\u805E\u304D\u3001Project Knowledge \u306B\u8A18\u9332\u3057\u307E\u3059\u3002
518
412
 
519
- 1. \`askUserQuestion\` \u3067\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:
413
+ 1. \`askUserQuestion\` \u3067\u5BFE\u8C61\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u805E\u304F:
520
414
  - \`type\`: \`"freeText"\`
521
- - \`question\`: \u300CGmail\u3092\u53C2\u7167\u3059\u308BGoogle Workspace\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u300D
522
- - \`placeholder\`: \`"user@example.com"\`
523
- 2. \u53D7\u3051\u53D6\u3063\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 \`updateConnectionParameters\` \u3067\u4FDD\u5B58\u3059\u308B:
524
- - \`parameterSlug\`: \`"delegated-user-email"\`
525
- - \`options\`: \`[{ value: <\u5165\u529B\u3055\u308C\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9>, label: <\u540C\u3058\u5024> }]\`\uFF081\u4EF6\u306E\u307F\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u81EA\u52D5\u9078\u629E\u3055\u308C\u308B\uFF09
526
- 3. \`${requestToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u3092\u53D6\u5F97\u3059\u308B:
415
+ - \`question\`: \u300CGmail \u3092\u53C2\u7167\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\u300D
416
+ - \`placeholder\`: \`"alice@example.com, bob@example.com"\`
417
+
418
+ 2. \u30E6\u30FC\u30B6\u30FC\u304B\u3089\u53D7\u3051\u53D6\u3063\u305F\u6587\u5B57\u5217\u304B\u3089\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u62BD\u51FA\u3059\u308B\u3002\u5404 \`<email>\` \u306B\u3064\u3044\u3066 \`${requestWithDelegationToolName}\` \u3092\u4EE5\u4E0B\u306E\u5F15\u6570\u3067\u547C\u3073\u3001Domain-wide Delegation \u7D4C\u7531\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u304B\u3092\u78BA\u8A8D\u3059\u308B:
527
419
  - \`method\`: \`"GET"\`
528
420
  - \`path\`: \`"/me/profile"\`
529
- 4. \u30A8\u30E9\u30FC\u304C\u8FD4\u3055\u308C\u305F\u5834\u5408\u3001\u4EE5\u4E0B\u3092\u78BA\u8A8D\u3059\u308B\u3088\u3046\u30E6\u30FC\u30B6\u30FC\u306B\u4F1D\u3048\u308B:
530
- - \u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u304C\u6709\u52B9\u304B
531
- - Google Workspace\u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u3067Gmail API\u30B9\u30B3\u30FC\u30D7\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u308B\u304B
532
- - \u5165\u529B\u3055\u308C\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u6B63\u3057\u3044\u304B
533
- 5. \`${requestToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u30E9\u30D9\u30EB\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B:
534
- - \`method\`: \`"GET"\`
535
- - \`path\`: \`"/me/labels"\`
421
+ - \`subject\`: \`<email>\`
422
+ - \`scopes\`: \`${READONLY_SCOPES}\`
423
+
424
+ 3. \u5931\u6557\u3057\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u3042\u308C\u3070\u3001\u30A8\u30E9\u30FC\u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`serviceAccountEmail\` \u30D5\u30A3\u30FC\u30EB\u30C9\u304B\u3089\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u308A\u51FA\u3057\u3001\`askUserQuestion\` \u3067\u6B21\u306E\u9078\u629E\u80A2\u3092\u63D0\u793A\u3059\u308B\u3002\`question\` \u306B\u306F\u6B21\u306E\u6848\u5185\u6587\u3092\u542B\u3081\u308B: \u300C\u6B21\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F: {\u5931\u6557\u30A2\u30C9\u30EC\u30B9\u4E00\u89A7}\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8 \`<serviceAccountEmail>\` \u306E Domain-wide Delegation \u304C Workspace \u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u3067\u627F\u8A8D\u3055\u308C\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF08[\u8A2D\u5B9A\u30AC\u30A4\u30C9](https://support.google.com/a/answer/162106)\uFF09\u300D\u3002
425
+ - \`options\`: \`[{ label: "\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u3092\u627F\u8A8D\u3057\u305F\u306E\u3067\u30EA\u30C8\u30E9\u30A4", value: "retry" }, { label: "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u76F4\u3059", value: "restart" }]\`
426
+ - \u300C\u30EA\u30C8\u30E9\u30A4\u300D: \u76F4\u524D\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u30EA\u30B9\u30C8\u3067\u30B9\u30C6\u30C3\u30D7 2 \u3092\u518D\u5B9F\u884C
427
+ - \u300C\u5165\u529B\u3057\u76F4\u3059\u300D: \u30B9\u30C6\u30C3\u30D7 1 \u304B\u3089\u518D\u5B9F\u884C
428
+
429
+ 4. \u5168\u30A2\u30C9\u30EC\u30B9\u304C\u6210\u529F\u3057\u305F\u3089 \`finalizeSetup\` \u3092\u547C\u3076\u3002\u691C\u8A3C\u6E08\u307F\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\uFF08\u30B9\u30C6\u30C3\u30D7 2 \u3067 \`subject\` \u3068\u3057\u3066\u4F7F\u3063\u305F\u5404 \`<email>\`\uFF09\u3092\u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30B9\u30B3\u30FC\u30D7\u60C5\u5831\u3068\u3057\u3066\u8A18\u9332\u3059\u308B\u3002
536
430
 
537
431
  #### \u5236\u7D04
538
- - **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u672C\u6587\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u53D6\u5F97\u3068\u30E9\u30D9\u30EB\u4E00\u89A7\u53D6\u5F97\u306E\u307F
539
- - \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`,
540
- en: `Follow these steps to set up the Gmail (Service Account) connection. Only the service account JSON is provided at connection creation time \u2014 the delegated user email is collected during this setup flow.
432
+ - \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u672C\u6587\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068\u3002\u8A31\u53EF\u3055\u308C\u3066\u3044\u308B\u306E\u306F\u30B9\u30C6\u30C3\u30D7 2 \u306E \`/me/profile\` \u78BA\u8A8D\u306E\u307F
433
+ - \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`,
434
+ en: `Set up the Gmail (Service Account) connection. Ask the user which Workspace users to access, verify each via Domain-wide Delegation, and record them in Project Knowledge.
541
435
 
542
- 1. Call \`askUserQuestion\` to ask the user for the Google Workspace user email the service account will impersonate via Domain-wide Delegation:
436
+ 1. Call \`askUserQuestion\` to collect target emails:
543
437
  - \`type\`: \`"freeText"\`
544
- - \`question\`: "Please enter the email address of the Google Workspace user whose Gmail mailbox you want to access"
545
- - \`placeholder\`: \`"user@example.com"\`
546
- 2. Save the email via \`updateConnectionParameters\`:
547
- - \`parameterSlug\`: \`"delegated-user-email"\`
548
- - \`options\`: \`[{ value: <entered email>, label: <same value> }]\` (a single option is auto-selected)
549
- 3. Call \`${requestToolName}\` to get the user's profile:
438
+ - \`question\`: "Enter the Google Workspace user email(s) whose Gmail mailbox you want to access (comma-separated for multiple)"
439
+ - \`placeholder\`: \`"alice@example.com, bob@example.com"\`
440
+
441
+ 2. Extract individual emails from the response. For each \`<email>\`, verify Domain-wide Delegation access by calling \`${requestWithDelegationToolName}\`:
550
442
  - \`method\`: \`"GET"\`
551
443
  - \`path\`: \`"/me/profile"\`
552
- 4. If an error is returned, ask the user to verify:
553
- - Domain-wide delegation is enabled for the service account
554
- - Gmail API scope is authorized in Google Workspace admin console
555
- - The entered email address is correct
556
- 5. Call \`${requestToolName}\` to get the label list:
557
- - \`method\`: \`"GET"\`
558
- - \`path\`: \`"/me/labels"\`
444
+ - \`subject\`: \`<email>\`
445
+ - \`scopes\`: \`${READONLY_SCOPES}\`
446
+
447
+ 3. For any failed email, take \`serviceAccountEmail\` from the error response and call \`askUserQuestion\`. Include this guidance in \`question\`: "Could not access Gmail for {failed emails}. Verify Domain-wide Delegation for service account \`<serviceAccountEmail>\` in the Workspace admin console ([setup guide](https://support.google.com/a/answer/162106))".
448
+ - \`options\`: \`[{ label: "Authorized Domain-wide Delegation \u2014 retry", value: "retry" }, { label: "Re-enter the email addresses", value: "restart" }]\`
449
+ - On "retry" \u2192 re-run step 2 with the previously entered email list
450
+ - On "Re-enter" \u2192 re-run step 1
451
+
452
+ 4. Once every email succeeds, call \`finalizeSetup\`. Record the verified email addresses (the \`<email>\` values used as \`subject\` in step 2) as this connection's scope info.
559
453
 
560
454
  #### Constraints
561
- - **Do NOT read message bodies during setup**. Only the profile and label list requests specified above are allowed
562
- - Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
455
+ - Do NOT read message bodies during setup. Only the \`/me/profile\` verification is permitted
456
+ - Write at most 1 sentence between tool calls`
563
457
  },
564
458
  dataOverviewInstructions: {
565
- en: `1. Call gmail-service-account_request with GET /me/labels to list all labels
566
- 2. Call gmail-service-account_request with GET /me/messages?maxResults=5 to get recent message IDs
567
- 3. Call gmail-service-account_request with GET /me/messages/{id}?format=metadata for each message to see subjects and senders`,
568
- ja: `1. gmail-service-account_request \u3067 GET /me/labels \u3092\u547C\u3073\u51FA\u3057\u3001\u5168\u30E9\u30D9\u30EB\u4E00\u89A7\u3092\u53D6\u5F97
569
- 2. gmail-service-account_request \u3067 GET /me/messages?maxResults=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u6700\u65B0\u30E1\u30C3\u30BB\u30FC\u30B8ID\u3092\u53D6\u5F97
570
- 3. \u5404\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3064\u3044\u3066 gmail-service-account_request \u3067 GET /me/messages/{id}?format=metadata \u3092\u547C\u3073\u51FA\u3057\u3001\u4EF6\u540D\u3068\u9001\u4FE1\u8005\u3092\u78BA\u8A8D`
459
+ en: `Pick ONE target user and use that user's email as \`subject\` for every call below. Pass \`scopes: ${READONLY_SCOPES}\` every time.
460
+
461
+ 1. \`method=GET\`, \`path=/me/labels\` to list labels.
462
+ 2. \`method=GET\`, \`path=/me/messages?maxResults=5\` to fetch recent message IDs.
463
+ 3. For each message id, \`method=GET\`, \`path=/me/messages/{id}?format=metadata\`.`,
464
+ ja: `\u4EE3\u7406\u5BFE\u8C61\u306E\u30E6\u30FC\u30B6\u30FC\u3092 1 \u4EBA\u9078\u3073\u3001\u4EE5\u4E0B\u306E\u30B9\u30C6\u30C3\u30D7\u3067 \`subject\` \u5F15\u6570\u3068\u3057\u3066\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002\`scopes\` \u306F\u6BCE\u56DE \`${READONLY_SCOPES}\` \u3092\u6E21\u3057\u307E\u3059\u3002
465
+
466
+ 1. \`method=GET\`\u3001\`path=/me/labels\` \u3067\u30E9\u30D9\u30EB\u4E00\u89A7\u3092\u53D6\u5F97
467
+ 2. \`method=GET\`\u3001\`path=/me/messages?maxResults=5\` \u3067\u6700\u8FD1\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 ID \u3092\u53D6\u5F97
468
+ 3. \u5404\u30E1\u30C3\u30BB\u30FC\u30B8 ID \u306B\u3064\u3044\u3066 \`method=GET\`\u3001\`path=/me/messages/{id}?format=metadata\``
571
469
  }
572
470
  });
573
471
 
574
472
  // ../connectors/src/connectors/gmail/index.ts
575
- var tools = { request: requestTool };
473
+ var tools = { request_with_delegation: requestWithDelegationTool };
576
474
  var gmailConnector = new ConnectorPlugin({
577
475
  slug: "gmail",
578
476
  authType: AUTH_TYPES.SERVICE_ACCOUNT,
579
477
  name: "Gmail",
580
- description: "Connect to Gmail for email data access using a service account with domain-wide delegation. Read-only access to messages, threads, and labels.",
478
+ description: "Connect to Gmail for email data access using a service account with domain-wide delegation. Currently read-only (messages, threads, labels).",
581
479
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4V3rfaSc1ksFIt2eHBNIwJ/7f3be41a154a6d96dcf229ed0e5858c9/Gmail_icon__2020_.svg.png",
582
480
  parameters,
583
481
  releaseFlag: { dev1: true, dev2: true, prod: true },
482
+ categories: ["productivity"],
584
483
  onboarding: gmailOnboarding,
585
484
  systemPrompt: {
586
485
  en: `### Tools
587
486
 
588
- - \`gmail-service-account_request\`: The only way to call the Gmail API (read-only). Use it to list messages, get message details, list labels, list threads, and get user profile. Authentication is handled automatically using a service account with domain-wide delegation.
487
+ - \`gmail-service-account_request_with_delegation\`: Call the Gmail API on behalf of the specified Workspace user via Domain-wide Delegation. Pass \`subject\` as the target user's email; the token will be issued as that user. Always pass \`scopes\`.
488
+
489
+ ### OAuth Scopes (pass as \`scopes\` argument)
490
+
491
+ This connector is currently read-only. Pass:
492
+
493
+ - \`https://www.googleapis.com/auth/gmail.readonly\` \u2014 read-only access (profile, labels, messages, threads)
494
+
495
+ The Workspace admin must have authorized this scope for the service account in the Domain-wide Delegation settings, otherwise token issuance will fail with \`unauthorized_client\`.
496
+
497
+ Per-endpoint scope reference: https://developers.google.com/gmail/api/auth/scopes
589
498
 
590
499
  ### Gmail API Reference
591
500
 
592
501
  #### Available Endpoints
593
- - GET \`/me/profile\` \u2014 Get the delegated user's profile (email address, total messages/threads)
502
+ - GET \`/me/profile\` \u2014 Get the impersonated user's profile (email address, total messages/threads)
594
503
  - GET \`/me/labels\` \u2014 List all labels in the mailbox
595
504
  - GET \`/me/labels/{id}\` \u2014 Get details for a specific label
596
505
  - GET \`/me/messages\` \u2014 List messages (returns IDs only; use format param on individual messages)
@@ -615,7 +524,7 @@ var gmailConnector = new ConnectorPlugin({
615
524
  - \`raw\` \u2014 Full RFC 2822 formatted message in base64url
616
525
 
617
526
  #### Tips
618
- - Always use \`/me\` as the userId \u2014 it refers to the delegated user
527
+ - Always use \`/me\` as the userId in the path \u2014 it refers to the user you passed as \`subject\`
619
528
  - List endpoints return only IDs; fetch individual resources for details
620
529
  - Use \`format=metadata\` to efficiently get subject/sender without full body
621
530
  - Message body content is base64url encoded in \`payload.body.data\` or nested \`payload.parts[].body.data\`
@@ -626,6 +535,12 @@ var gmailConnector = new ConnectorPlugin({
626
535
 
627
536
  The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables.
628
537
 
538
+ SDK methods (client created via \`connection(connectionId)\`):
539
+
540
+ - \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 call the Gmail API as the impersonated Workspace user via Domain-wide Delegation. Pass the minimum scopes required by the endpoint.
541
+
542
+ The method returns a standard \`Response\`. Read the body with \`.json()\`. Same path conventions as the tool.
543
+
629
544
  #### Example
630
545
 
631
546
  \`\`\`ts
@@ -633,37 +548,51 @@ import { connection } from "@squadbase/vite-server/connectors/gmail";
633
548
 
634
549
  const gmail = connection("<connectionId>");
635
550
 
636
- // Get user profile
637
- const profile = await gmail.getProfile();
551
+ // The user to impersonate.
552
+ const subject = "alice@example.com";
553
+ const READ = ["https://www.googleapis.com/auth/gmail.readonly"];
554
+
555
+ const profileRes = await gmail.requestWithDelegation("/me/profile", {
556
+ subject,
557
+ scopes: READ,
558
+ });
559
+ const profile = await profileRes.json();
638
560
  console.log(profile.emailAddress, profile.messagesTotal);
639
561
 
640
- // List recent messages
641
- const messages = await gmail.listMessages({ maxResults: 10 });
642
- for (const msg of messages.messages) {
643
- const detail = await gmail.getMessage(msg.id, "metadata");
644
- const subject = detail.payload.headers.find(h => h.name === "Subject")?.value;
645
- console.log(subject, detail.snippet);
562
+ const messagesRes = await gmail.requestWithDelegation(
563
+ "/me/messages?maxResults=10",
564
+ { subject, scopes: READ },
565
+ );
566
+ const messages = await messagesRes.json();
567
+
568
+ for (const msg of messages.messages ?? []) {
569
+ const detailRes = await gmail.requestWithDelegation(
570
+ \`/me/messages/\${msg.id}?format=metadata\`,
571
+ { subject, scopes: READ },
572
+ );
573
+ const detail = await detailRes.json();
574
+ const subjectHeader = detail.payload.headers.find(h => h.name === "Subject")?.value;
575
+ console.log(subjectHeader, detail.snippet);
646
576
  }
577
+ \`\`\``,
578
+ ja: `### \u30C4\u30FC\u30EB
647
579
 
648
- // Search messages
649
- const results = await gmail.listMessages({ q: "from:boss@company.com is:unread" });
580
+ - \`gmail-service-account_request_with_delegation\`: \u6307\u5B9A\u3055\u308C\u305F Workspace \u30E6\u30FC\u30B6\u30FC\u306B\u4EE3\u308F\u3063\u3066 Domain-wide Delegation \u7D4C\u7531\u3067 Gmail API \u3092\u547C\u3073\u51FA\u3057\u307E\u3059\u3002\u4EE3\u7406\u5BFE\u8C61\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 \`subject\` \u3068\u3057\u3066\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30C8\u30FC\u30AF\u30F3\u306F\u305D\u306E\u30E6\u30FC\u30B6\u30FC\u3068\u3057\u3066\u767A\u884C\u3055\u308C\u307E\u3059\u3002\`scopes\` \u3082\u6BCE\u56DE\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002
650
581
 
651
- // List labels
652
- const labels = await gmail.listLabels();
653
- labels.labels.forEach(l => console.log(l.name, l.messagesTotal));
582
+ ### OAuth \u30B9\u30B3\u30FC\u30D7 (\`scopes\` \u5F15\u6570\u3067\u6E21\u3059)
654
583
 
655
- // Get a thread
656
- const thread = await gmail.getThread("<threadId>");
657
- thread.messages.forEach(m => console.log(m.snippet));
658
- \`\`\``,
659
- ja: `### \u30C4\u30FC\u30EB
584
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u30FC\u306F\u73FE\u72B6\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u3059\u3002\u6B21\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044:
660
585
 
661
- - \`gmail-service-account_request\`: Gmail API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\uFF08\u8AAD\u307F\u53D6\u308A\u5C02\u7528\uFF09\u3002\u30E1\u30C3\u30BB\u30FC\u30B8\u4E00\u89A7\u306E\u53D6\u5F97\u3001\u30E1\u30C3\u30BB\u30FC\u30B8\u8A73\u7D30\u306E\u53D6\u5F97\u3001\u30E9\u30D9\u30EB\u4E00\u89A7\u3001\u30B9\u30EC\u30C3\u30C9\u4E00\u89A7\u3001\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u306E\u53D6\u5F97\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u3092\u4F7F\u7528\u3057\u3066\u8A8D\u8A3C\u306F\u81EA\u52D5\u7684\u306B\u51E6\u7406\u3055\u308C\u307E\u3059\u3002
586
+ - \`https://www.googleapis.com/auth/gmail.readonly\` \u2014 \u8AAD\u307F\u53D6\u308A\uFF08\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u3001\u30E9\u30D9\u30EB\u3001\u30E1\u30C3\u30BB\u30FC\u30B8\u3001\u30B9\u30EC\u30C3\u30C9\uFF09
587
+
588
+ \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
589
+
590
+ \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u5225\u306E\u6B63\u78BA\u306A scope \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9: https://developers.google.com/gmail/api/auth/scopes
662
591
 
663
592
  ### Gmail API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
664
593
 
665
594
  #### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
666
- - GET \`/me/profile\` \u2014 \u59D4\u4EFB\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u3092\u53D6\u5F97\uFF08\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3001\u30E1\u30C3\u30BB\u30FC\u30B8/\u30B9\u30EC\u30C3\u30C9\u7DCF\u6570\uFF09
595
+ - GET \`/me/profile\` \u2014 \u4EE3\u7406\u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u3092\u53D6\u5F97\uFF08\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3001\u30E1\u30C3\u30BB\u30FC\u30B8/\u30B9\u30EC\u30C3\u30C9\u7DCF\u6570\uFF09
667
596
  - GET \`/me/labels\` \u2014 \u30E1\u30FC\u30EB\u30DC\u30C3\u30AF\u30B9\u306E\u5168\u30E9\u30D9\u30EB\u3092\u4E00\u89A7
668
597
  - GET \`/me/labels/{id}\` \u2014 \u7279\u5B9A\u30E9\u30D9\u30EB\u306E\u8A73\u7D30\u3092\u53D6\u5F97
669
598
  - GET \`/me/messages\` \u2014 \u30E1\u30C3\u30BB\u30FC\u30B8\u4E00\u89A7\uFF08ID\u306E\u307F\u8FD4\u5374\u3002\u500B\u5225\u30E1\u30C3\u30BB\u30FC\u30B8\u3067format\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4F7F\u7528\uFF09
@@ -688,7 +617,7 @@ thread.messages.forEach(m => console.log(m.snippet));
688
617
  - \`raw\` \u2014 base64url\u30A8\u30F3\u30B3\u30FC\u30C9\u3055\u308C\u305F\u5B8C\u5168\u306ARFC 2822\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u30E1\u30C3\u30BB\u30FC\u30B8
689
618
 
690
619
  #### \u30D2\u30F3\u30C8
691
- - userId\u306B\u306F\u5E38\u306B \`/me\` \u3092\u4F7F\u7528 \u2014 \u59D4\u4EFB\u30E6\u30FC\u30B6\u30FC\u3092\u6307\u3057\u307E\u3059
620
+ - \u30D1\u30B9\u306E userId \u306B\u306F\u5E38\u306B \`/me\` \u3092\u4F7F\u7528 \u2014 \`subject\` \u306B\u6E21\u3057\u305F\u30E6\u30FC\u30B6\u30FC\u3092\u6307\u3057\u307E\u3059
692
621
  - \u4E00\u89A7\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306FID\u306E\u307F\u8FD4\u5374\u3057\u307E\u3059\u3002\u8A73\u7D30\u306F\u500B\u5225\u30EA\u30BD\u30FC\u30B9\u3092\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044
693
622
  - \u4EF6\u540D/\u9001\u4FE1\u8005\u3092\u52B9\u7387\u7684\u306B\u53D6\u5F97\u3059\u308B\u306B\u306F \`format=metadata\` \u3092\u4F7F\u7528\u3057\u307E\u3059
694
623
  - \u30E1\u30C3\u30BB\u30FC\u30B8\u672C\u6587\u306F \`payload.body.data\` \u307E\u305F\u306F\u30CD\u30B9\u30C8\u3055\u308C\u305F \`payload.parts[].body.data\` \u306Bbase64url\u30A8\u30F3\u30B3\u30FC\u30C9\u3067\u683C\u7D0D\u3055\u308C\u3066\u3044\u307E\u3059
@@ -699,6 +628,12 @@ thread.messages.forEach(m => console.log(m.snippet));
699
628
 
700
629
  \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
701
630
 
631
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
632
+
633
+ - \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 Domain-wide Delegation \u3067\u6307\u5B9A Workspace \u30E6\u30FC\u30B6\u30FC\u306B\u4EE3\u308F\u3063\u3066 Gmail API \u3092\u547C\u3076\u3002\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306B\u5FC5\u8981\u306A\u6700\u5C0F scope \u3092\u6E21\u3059\u3002
634
+
635
+ \u30E1\u30BD\u30C3\u30C9\u306F\u6A19\u6E96\u306E \`Response\` \u3092\u8FD4\u3057\u307E\u3059\u3002\`response.json()\` \u3067\u30DC\u30C7\u30A3\u3092\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D1\u30B9\u306E\u66F8\u304D\u65B9\u306F\u30C4\u30FC\u30EB\u3068\u540C\u3058\u3002
636
+
702
637
  #### Example
703
638
 
704
639
  \`\`\`ts
@@ -706,86 +641,35 @@ import { connection } from "@squadbase/vite-server/connectors/gmail";
706
641
 
707
642
  const gmail = connection("<connectionId>");
708
643
 
709
- // Get user profile
710
- const profile = await gmail.getProfile();
711
- console.log(profile.emailAddress, profile.messagesTotal);
644
+ // \u4EE3\u7406\u5BFE\u8C61\u30E6\u30FC\u30B6\u30FC
645
+ const subject = "alice@example.com";
646
+ const READ = ["https://www.googleapis.com/auth/gmail.readonly"];
712
647
 
713
- // List recent messages
714
- const messages = await gmail.listMessages({ maxResults: 10 });
715
- for (const msg of messages.messages) {
716
- const detail = await gmail.getMessage(msg.id, "metadata");
717
- const subject = detail.payload.headers.find(h => h.name === "Subject")?.value;
718
- console.log(subject, detail.snippet);
719
- }
720
-
721
- // Search messages
722
- const results = await gmail.listMessages({ q: "from:boss@company.com is:unread" });
648
+ const profileRes = await gmail.requestWithDelegation("/me/profile", {
649
+ subject,
650
+ scopes: READ,
651
+ });
652
+ const profile = await profileRes.json();
653
+ console.log(profile.emailAddress, profile.messagesTotal);
723
654
 
724
- // List labels
725
- const labels = await gmail.listLabels();
726
- labels.labels.forEach(l => console.log(l.name, l.messagesTotal));
655
+ const messagesRes = await gmail.requestWithDelegation(
656
+ "/me/messages?maxResults=10",
657
+ { subject, scopes: READ },
658
+ );
659
+ const messages = await messagesRes.json();
727
660
 
728
- // Get a thread
729
- const thread = await gmail.getThread("<threadId>");
730
- thread.messages.forEach(m => console.log(m.snippet));
661
+ for (const msg of messages.messages ?? []) {
662
+ const detailRes = await gmail.requestWithDelegation(
663
+ \`/me/messages/\${msg.id}?format=metadata\`,
664
+ { subject, scopes: READ },
665
+ );
666
+ const detail = await detailRes.json();
667
+ const subjectHeader = detail.payload.headers.find(h => h.name === "Subject")?.value;
668
+ console.log(subjectHeader, detail.snippet);
669
+ }
731
670
  \`\`\``
732
671
  },
733
- tools,
734
- async checkConnection(params, _config) {
735
- const { GoogleAuth } = await import("google-auth-library");
736
- const credentials = JSON.parse(
737
- Buffer.from(
738
- params[parameters.serviceAccountKeyJsonBase64.slug],
739
- "base64"
740
- ).toString("utf-8")
741
- );
742
- const delegatedUserEmail = params[delegatedUserEmailParameter.slug];
743
- if (!delegatedUserEmail) {
744
- if (!credentials.client_email || !credentials.private_key) {
745
- return {
746
- success: false,
747
- error: "Service account JSON must contain client_email and private_key"
748
- };
749
- }
750
- return { success: true };
751
- }
752
- const auth = new GoogleAuth({
753
- credentials,
754
- scopes: ["https://www.googleapis.com/auth/gmail.readonly"],
755
- clientOptions: {
756
- subject: delegatedUserEmail
757
- }
758
- });
759
- try {
760
- const token = await auth.getAccessToken();
761
- if (!token) {
762
- return {
763
- success: false,
764
- error: "Failed to obtain access token"
765
- };
766
- }
767
- const res = await fetch(
768
- "https://gmail.googleapis.com/gmail/v1/users/me/profile",
769
- {
770
- method: "GET",
771
- headers: { Authorization: `Bearer ${token}` }
772
- }
773
- );
774
- if (!res.ok) {
775
- const errorText = await res.text().catch(() => res.statusText);
776
- return {
777
- success: false,
778
- error: `Gmail API failed: HTTP ${res.status} ${errorText}`
779
- };
780
- }
781
- return { success: true };
782
- } catch (error) {
783
- return {
784
- success: false,
785
- error: error instanceof Error ? error.message : String(error)
786
- };
787
- }
788
- }
672
+ tools
789
673
  });
790
674
 
791
675
  // src/connectors/create-connector-sdk.ts