@squadbase/vite-server 0.1.3-dev.15 → 0.1.3-dev.16

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 (59) hide show
  1. package/dist/cli/index.js +2105 -2700
  2. package/dist/connectors/airtable-oauth.js +16 -5
  3. package/dist/connectors/airtable.js +16 -5
  4. package/dist/connectors/amplitude.js +16 -5
  5. package/dist/connectors/anthropic.js +16 -5
  6. package/dist/connectors/asana.js +16 -5
  7. package/dist/connectors/attio.js +16 -5
  8. package/dist/connectors/backlog-api-key.js +16 -5
  9. package/dist/connectors/customerio.js +16 -5
  10. package/dist/connectors/dbt.js +16 -5
  11. package/dist/connectors/gamma.js +16 -5
  12. package/dist/connectors/gemini.js +16 -5
  13. package/dist/connectors/gmail-oauth.js +16 -5
  14. package/dist/connectors/gmail.js +68 -34
  15. package/dist/connectors/google-ads.js +16 -5
  16. package/dist/connectors/google-analytics-oauth.js +16 -5
  17. package/dist/connectors/google-analytics.js +16 -5
  18. package/dist/connectors/google-calendar-oauth.js +16 -5
  19. package/dist/connectors/google-calendar.js +71 -48
  20. package/dist/connectors/{google-drive-oauth.d.ts → google-docs.d.ts} +1 -1
  21. package/dist/connectors/google-docs.js +585 -0
  22. package/dist/connectors/google-drive.d.ts +1 -1
  23. package/dist/connectors/google-drive.js +391 -327
  24. package/dist/connectors/google-sheets.d.ts +1 -1
  25. package/dist/connectors/google-sheets.js +210 -280
  26. package/dist/connectors/google-slides.d.ts +1 -1
  27. package/dist/connectors/google-slides.js +198 -335
  28. package/dist/connectors/grafana.js +16 -5
  29. package/dist/connectors/hubspot-oauth.js +16 -5
  30. package/dist/connectors/hubspot.js +16 -5
  31. package/dist/connectors/intercom-oauth.js +16 -5
  32. package/dist/connectors/intercom.js +16 -5
  33. package/dist/connectors/jira-api-key.js +16 -5
  34. package/dist/connectors/kintone-api-token.js +133 -59
  35. package/dist/connectors/kintone.js +16 -5
  36. package/dist/connectors/linkedin-ads.js +16 -5
  37. package/dist/connectors/mailchimp-oauth.js +16 -5
  38. package/dist/connectors/mailchimp.js +16 -5
  39. package/dist/connectors/mixpanel.js +16 -5
  40. package/dist/connectors/notion-oauth.js +16 -5
  41. package/dist/connectors/notion.js +16 -5
  42. package/dist/connectors/openai.js +16 -5
  43. package/dist/connectors/sentry.js +16 -5
  44. package/dist/connectors/shopify-oauth.js +16 -5
  45. package/dist/connectors/shopify.js +16 -5
  46. package/dist/connectors/stripe-api-key.js +16 -5
  47. package/dist/connectors/stripe-oauth.js +16 -5
  48. package/dist/connectors/wix-store.js +16 -5
  49. package/dist/connectors/zendesk-oauth.js +16 -5
  50. package/dist/connectors/zendesk.js +16 -5
  51. package/dist/index.js +2100 -2695
  52. package/dist/main.js +2100 -2695
  53. package/dist/vite-plugin.js +2100 -2695
  54. package/package.json +7 -15
  55. package/dist/connectors/google-drive-oauth.js +0 -879
  56. package/dist/connectors/google-sheets-oauth.d.ts +0 -5
  57. package/dist/connectors/google-sheets-oauth.js +0 -821
  58. package/dist/connectors/google-slides-oauth.d.ts +0 -5
  59. package/dist/connectors/google-slides-oauth.js +0 -742
@@ -1,287 +1,145 @@
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-drive/sdk/index.ts
46
- import * as crypto from "crypto";
47
-
48
- // ../connectors/src/connectors/google-drive/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 Drive.",
54
- envVarBaseKey: "GOOGLE_DRIVE_SERVICE_ACCOUNT_JSON_BASE64",
55
- type: "base64EncodedJson",
56
- secret: true,
57
- required: true
58
- }),
59
- folderId: new ParameterDefinition({
60
- slug: "folder-id",
61
- name: "Google Drive Folder ID",
62
- description: "The ID of a default Google Drive folder to scope operations to (e.g., from the folder URL: https://drive.google.com/drive/folders/{folderId}). Optional \u2014 if not set, operations target the root of My Drive.",
63
- envVarBaseKey: "GOOGLE_DRIVE_FOLDER_ID",
64
- type: "text",
65
- secret: false,
66
- required: false
67
- })
68
- };
69
-
70
- // ../connectors/src/connectors/google-drive-oauth/utils.ts
71
- var FOLDER_URL_PATTERN = /drive\.google\.com\/drive\/folders\/([a-zA-Z0-9_-]+)/;
72
- function extractFolderId(urlOrId) {
73
- const trimmed = urlOrId.trim();
74
- const match = trimmed.match(FOLDER_URL_PATTERN);
75
- if (match) {
76
- return match[1];
77
- }
78
- return trimmed;
79
- }
80
-
81
1
  // ../connectors/src/connectors/google-drive/sdk/index.ts
82
- var TOKEN_URL = "https://oauth2.googleapis.com/token";
83
2
  var BASE_URL = "https://www.googleapis.com/drive/v3";
84
- var SCOPE = "https://www.googleapis.com/auth/drive";
85
- function base64url(input) {
86
- const buf = typeof input === "string" ? Buffer.from(input) : input;
87
- return buf.toString("base64url");
88
- }
89
- function buildJwt(clientEmail, privateKey, nowSec) {
90
- const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
91
- const payload = base64url(
92
- JSON.stringify({
93
- iss: clientEmail,
94
- scope: SCOPE,
95
- aud: TOKEN_URL,
96
- iat: nowSec,
97
- exp: nowSec + 3600
98
- })
99
- );
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
3
  var DEFAULT_FILE_FIELDS = "id,name,mimeType,parents,webViewLink,webContentLink,createdTime,modifiedTime,size,starred,trashed,shared,owners";
108
- function createClient(params) {
109
- const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
110
- const folderIdRaw = params[parameters.folderId.slug];
111
- const defaultFolderId = folderIdRaw ? extractFolderId(folderIdRaw) : void 0;
112
- if (!serviceAccountKeyJsonBase64) {
113
- throw new Error(
114
- `google-drive: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
115
- );
4
+ function createClient(_params, fetchFn = fetch) {
5
+ function request(path2, init) {
6
+ const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
7
+ return fetchFn(url, init);
116
8
  }
117
- let serviceAccountKey;
118
- try {
119
- const decoded = Buffer.from(
120
- serviceAccountKeyJsonBase64,
121
- "base64"
122
- ).toString("utf-8");
123
- serviceAccountKey = JSON.parse(decoded);
124
- } catch {
125
- throw new Error(
126
- "google-drive: failed to decode service account key JSON from base64"
127
- );
9
+ async function listFiles(options) {
10
+ const searchParams = new URLSearchParams();
11
+ const query = options?.query ?? "";
12
+ if (query) searchParams.set("q", query);
13
+ if (options?.pageSize) searchParams.set("pageSize", String(options.pageSize));
14
+ if (options?.pageToken) searchParams.set("pageToken", options.pageToken);
15
+ if (options?.orderBy) searchParams.set("orderBy", options.orderBy);
16
+ searchParams.set("fields", options?.fields ?? `nextPageToken,files(${DEFAULT_FILE_FIELDS})`);
17
+ const url = `${BASE_URL}/files?${searchParams.toString()}`;
18
+ const response = await fetchFn(url);
19
+ if (!response.ok) {
20
+ const body = await response.text();
21
+ throw new Error(
22
+ `google-drive: listFiles failed (${response.status}): ${body}`
23
+ );
24
+ }
25
+ return await response.json();
128
26
  }
129
- if (!serviceAccountKey.client_email || !serviceAccountKey.private_key) {
130
- throw new Error(
131
- "google-drive: service account key JSON must contain client_email and private_key"
132
- );
27
+ async function getFile(fileId, fields) {
28
+ const url = `${BASE_URL}/files/${fileId}?fields=${fields ?? DEFAULT_FILE_FIELDS}`;
29
+ const response = await fetchFn(url);
30
+ if (!response.ok) {
31
+ const body = await response.text();
32
+ throw new Error(
33
+ `google-drive: getFile failed (${response.status}): ${body}`
34
+ );
35
+ }
36
+ return await response.json();
133
37
  }
134
- let cachedToken = null;
135
- let tokenExpiresAt = 0;
136
- async function getAccessToken() {
137
- const nowSec = Math.floor(Date.now() / 1e3);
138
- if (cachedToken && nowSec < tokenExpiresAt - 60) {
139
- return cachedToken;
38
+ async function createFile(options) {
39
+ const metadata = { name: options.name };
40
+ if (options.mimeType) metadata.mimeType = options.mimeType;
41
+ if (options.description) metadata.description = options.description;
42
+ if (options.parents) {
43
+ metadata.parents = options.parents;
140
44
  }
141
- const jwt = buildJwt(
142
- serviceAccountKey.client_email,
143
- serviceAccountKey.private_key,
144
- nowSec
145
- );
146
- const response = await fetch(TOKEN_URL, {
45
+ const url = `${BASE_URL}/files?fields=${DEFAULT_FILE_FIELDS}`;
46
+ const response = await fetchFn(url, {
147
47
  method: "POST",
148
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
149
- body: new URLSearchParams({
150
- grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
151
- assertion: jwt
152
- })
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify(metadata)
153
50
  });
154
51
  if (!response.ok) {
155
- const text = await response.text();
52
+ const body = await response.text();
156
53
  throw new Error(
157
- `google-drive: token exchange failed (${response.status}): ${text}`
54
+ `google-drive: createFile failed (${response.status}): ${body}`
158
55
  );
159
56
  }
160
- const data = await response.json();
161
- cachedToken = data.access_token;
162
- tokenExpiresAt = nowSec + data.expires_in;
163
- return cachedToken;
57
+ return await response.json();
164
58
  }
165
- async function authenticatedFetch(url, init) {
166
- const accessToken = await getAccessToken();
167
- const headers = new Headers(init?.headers);
168
- headers.set("Authorization", `Bearer ${accessToken}`);
169
- if (!headers.has("Content-Type")) {
170
- headers.set("Content-Type", "application/json");
59
+ async function updateFile(fileId, metadata, addParents, removeParents) {
60
+ const searchParams = new URLSearchParams();
61
+ searchParams.set("fields", DEFAULT_FILE_FIELDS);
62
+ if (addParents) searchParams.set("addParents", addParents);
63
+ if (removeParents) searchParams.set("removeParents", removeParents);
64
+ const url = `${BASE_URL}/files/${fileId}?${searchParams.toString()}`;
65
+ const response = await fetchFn(url, {
66
+ method: "PATCH",
67
+ headers: { "Content-Type": "application/json" },
68
+ body: JSON.stringify(metadata)
69
+ });
70
+ if (!response.ok) {
71
+ const body = await response.text();
72
+ throw new Error(
73
+ `google-drive: updateFile failed (${response.status}): ${body}`
74
+ );
171
75
  }
172
- return fetch(url, { ...init, headers });
76
+ return await response.json();
173
77
  }
174
- return {
175
- async request(path2, init) {
176
- const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
177
- return authenticatedFetch(url, init);
178
- },
179
- async listFiles(options) {
180
- const searchParams = new URLSearchParams();
181
- let query = options?.query ?? "";
182
- if (defaultFolderId && !query.includes("in parents")) {
183
- const folderClause = `'${defaultFolderId}' in parents`;
184
- query = query ? `${folderClause} and (${query})` : folderClause;
185
- }
186
- if (query) searchParams.set("q", query);
187
- if (options?.pageSize) searchParams.set("pageSize", String(options.pageSize));
188
- if (options?.pageToken) searchParams.set("pageToken", options.pageToken);
189
- if (options?.orderBy) searchParams.set("orderBy", options.orderBy);
190
- searchParams.set("fields", options?.fields ?? `nextPageToken,files(${DEFAULT_FILE_FIELDS})`);
191
- const response = await authenticatedFetch(`${BASE_URL}/files?${searchParams.toString()}`);
192
- if (!response.ok) {
193
- const body = await response.text();
194
- throw new Error(`google-drive: listFiles failed (${response.status}): ${body}`);
195
- }
196
- return await response.json();
197
- },
198
- async getFile(fileId, fields) {
199
- const response = await authenticatedFetch(
200
- `${BASE_URL}/files/${fileId}?fields=${fields ?? DEFAULT_FILE_FIELDS}`
78
+ async function copyFile(fileId, name, parents) {
79
+ const metadata = {};
80
+ if (name) metadata.name = name;
81
+ if (parents) metadata.parents = parents;
82
+ const url = `${BASE_URL}/files/${fileId}/copy?fields=${DEFAULT_FILE_FIELDS}`;
83
+ const response = await fetchFn(url, {
84
+ method: "POST",
85
+ headers: { "Content-Type": "application/json" },
86
+ body: JSON.stringify(metadata)
87
+ });
88
+ if (!response.ok) {
89
+ const body = await response.text();
90
+ throw new Error(
91
+ `google-drive: copyFile failed (${response.status}): ${body}`
201
92
  );
202
- if (!response.ok) {
203
- const body = await response.text();
204
- throw new Error(`google-drive: getFile failed (${response.status}): ${body}`);
205
- }
206
- return await response.json();
207
- },
208
- async createFile(options) {
209
- const metadata = { name: options.name };
210
- if (options.mimeType) metadata.mimeType = options.mimeType;
211
- if (options.description) metadata.description = options.description;
212
- if (options.parents) {
213
- metadata.parents = options.parents;
214
- } else if (defaultFolderId) {
215
- metadata.parents = [defaultFolderId];
216
- }
217
- const response = await authenticatedFetch(`${BASE_URL}/files?fields=${DEFAULT_FILE_FIELDS}`, {
218
- method: "POST",
219
- body: JSON.stringify(metadata)
220
- });
221
- if (!response.ok) {
222
- const body = await response.text();
223
- throw new Error(`google-drive: createFile failed (${response.status}): ${body}`);
224
- }
225
- return await response.json();
226
- },
227
- async updateFile(fileId, metadata, addParents, removeParents) {
228
- const sp = new URLSearchParams();
229
- sp.set("fields", DEFAULT_FILE_FIELDS);
230
- if (addParents) sp.set("addParents", addParents);
231
- if (removeParents) sp.set("removeParents", removeParents);
232
- const response = await authenticatedFetch(`${BASE_URL}/files/${fileId}?${sp.toString()}`, {
233
- method: "PATCH",
234
- body: JSON.stringify(metadata)
235
- });
236
- if (!response.ok) {
237
- const body = await response.text();
238
- throw new Error(`google-drive: updateFile failed (${response.status}): ${body}`);
239
- }
240
- return await response.json();
241
- },
242
- async copyFile(fileId, name, parents) {
243
- const metadata = {};
244
- if (name) metadata.name = name;
245
- if (parents) metadata.parents = parents;
246
- const response = await authenticatedFetch(`${BASE_URL}/files/${fileId}/copy?fields=${DEFAULT_FILE_FIELDS}`, {
247
- method: "POST",
248
- body: JSON.stringify(metadata)
249
- });
250
- if (!response.ok) {
251
- const body = await response.text();
252
- throw new Error(`google-drive: copyFile failed (${response.status}): ${body}`);
253
- }
254
- return await response.json();
255
- },
256
- async listPermissions(fileId) {
257
- const response = await authenticatedFetch(
258
- `${BASE_URL}/files/${fileId}/permissions?fields=permissions(id,type,role,emailAddress,displayName)`
93
+ }
94
+ return await response.json();
95
+ }
96
+ async function listPermissions(fileId) {
97
+ const url = `${BASE_URL}/files/${fileId}/permissions?fields=permissions(id,type,role,emailAddress,displayName)`;
98
+ const response = await fetchFn(url);
99
+ if (!response.ok) {
100
+ const body = await response.text();
101
+ throw new Error(
102
+ `google-drive: listPermissions failed (${response.status}): ${body}`
259
103
  );
260
- if (!response.ok) {
261
- const body = await response.text();
262
- throw new Error(`google-drive: listPermissions failed (${response.status}): ${body}`);
263
- }
264
- return await response.json();
265
- },
266
- async shareFile(fileId, type, role, emailAddress) {
267
- const permission = { type, role };
268
- if (emailAddress) permission.emailAddress = emailAddress;
269
- const response = await authenticatedFetch(`${BASE_URL}/files/${fileId}/permissions`, {
270
- method: "POST",
271
- body: JSON.stringify(permission)
272
- });
273
- if (!response.ok) {
274
- const body = await response.text();
275
- throw new Error(`google-drive: shareFile failed (${response.status}): ${body}`);
276
- }
277
- return await response.json();
278
- },
279
- downloadFile(fileId) {
280
- return authenticatedFetch(`${BASE_URL}/files/${fileId}?alt=media`);
281
- },
282
- exportFile(fileId, mimeType) {
283
- return authenticatedFetch(`${BASE_URL}/files/${fileId}/export?mimeType=${encodeURIComponent(mimeType)}`);
284
104
  }
105
+ return await response.json();
106
+ }
107
+ async function shareFile(fileId, type, role, emailAddress) {
108
+ const permission = { type, role };
109
+ if (emailAddress) permission.emailAddress = emailAddress;
110
+ const url = `${BASE_URL}/files/${fileId}/permissions`;
111
+ const response = await fetchFn(url, {
112
+ method: "POST",
113
+ headers: { "Content-Type": "application/json" },
114
+ body: JSON.stringify(permission)
115
+ });
116
+ if (!response.ok) {
117
+ const body = await response.text();
118
+ throw new Error(
119
+ `google-drive: shareFile failed (${response.status}): ${body}`
120
+ );
121
+ }
122
+ return await response.json();
123
+ }
124
+ function downloadFile(fileId) {
125
+ const url = `${BASE_URL}/files/${fileId}?alt=media`;
126
+ return fetchFn(url);
127
+ }
128
+ function exportFile(fileId, mimeType) {
129
+ const url = `${BASE_URL}/files/${fileId}/export?mimeType=${encodeURIComponent(mimeType)}`;
130
+ return fetchFn(url);
131
+ }
132
+ return {
133
+ request,
134
+ listFiles,
135
+ getFile,
136
+ createFile,
137
+ updateFile,
138
+ copyFile,
139
+ listPermissions,
140
+ shareFile,
141
+ downloadFile,
142
+ exportFile
285
143
  };
286
144
  }
287
145
 
@@ -367,16 +225,27 @@ var ConnectorPlugin = class _ConnectorPlugin {
367
225
  * Filters connections by connectorKey internally.
368
226
  * Returns tools keyed as `${connectorKey}_${toolName}`.
369
227
  */
370
- createTools(connections, config) {
228
+ createTools(connections, config, opts) {
371
229
  const myConnections = connections.filter(
372
230
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
373
231
  );
374
232
  const result = {};
375
233
  for (const t of Object.values(this.tools)) {
376
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
377
- myConnections,
378
- config
379
- );
234
+ const tool = t.createTool(myConnections, config);
235
+ const originalToModelOutput = tool.toModelOutput;
236
+ result[`${this.connectorKey}_${t.name}`] = {
237
+ ...tool,
238
+ toModelOutput: async (options) => {
239
+ if (!originalToModelOutput) {
240
+ return opts.truncateOutput(options.output);
241
+ }
242
+ const modelOutput = await originalToModelOutput(options);
243
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
244
+ return opts.truncateOutput(modelOutput.value);
245
+ }
246
+ return modelOutput;
247
+ }
248
+ };
380
249
  }
381
250
  return result;
382
251
  }
@@ -405,10 +274,44 @@ var googleDriveOnboarding = new ConnectorOnboarding({
405
274
  }
406
275
  });
407
276
 
277
+ // ../connectors/src/connectors/google-drive/parameters.ts
278
+ var parameters = {};
279
+
408
280
  // ../connectors/src/connectors/google-drive/tools/request.ts
409
281
  import { z } from "zod";
410
282
  var BASE_URL2 = "https://www.googleapis.com/drive/v3";
411
283
  var REQUEST_TIMEOUT_MS = 6e4;
284
+ var cachedToken = null;
285
+ async function getProxyToken(config) {
286
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
287
+ return cachedToken.token;
288
+ }
289
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
290
+ const res = await fetch(url, {
291
+ method: "POST",
292
+ headers: {
293
+ "Content-Type": "application/json",
294
+ "x-api-key": config.appApiKey,
295
+ "project-id": config.projectId
296
+ },
297
+ body: JSON.stringify({
298
+ sandboxId: config.sandboxId,
299
+ issuedBy: "coding-agent"
300
+ })
301
+ });
302
+ if (!res.ok) {
303
+ const errorText = await res.text().catch(() => res.statusText);
304
+ throw new Error(
305
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
306
+ );
307
+ }
308
+ const data = await res.json();
309
+ cachedToken = {
310
+ token: data.token,
311
+ expiresAt: new Date(data.expiresAt).getTime()
312
+ };
313
+ return data.token;
314
+ }
412
315
  var inputSchema = z.object({
413
316
  toolUseIntent: z.string().optional().describe(
414
317
  "Brief description of what you intend to accomplish with this tool call"
@@ -416,7 +319,7 @@ var inputSchema = z.object({
416
319
  connectionId: z.string().describe("ID of the Google Drive connection to use"),
417
320
  method: z.enum(["GET", "POST", "PATCH"]).describe("HTTP method"),
418
321
  path: z.string().describe(
419
- "API path appended to https://www.googleapis.com/drive/v3 (e.g., '/files', '/files/{fileId}')."
322
+ "API path appended to https://www.googleapis.com/drive/v3 (e.g., '/files', '/files/{fileId}', '/files/{fileId}/permissions')."
420
323
  ),
421
324
  body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PATCH requests"),
422
325
  queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL")
@@ -425,7 +328,7 @@ var outputSchema = z.discriminatedUnion("success", [
425
328
  z.object({
426
329
  success: z.literal(true),
427
330
  status: z.number(),
428
- data: z.unknown()
331
+ data: z.record(z.string(), z.unknown())
429
332
  }),
430
333
  z.object({
431
334
  success: z.literal(false),
@@ -436,10 +339,10 @@ var requestTool = new ConnectorTool({
436
339
  name: "request",
437
340
  description: `Send authenticated requests to the Google Drive API v3.
438
341
  Supports GET (read/list/download), POST (create/copy), and PATCH (update) methods.
439
- Authentication is handled automatically using a service account.`,
342
+ Authentication is handled automatically via OAuth proxy.`,
440
343
  inputSchema,
441
344
  outputSchema,
442
- async execute({ connectionId, method, path: path2, body, queryParams }, connections) {
345
+ async execute({ connectionId, method, path: path2, body, queryParams }, connections, config) {
443
346
  const connection2 = connections.find((c) => c.id === connectionId);
444
347
  if (!connection2) {
445
348
  return {
@@ -451,46 +354,33 @@ Authentication is handled automatically using a service account.`,
451
354
  `[connector-request] google-drive/${connection2.name}: ${method} ${path2}`
452
355
  );
453
356
  try {
454
- const { GoogleAuth } = await import("google-auth-library");
455
- const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
456
- const credentials = JSON.parse(
457
- Buffer.from(keyJsonBase64, "base64").toString("utf-8")
458
- );
459
- const auth = new GoogleAuth({
460
- credentials,
461
- scopes: ["https://www.googleapis.com/auth/drive"]
462
- });
463
- const token = await auth.getAccessToken();
464
- if (!token) {
465
- return {
466
- success: false,
467
- error: "Failed to obtain access token"
468
- };
469
- }
470
357
  let url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
471
358
  if (queryParams) {
472
359
  const searchParams = new URLSearchParams(queryParams);
473
360
  url += `?${searchParams.toString()}`;
474
361
  }
362
+ const token = await getProxyToken(config.oauthProxy);
363
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
475
364
  const controller = new AbortController();
476
365
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
477
366
  try {
478
- const response = await fetch(url, {
479
- method,
367
+ const response = await fetch(proxyUrl, {
368
+ method: "POST",
480
369
  headers: {
481
- Authorization: `Bearer ${token}`,
482
- "Content-Type": "application/json"
370
+ "Content-Type": "application/json",
371
+ Authorization: `Bearer ${token}`
483
372
  },
484
- ...body != null ? { body: JSON.stringify(body) } : {},
373
+ body: JSON.stringify({
374
+ url,
375
+ method,
376
+ ...body != null ? { body: JSON.stringify(body) } : {}
377
+ }),
485
378
  signal: controller.signal
486
379
  });
487
380
  const data = await response.json();
488
381
  if (!response.ok) {
489
- const errorObj = data;
490
- return {
491
- success: false,
492
- error: errorObj?.error?.message ?? `HTTP ${response.status} ${response.statusText}`
493
- };
382
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
383
+ return { success: false, error: errorMessage };
494
384
  }
495
385
  return { success: true, status: response.status, data };
496
386
  } finally {
@@ -507,47 +397,93 @@ Authentication is handled automatically using a service account.`,
507
397
  var tools = { request: requestTool };
508
398
  var googleDriveConnector = new ConnectorPlugin({
509
399
  slug: "google-drive",
510
- authType: AUTH_TYPES.SERVICE_ACCOUNT,
400
+ authType: AUTH_TYPES.OAUTH,
511
401
  name: "Google Drive",
512
- description: "Connect to Google Drive for file management, sharing, and collaboration using a service account.",
402
+ description: "Connect to Google Drive for file management, sharing, and collaboration using OAuth.",
513
403
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4GJX5yQTogUgar1buWxXbv/4b43a65353319c508111489f834d22c4/google_drive.png",
514
404
  parameters,
515
405
  releaseFlag: { dev1: true, dev2: false, prod: false },
516
406
  onboarding: googleDriveOnboarding,
407
+ proxyPolicy: {
408
+ allowlist: [
409
+ {
410
+ host: "www.googleapis.com",
411
+ pathPrefix: "/drive/",
412
+ methods: ["GET", "POST", "PATCH"]
413
+ }
414
+ ]
415
+ },
517
416
  systemPrompt: {
518
417
  en: `### Tools
519
418
 
520
- - \`google-drive_request\`: Send authenticated requests to the Google Drive API v3. Supports GET, POST, and PATCH methods. Authentication is configured automatically via service account.
419
+ - \`google-drive_request\`: Send authenticated requests to the Google Drive API v3. Supports GET, POST, and PATCH methods. Authentication is configured automatically via OAuth.
521
420
 
522
421
  ### Google Drive API Reference
523
422
 
524
423
  #### Files
525
424
  - GET \`/files\` \u2014 List files. Key query params: \`q\` (search query), \`pageSize\`, \`pageToken\`, \`orderBy\`, \`fields\`
526
- - GET \`/files/{fileId}\` \u2014 Get file metadata
425
+ - GET \`/files/{fileId}\` \u2014 Get file metadata. Use \`fields\` param to select specific fields
527
426
  - GET \`/files/{fileId}?alt=media\` \u2014 Download file content (for non-Google-Workspace files)
528
427
  - POST \`/files\` \u2014 Create a new file or folder (metadata only). Body: \`{ "name": "My File", "mimeType": "...", "parents": ["folderId"] }\`
529
- - PATCH \`/files/{fileId}\` \u2014 Update file metadata (rename, move, star). Use \`addParents\`/\`removeParents\` query params to move
530
- - POST \`/files/{fileId}/copy\` \u2014 Copy a file
428
+ - PATCH \`/files/{fileId}\` \u2014 Update file metadata (rename, move, star). Body: \`{ "name": "New Name" }\`. Use \`addParents\`/\`removeParents\` query params to move
429
+ - POST \`/files/{fileId}/copy\` \u2014 Copy a file. Body: \`{ "name": "Copy of File", "parents": ["folderId"] }\`
531
430
 
532
431
  #### Download & Export
533
432
  - GET \`/files/{fileId}?alt=media\` \u2014 Download file content (PDFs, images, text files, etc.)
534
- - GET \`/files/{fileId}/export?mimeType={mimeType}\` \u2014 Export Google Workspace files to another format
433
+ - GET \`/files/{fileId}/export?mimeType={mimeType}\` \u2014 Export a Google Workspace file (Docs, Sheets, Slides) to another format
535
434
 
536
435
  #### Permissions (Sharing)
537
- - GET \`/files/{fileId}/permissions\` \u2014 List permissions
436
+ - GET \`/files/{fileId}/permissions\` \u2014 List permissions on a file
538
437
  - POST \`/files/{fileId}/permissions\` \u2014 Share a file. Body: \`{ "type": "user", "role": "writer", "emailAddress": "user@example.com" }\`
539
438
 
439
+ #### Account Info
440
+ - GET \`/about?fields=user,storageQuota\` \u2014 Get account info and storage usage
441
+
540
442
  ### Search Query Syntax (\`q\` parameter)
443
+ - \`name = 'My Document'\` \u2014 Exact name match
541
444
  - \`name contains 'report'\` \u2014 Name contains text
542
445
  - \`mimeType = 'application/vnd.google-apps.folder'\` \u2014 Folders only
543
446
  - \`mimeType = 'application/vnd.google-apps.spreadsheet'\` \u2014 Google Sheets only
447
+ - \`mimeType = 'application/vnd.google-apps.presentation'\` \u2014 Google Slides only
448
+ - \`mimeType = 'application/vnd.google-apps.document'\` \u2014 Google Docs only
544
449
  - \`'folderId' in parents\` \u2014 Files in a specific folder
545
450
  - \`trashed = false\` \u2014 Exclude trashed files
546
- - Combine with \`and\`/\`or\`: \`mimeType = 'application/vnd.google-apps.folder' and name contains 'project'\`
451
+ - \`starred = true\` \u2014 Starred files
452
+ - \`sharedWithMe\` \u2014 Files shared with the user
453
+ - \`modifiedTime > '2024-01-01T00:00:00'\` \u2014 Modified after date
454
+ - Combine with \`and\`/\`or\`/\`not\`: \`mimeType = 'application/vnd.google-apps.folder' and name contains 'project'\`
455
+
456
+ ### Common MIME Types
457
+ | Type | MIME Type |
458
+ |------|-----------|
459
+ | Folder | \`application/vnd.google-apps.folder\` |
460
+ | Google Docs | \`application/vnd.google-apps.document\` |
461
+ | Google Sheets | \`application/vnd.google-apps.spreadsheet\` |
462
+ | Google Slides | \`application/vnd.google-apps.presentation\` |
463
+ | PDF | \`application/pdf\` |
464
+
465
+ ### Export MIME Types (for Google Workspace files)
466
+ | Source | Export Format | MIME Type |
467
+ |--------|--------------|-----------|
468
+ | Docs | PDF | \`application/pdf\` |
469
+ | Docs | Word | \`application/vnd.openxmlformats-officedocument.wordprocessingml.document\` |
470
+ | Docs | Plain Text | \`text/plain\` |
471
+ | Sheets | PDF | \`application/pdf\` |
472
+ | Sheets | Excel | \`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\` |
473
+ | Sheets | CSV | \`text/csv\` |
474
+ | Slides | PDF | \`application/pdf\` |
475
+ | Slides | PowerPoint | \`application/vnd.openxmlformats-officedocument.presentationml.presentation\` |
476
+
477
+ ### Tips
478
+ - Always use \`fields\` parameter to limit response data and improve performance
479
+ - Use \`orderBy=modifiedTime desc\` to get most recently modified files first
480
+ - To create a folder, use mimeType \`application/vnd.google-apps.folder\`
481
+ - To move a file, use PATCH with \`addParents\` and \`removeParents\` query params
482
+ - Files in "My Drive" have no parent specified; use \`'root' in parents\` to list root files
547
483
 
548
484
  ### Business Logic
549
485
 
550
- The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below.
486
+ 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.
551
487
 
552
488
  #### Example
553
489
 
@@ -556,45 +492,118 @@ import { connection } from "@squadbase/vite-server/connectors/google-drive";
556
492
 
557
493
  const drive = connection("<connectionId>");
558
494
 
495
+ // List recent files
559
496
  const result = await drive.listFiles({ pageSize: 20, orderBy: "modifiedTime desc" });
560
497
  result.files.forEach(f => console.log(f.name, f.mimeType));
561
498
 
562
- const folder = await drive.createFile({ name: "Reports", mimeType: "application/vnd.google-apps.folder" });
499
+ // Search for spreadsheets
500
+ const sheets = await drive.listFiles({
501
+ query: "mimeType = 'application/vnd.google-apps.spreadsheet' and name contains 'report'"
502
+ });
503
+
504
+ // Get file metadata
505
+ const file = await drive.getFile("fileId123");
506
+ console.log(file.name, file.webViewLink);
507
+
508
+ // Create a folder
509
+ const folder = await drive.createFile({
510
+ name: "Reports",
511
+ mimeType: "application/vnd.google-apps.folder",
512
+ });
513
+
514
+ // Create a Google Sheets file inside the folder
515
+ const sheet = await drive.createFile({
516
+ name: "Q1 Report",
517
+ mimeType: "application/vnd.google-apps.spreadsheet",
518
+ parents: [folder.id],
519
+ });
520
+
521
+ // Download file content (non-Google-Workspace files)
563
522
  const content = await drive.downloadFile("fileId123");
523
+ const text = await content.text(); // or content.arrayBuffer() for binary
524
+
525
+ // Export a Google Docs file as PDF
564
526
  const pdf = await drive.exportFile("docFileId", "application/pdf");
527
+
528
+ // Share a file
529
+ await drive.shareFile("fileId123", "user", "writer", "colleague@example.com");
530
+
531
+ // Copy a file
532
+ const copy = await drive.copyFile("fileId123", "Backup Copy");
533
+
534
+ // Move a file to a different folder
535
+ await drive.updateFile("fileId123", {}, "newFolderId", "oldFolderId");
565
536
  \`\`\``,
566
537
  ja: `### \u30C4\u30FC\u30EB
567
538
 
568
- - \`google-drive_request\`: Google Drive API v3\u3078\u306E\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002GET, POST, PATCH\u30E1\u30BD\u30C3\u30C9\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
539
+ - \`google-drive_request\`: Google Drive API v3\u3078\u306E\u8A8D\u8A3C\u6E08\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002GET, POST, PATCH\u30E1\u30BD\u30C3\u30C9\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002OAuth\u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
569
540
 
570
541
  ### Google Drive API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
571
542
 
572
543
  #### \u30D5\u30A1\u30A4\u30EB
573
- - GET \`/files\` \u2014 \u30D5\u30A1\u30A4\u30EB\u4E00\u89A7\u3002\u4E3B\u8981\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF: \`q\`, \`pageSize\`, \`pageToken\`, \`orderBy\`, \`fields\`
574
- - GET \`/files/{fileId}\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
575
- - GET \`/files/{fileId}?alt=media\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF08\u975EGoogle Workspace\u30D5\u30A1\u30A4\u30EB\uFF09
576
- - POST \`/files\` \u2014 \u65B0\u3057\u3044\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F\u30D5\u30A9\u30EB\u30C0\u3092\u4F5C\u6210\uFF08\u30E1\u30BF\u30C7\u30FC\u30BF\u306E\u307F\uFF09
577
- - PATCH \`/files/{fileId}\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u66F4\u65B0\uFF08\u540D\u524D\u5909\u66F4\u3001\u79FB\u52D5\u3001\u30B9\u30BF\u30FC\uFF09
578
- - POST \`/files/{fileId}/copy\` \u2014 \u30D5\u30A1\u30A4\u30EB\u3092\u30B3\u30D4\u30FC
544
+ - GET \`/files\` \u2014 \u30D5\u30A1\u30A4\u30EB\u4E00\u89A7\u3002\u4E3B\u8981\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF: \`q\`\uFF08\u691C\u7D22\u30AF\u30A8\u30EA\uFF09, \`pageSize\`, \`pageToken\`, \`orderBy\`, \`fields\`
545
+ - GET \`/files/{fileId}\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3002\`fields\`\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u7279\u5B9A\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u9078\u629E
546
+ - GET \`/files/{fileId}?alt=media\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF08\u975EGoogle Workspace\u30D5\u30A1\u30A4\u30EB\u5411\u3051\uFF09
547
+ - POST \`/files\` \u2014 \u65B0\u3057\u3044\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F\u30D5\u30A9\u30EB\u30C0\u3092\u4F5C\u6210\uFF08\u30E1\u30BF\u30C7\u30FC\u30BF\u306E\u307F\uFF09\u3002Body: \`{ "name": "\u30DE\u30A4\u30D5\u30A1\u30A4\u30EB", "mimeType": "...", "parents": ["folderId"] }\`
548
+ - PATCH \`/files/{fileId}\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u66F4\u65B0\uFF08\u540D\u524D\u5909\u66F4\u3001\u79FB\u52D5\u3001\u30B9\u30BF\u30FC\uFF09\u3002Body: \`{ "name": "\u65B0\u3057\u3044\u540D\u524D" }\`\u3002\`addParents\`/\`removeParents\`\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u79FB\u52D5
549
+ - POST \`/files/{fileId}/copy\` \u2014 \u30D5\u30A1\u30A4\u30EB\u3092\u30B3\u30D4\u30FC\u3002Body: \`{ "name": "\u30B3\u30D4\u30FC", "parents": ["folderId"] }\`
579
550
 
580
551
  #### \u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 & \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
581
- - GET \`/files/{fileId}?alt=media\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9
582
- - GET \`/files/{fileId}/export?mimeType={mimeType}\` \u2014 Google Workspace\u30D5\u30A1\u30A4\u30EB\u3092\u5225\u5F62\u5F0F\u306B\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
552
+ - GET \`/files/{fileId}?alt=media\` \u2014 \u30D5\u30A1\u30A4\u30EB\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF08PDF\u3001\u753B\u50CF\u3001\u30C6\u30AD\u30B9\u30C8\u30D5\u30A1\u30A4\u30EB\u7B49\uFF09
553
+ - GET \`/files/{fileId}/export?mimeType={mimeType}\` \u2014 Google Workspace\u30D5\u30A1\u30A4\u30EB\uFF08Docs, Sheets, Slides\uFF09\u3092\u5225\u306E\u5F62\u5F0F\u306B\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
583
554
 
584
555
  #### \u30D1\u30FC\u30DF\u30C3\u30B7\u30E7\u30F3\uFF08\u5171\u6709\uFF09
585
- - GET \`/files/{fileId}/permissions\` \u2014 \u30D1\u30FC\u30DF\u30C3\u30B7\u30E7\u30F3\u4E00\u89A7
586
- - POST \`/files/{fileId}/permissions\` \u2014 \u30D5\u30A1\u30A4\u30EB\u3092\u5171\u6709
556
+ - GET \`/files/{fileId}/permissions\` \u2014 \u30D5\u30A1\u30A4\u30EB\u306E\u30D1\u30FC\u30DF\u30C3\u30B7\u30E7\u30F3\u4E00\u89A7
557
+ - POST \`/files/{fileId}/permissions\` \u2014 \u30D5\u30A1\u30A4\u30EB\u3092\u5171\u6709\u3002Body: \`{ "type": "user", "role": "writer", "emailAddress": "user@example.com" }\`
558
+
559
+ #### \u30A2\u30AB\u30A6\u30F3\u30C8\u60C5\u5831
560
+ - GET \`/about?fields=user,storageQuota\` \u2014 \u30A2\u30AB\u30A6\u30F3\u30C8\u60C5\u5831\u3068\u30B9\u30C8\u30EC\u30FC\u30B8\u4F7F\u7528\u91CF\u3092\u53D6\u5F97
587
561
 
588
562
  ### \u691C\u7D22\u30AF\u30A8\u30EA\u69CB\u6587\uFF08\`q\` \u30D1\u30E9\u30E1\u30FC\u30BF\uFF09
563
+ - \`name = '\u30DE\u30A4\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8'\` \u2014 \u540D\u524D\u306E\u5B8C\u5168\u4E00\u81F4
589
564
  - \`name contains '\u30EC\u30DD\u30FC\u30C8'\` \u2014 \u540D\u524D\u306B\u30C6\u30AD\u30B9\u30C8\u3092\u542B\u3080
590
565
  - \`mimeType = 'application/vnd.google-apps.folder'\` \u2014 \u30D5\u30A9\u30EB\u30C0\u306E\u307F
591
- - \`'folderId' in parents\` \u2014 \u7279\u5B9A\u30D5\u30A9\u30EB\u30C0\u5185\u306E\u30D5\u30A1\u30A4\u30EB
566
+ - \`mimeType = 'application/vnd.google-apps.spreadsheet'\` \u2014 Google Sheets\u306E\u307F
567
+ - \`mimeType = 'application/vnd.google-apps.presentation'\` \u2014 Google Slides\u306E\u307F
568
+ - \`mimeType = 'application/vnd.google-apps.document'\` \u2014 Google Docs\u306E\u307F
569
+ - \`'folderId' in parents\` \u2014 \u7279\u5B9A\u306E\u30D5\u30A9\u30EB\u30C0\u5185\u306E\u30D5\u30A1\u30A4\u30EB
592
570
  - \`trashed = false\` \u2014 \u30B4\u30DF\u7BB1\u3092\u9664\u5916
593
- - \`and\`/\`or\`\u3067\u7D44\u307F\u5408\u308F\u305B\u53EF\u80FD
571
+ - \`starred = true\` \u2014 \u30B9\u30BF\u30FC\u4ED8\u304D\u30D5\u30A1\u30A4\u30EB
572
+ - \`sharedWithMe\` \u2014 \u5171\u6709\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB
573
+ - \`modifiedTime > '2024-01-01T00:00:00'\` \u2014 \u6307\u5B9A\u65E5\u4EE5\u964D\u306B\u66F4\u65B0
574
+ - \`and\`/\`or\`/\`not\`\u3067\u7D44\u307F\u5408\u308F\u305B: \`mimeType = 'application/vnd.google-apps.folder' and name contains 'project'\`
575
+
576
+ ### \u4E3B\u8981\u306A MIME \u30BF\u30A4\u30D7
577
+ | \u30BF\u30A4\u30D7 | MIME Type |
578
+ |--------|-----------|
579
+ | \u30D5\u30A9\u30EB\u30C0 | \`application/vnd.google-apps.folder\` |
580
+ | Google Docs | \`application/vnd.google-apps.document\` |
581
+ | Google Sheets | \`application/vnd.google-apps.spreadsheet\` |
582
+ | Google Slides | \`application/vnd.google-apps.presentation\` |
583
+ | PDF | \`application/pdf\` |
584
+
585
+ ### \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8 MIME \u30BF\u30A4\u30D7\uFF08Google Workspace\u30D5\u30A1\u30A4\u30EB\u7528\uFF09
586
+ | \u30BD\u30FC\u30B9 | \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u5F62\u5F0F | MIME Type |
587
+ |--------|----------------|-----------|
588
+ | Docs | PDF | \`application/pdf\` |
589
+ | Docs | Word | \`application/vnd.openxmlformats-officedocument.wordprocessingml.document\` |
590
+ | Docs | \u30D7\u30EC\u30FC\u30F3\u30C6\u30AD\u30B9\u30C8 | \`text/plain\` |
591
+ | Sheets | PDF | \`application/pdf\` |
592
+ | Sheets | Excel | \`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\` |
593
+ | Sheets | CSV | \`text/csv\` |
594
+ | Slides | PDF | \`application/pdf\` |
595
+ | Slides | PowerPoint | \`application/vnd.openxmlformats-officedocument.presentationml.presentation\` |
596
+
597
+ ### \u30D2\u30F3\u30C8
598
+ - \`fields\`\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4F7F\u7528\u3057\u3066\u30EC\u30B9\u30DD\u30F3\u30B9\u30C7\u30FC\u30BF\u3092\u5236\u9650\u3057\u3001\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9\u3092\u5411\u4E0A\u3055\u305B\u3066\u304F\u3060\u3055\u3044
599
+ - \`orderBy=modifiedTime desc\`\u3067\u6700\u8FD1\u66F4\u65B0\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u5148\u306B\u53D6\u5F97
600
+ - \u30D5\u30A9\u30EB\u30C0\u3092\u4F5C\u6210\u3059\u308B\u306B\u306FmimeType\u306B\`application/vnd.google-apps.folder\`\u3092\u4F7F\u7528
601
+ - \u30D5\u30A1\u30A4\u30EB\u3092\u79FB\u52D5\u3059\u308B\u306B\u306FPATCH\u3067\`addParents\`\u3068\`removeParents\`\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4F7F\u7528
602
+ - \u300C\u30DE\u30A4\u30C9\u30E9\u30A4\u30D6\u300D\u306E\u30EB\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u306F\`'root' in parents\`\u3067\u4E00\u89A7\u8868\u793A
594
603
 
595
604
  ### Business Logic
596
605
 
597
- \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\u306ESDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002
606
+ \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
598
607
 
599
608
  #### Example
600
609
 
@@ -603,15 +612,70 @@ import { connection } from "@squadbase/vite-server/connectors/google-drive";
603
612
 
604
613
  const drive = connection("<connectionId>");
605
614
 
615
+ // \u6700\u8FD1\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u4E00\u89A7\u8868\u793A
606
616
  const result = await drive.listFiles({ pageSize: 20, orderBy: "modifiedTime desc" });
607
617
  result.files.forEach(f => console.log(f.name, f.mimeType));
608
618
 
609
- const folder = await drive.createFile({ name: "\u30EC\u30DD\u30FC\u30C8", mimeType: "application/vnd.google-apps.folder" });
619
+ // \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u691C\u7D22
620
+ const sheets = await drive.listFiles({
621
+ query: "mimeType = 'application/vnd.google-apps.spreadsheet' and name contains '\u30EC\u30DD\u30FC\u30C8'"
622
+ });
623
+
624
+ // \u30D5\u30A1\u30A4\u30EB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
625
+ const file = await drive.getFile("fileId123");
626
+ console.log(file.name, file.webViewLink);
627
+
628
+ // \u30D5\u30A9\u30EB\u30C0\u3092\u4F5C\u6210
629
+ const folder = await drive.createFile({
630
+ name: "\u30EC\u30DD\u30FC\u30C8",
631
+ mimeType: "application/vnd.google-apps.folder",
632
+ });
633
+
634
+ // \u30D5\u30A9\u30EB\u30C0\u5185\u306BGoogle Sheets\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210
635
+ const sheet = await drive.createFile({
636
+ name: "Q1\u30EC\u30DD\u30FC\u30C8",
637
+ mimeType: "application/vnd.google-apps.spreadsheet",
638
+ parents: [folder.id],
639
+ });
640
+
641
+ // \u30D5\u30A1\u30A4\u30EB\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF08\u975EGoogle Workspace\u30D5\u30A1\u30A4\u30EB\uFF09
610
642
  const content = await drive.downloadFile("fileId123");
643
+ const text = await content.text(); // \u30D0\u30A4\u30CA\u30EA\u306E\u5834\u5408\u306F content.arrayBuffer()
644
+
645
+ // Google Docs\u30D5\u30A1\u30A4\u30EB\u3092PDF\u3068\u3057\u3066\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
611
646
  const pdf = await drive.exportFile("docFileId", "application/pdf");
647
+
648
+ // \u30D5\u30A1\u30A4\u30EB\u3092\u5171\u6709
649
+ await drive.shareFile("fileId123", "user", "writer", "colleague@example.com");
650
+
651
+ // \u30D5\u30A1\u30A4\u30EB\u3092\u30B3\u30D4\u30FC
652
+ const copy = await drive.copyFile("fileId123", "\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u30B3\u30D4\u30FC");
653
+
654
+ // \u30D5\u30A1\u30A4\u30EB\u3092\u5225\u306E\u30D5\u30A9\u30EB\u30C0\u306B\u79FB\u52D5
655
+ await drive.updateFile("fileId123", {}, "newFolderId", "oldFolderId");
612
656
  \`\`\``
613
657
  },
614
- tools
658
+ tools,
659
+ async checkConnection(_params, config) {
660
+ const { proxyFetch } = config;
661
+ const url = "https://www.googleapis.com/drive/v3/about?fields=user";
662
+ try {
663
+ const res = await proxyFetch(url, { method: "GET" });
664
+ if (!res.ok) {
665
+ const errorText = await res.text().catch(() => res.statusText);
666
+ return {
667
+ success: false,
668
+ error: `Google Drive API failed: HTTP ${res.status} ${errorText}`
669
+ };
670
+ }
671
+ return { success: true };
672
+ } catch (error) {
673
+ return {
674
+ success: false,
675
+ error: error instanceof Error ? error.message : String(error)
676
+ };
677
+ }
678
+ }
615
679
  });
616
680
 
617
681
  // src/connectors/create-connector-sdk.ts