@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,239 +1,104 @@
1
- var __getOwnPropNames = Object.getOwnPropertyNames;
2
- var __esm = (fn, res) => function __init() {
3
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
- };
5
-
6
- // ../connectors/src/connectors/google-sheets/utils.ts
7
- function extractSpreadsheetId(urlOrId) {
8
- const trimmed = urlOrId.trim();
9
- const match = trimmed.match(SPREADSHEET_URL_PATTERN);
10
- if (match) {
11
- return match[1];
12
- }
13
- return trimmed;
14
- }
15
- var SPREADSHEET_URL_PATTERN;
16
- var init_utils = __esm({
17
- "../connectors/src/connectors/google-sheets/utils.ts"() {
18
- "use strict";
19
- SPREADSHEET_URL_PATTERN = /docs\.google\.com\/spreadsheets\/d\/([a-zA-Z0-9_-]+)/;
20
- }
21
- });
22
-
23
- // ../connectors/src/parameter-definition.ts
24
- var ParameterDefinition = class {
25
- slug;
26
- name;
27
- description;
28
- envVarBaseKey;
29
- type;
30
- secret;
31
- required;
32
- constructor(config) {
33
- this.slug = config.slug;
34
- this.name = config.name;
35
- this.description = config.description;
36
- this.envVarBaseKey = config.envVarBaseKey;
37
- this.type = config.type;
38
- this.secret = config.secret;
39
- this.required = config.required;
1
+ // ../connectors/src/connectors/google-sheets/sdk/index.ts
2
+ var SHEETS_BASE_URL = "https://sheets.googleapis.com/v4/spreadsheets";
3
+ function createClient(_params, fetchFn = fetch) {
4
+ function request(path2, init) {
5
+ const url = `${SHEETS_BASE_URL}${path2 === "" || path2.startsWith("/") ? "" : "/"}${path2}`;
6
+ return fetchFn(url, init);
40
7
  }
41
- /**
42
- * Get the parameter value from a ConnectorConnectionObject.
43
- */
44
- getValue(connection2) {
45
- const param = connection2.parameters.find(
46
- (p) => p.parameterSlug === this.slug
47
- );
48
- if (!param || param.value == null) {
8
+ async function getSpreadsheet(spreadsheetId) {
9
+ const url = `${SHEETS_BASE_URL}/${spreadsheetId}?fields=spreadsheetId,properties,sheets.properties`;
10
+ const response = await fetchFn(url);
11
+ if (!response.ok) {
12
+ const body = await response.text();
49
13
  throw new Error(
50
- `Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
14
+ `google-sheets: getSpreadsheet failed (${response.status}): ${body}`
51
15
  );
52
16
  }
53
- return param.value;
54
- }
55
- /**
56
- * Try to get the parameter value. Returns undefined if not found (for optional params).
57
- */
58
- tryGetValue(connection2) {
59
- const param = connection2.parameters.find(
60
- (p) => p.parameterSlug === this.slug
61
- );
62
- if (!param || param.value == null) return void 0;
63
- return param.value;
64
- }
65
- };
66
-
67
- // ../connectors/src/connectors/google-sheets/sdk/index.ts
68
- import * as crypto from "crypto";
69
-
70
- // ../connectors/src/connectors/google-sheets/parameters.ts
71
- var parameters = {
72
- serviceAccountKeyJsonBase64: new ParameterDefinition({
73
- slug: "service-account-key-json-base64",
74
- name: "Google Cloud Service Account JSON",
75
- 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 Sheets.",
76
- envVarBaseKey: "GOOGLE_SHEETS_SERVICE_ACCOUNT_JSON_BASE64",
77
- type: "base64EncodedJson",
78
- secret: true,
79
- required: true
80
- }),
81
- spreadsheetUrl: new ParameterDefinition({
82
- slug: "spreadsheet-url",
83
- name: "Google Spreadsheet URL",
84
- description: "The URL of the Google Spreadsheet (e.g., https://docs.google.com/spreadsheets/d/xxxxx/edit). The spreadsheet ID is automatically extracted from the URL.",
85
- envVarBaseKey: "GOOGLE_SHEETS_SPREADSHEET_URL",
86
- type: "text",
87
- secret: false,
88
- required: true
89
- })
90
- };
91
-
92
- // ../connectors/src/connectors/google-sheets/sdk/index.ts
93
- init_utils();
94
- var TOKEN_URL = "https://oauth2.googleapis.com/token";
95
- var BASE_URL = "https://sheets.googleapis.com/v4/spreadsheets";
96
- var SCOPE = "https://www.googleapis.com/auth/spreadsheets.readonly";
97
- function base64url(input) {
98
- const buf = typeof input === "string" ? Buffer.from(input) : input;
99
- return buf.toString("base64url");
100
- }
101
- function buildJwt(clientEmail, privateKey, nowSec) {
102
- const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
103
- const payload = base64url(
104
- JSON.stringify({
105
- iss: clientEmail,
106
- scope: SCOPE,
107
- aud: TOKEN_URL,
108
- iat: nowSec,
109
- exp: nowSec + 3600
110
- })
111
- );
112
- const signingInput = `${header}.${payload}`;
113
- const sign = crypto.createSign("RSA-SHA256");
114
- sign.update(signingInput);
115
- sign.end();
116
- const signature = base64url(sign.sign(privateKey));
117
- return `${signingInput}.${signature}`;
118
- }
119
- function createClient(params) {
120
- const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
121
- const spreadsheetUrl = params[parameters.spreadsheetUrl.slug];
122
- const defaultSpreadsheetId = spreadsheetUrl ? extractSpreadsheetId(spreadsheetUrl) : void 0;
123
- if (!serviceAccountKeyJsonBase64) {
124
- throw new Error(
125
- `google-sheets: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
126
- );
17
+ return await response.json();
127
18
  }
128
- let serviceAccountKey;
129
- try {
130
- const decoded = Buffer.from(
131
- serviceAccountKeyJsonBase64,
132
- "base64"
133
- ).toString("utf-8");
134
- serviceAccountKey = JSON.parse(decoded);
135
- } catch {
136
- throw new Error(
137
- "google-sheets: failed to decode service account key JSON from base64"
138
- );
19
+ async function getValues(spreadsheetId, range) {
20
+ const url = `${SHEETS_BASE_URL}/${spreadsheetId}/values/${encodeURIComponent(range)}`;
21
+ const response = await fetchFn(url);
22
+ if (!response.ok) {
23
+ const body = await response.text();
24
+ throw new Error(
25
+ `google-sheets: getValues failed (${response.status}): ${body}`
26
+ );
27
+ }
28
+ return await response.json();
139
29
  }
140
- if (!serviceAccountKey.client_email || !serviceAccountKey.private_key) {
141
- throw new Error(
142
- "google-sheets: service account key JSON must contain client_email and private_key"
143
- );
30
+ async function batchGetValues(spreadsheetId, ranges) {
31
+ const searchParams = new URLSearchParams();
32
+ for (const range of ranges) {
33
+ searchParams.append("ranges", range);
34
+ }
35
+ const url = `${SHEETS_BASE_URL}/${spreadsheetId}/values:batchGet?${searchParams.toString()}`;
36
+ const response = await fetchFn(url);
37
+ if (!response.ok) {
38
+ const body = await response.text();
39
+ throw new Error(
40
+ `google-sheets: batchGetValues failed (${response.status}): ${body}`
41
+ );
42
+ }
43
+ return await response.json();
144
44
  }
145
- let cachedToken = null;
146
- let tokenExpiresAt = 0;
147
- async function getAccessToken() {
148
- const nowSec = Math.floor(Date.now() / 1e3);
149
- if (cachedToken && nowSec < tokenExpiresAt - 60) {
150
- return cachedToken;
45
+ async function updateValues(spreadsheetId, range, values) {
46
+ const url = `${SHEETS_BASE_URL}/${spreadsheetId}/values/${encodeURIComponent(range)}?valueInputOption=USER_ENTERED`;
47
+ const response = await fetchFn(url, {
48
+ method: "PUT",
49
+ headers: { "Content-Type": "application/json" },
50
+ body: JSON.stringify({ range, majorDimension: "ROWS", values })
51
+ });
52
+ if (!response.ok) {
53
+ const body = await response.text();
54
+ throw new Error(
55
+ `google-sheets: updateValues failed (${response.status}): ${body}`
56
+ );
151
57
  }
152
- const jwt = buildJwt(
153
- serviceAccountKey.client_email,
154
- serviceAccountKey.private_key,
155
- nowSec
156
- );
157
- const response = await fetch(TOKEN_URL, {
58
+ return await response.json();
59
+ }
60
+ async function appendValues(spreadsheetId, range, values) {
61
+ const url = `${SHEETS_BASE_URL}/${spreadsheetId}/values/${encodeURIComponent(range)}:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS`;
62
+ const response = await fetchFn(url, {
158
63
  method: "POST",
159
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
160
- body: new URLSearchParams({
161
- grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
162
- assertion: jwt
163
- })
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify({ range, majorDimension: "ROWS", values })
164
66
  });
165
67
  if (!response.ok) {
166
- const text = await response.text();
68
+ const body = await response.text();
167
69
  throw new Error(
168
- `google-sheets: token exchange failed (${response.status}): ${text}`
70
+ `google-sheets: appendValues failed (${response.status}): ${body}`
169
71
  );
170
72
  }
171
- const data = await response.json();
172
- cachedToken = data.access_token;
173
- tokenExpiresAt = nowSec + data.expires_in;
174
- return cachedToken;
73
+ return await response.json();
175
74
  }
176
- function resolveSpreadsheetId(override) {
177
- const id = override ?? defaultSpreadsheetId;
178
- if (!id) {
75
+ async function createSpreadsheet(title, sheetTitles) {
76
+ const sheets = sheetTitles && sheetTitles.length > 0 ? sheetTitles.map((t) => ({ properties: { title: t } })) : void 0;
77
+ const url = `${SHEETS_BASE_URL}`;
78
+ const response = await fetchFn(url, {
79
+ method: "POST",
80
+ headers: { "Content-Type": "application/json" },
81
+ body: JSON.stringify({
82
+ properties: { title },
83
+ ...sheets ? { sheets } : {}
84
+ })
85
+ });
86
+ if (!response.ok) {
87
+ const body = await response.text();
179
88
  throw new Error(
180
- "google-sheets: spreadsheetId is required. Either configure a default or pass it explicitly."
89
+ `google-sheets: createSpreadsheet failed (${response.status}): ${body}`
181
90
  );
182
91
  }
183
- return id;
184
- }
185
- async function authenticatedFetch(url, init) {
186
- const accessToken = await getAccessToken();
187
- const headers = new Headers(init?.headers);
188
- headers.set("Authorization", `Bearer ${accessToken}`);
189
- return fetch(url, { ...init, headers });
92
+ return await response.json();
190
93
  }
191
94
  return {
192
- async request(path2, init) {
193
- const resolvedPath = defaultSpreadsheetId ? path2.replace(/\{spreadsheetId\}/g, defaultSpreadsheetId) : path2;
194
- const url = `${BASE_URL}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
195
- return authenticatedFetch(url, init);
196
- },
197
- async getSpreadsheet(spreadsheetId) {
198
- const id = resolveSpreadsheetId(spreadsheetId);
199
- const url = `${BASE_URL}/${id}?fields=spreadsheetId,properties,sheets.properties`;
200
- const response = await authenticatedFetch(url);
201
- if (!response.ok) {
202
- const body = await response.text();
203
- throw new Error(
204
- `google-sheets: getSpreadsheet failed (${response.status}): ${body}`
205
- );
206
- }
207
- return await response.json();
208
- },
209
- async getValues(range, spreadsheetId) {
210
- const id = resolveSpreadsheetId(spreadsheetId);
211
- const url = `${BASE_URL}/${id}/values/${encodeURIComponent(range)}`;
212
- const response = await authenticatedFetch(url);
213
- if (!response.ok) {
214
- const body = await response.text();
215
- throw new Error(
216
- `google-sheets: getValues failed (${response.status}): ${body}`
217
- );
218
- }
219
- return await response.json();
220
- },
221
- async batchGetValues(ranges, spreadsheetId) {
222
- const id = resolveSpreadsheetId(spreadsheetId);
223
- const searchParams = new URLSearchParams();
224
- for (const range of ranges) {
225
- searchParams.append("ranges", range);
226
- }
227
- const url = `${BASE_URL}/${id}/values:batchGet?${searchParams.toString()}`;
228
- const response = await authenticatedFetch(url);
229
- if (!response.ok) {
230
- const body = await response.text();
231
- throw new Error(
232
- `google-sheets: batchGetValues failed (${response.status}): ${body}`
233
- );
234
- }
235
- return await response.json();
236
- }
95
+ request,
96
+ getSpreadsheet,
97
+ getValues,
98
+ batchGetValues,
99
+ updateValues,
100
+ appendValues,
101
+ createSpreadsheet
237
102
  };
238
103
  }
239
104
 
@@ -319,16 +184,27 @@ var ConnectorPlugin = class _ConnectorPlugin {
319
184
  * Filters connections by connectorKey internally.
320
185
  * Returns tools keyed as `${connectorKey}_${toolName}`.
321
186
  */
322
- createTools(connections, config) {
187
+ createTools(connections, config, opts) {
323
188
  const myConnections = connections.filter(
324
189
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
325
190
  );
326
191
  const result = {};
327
192
  for (const t of Object.values(this.tools)) {
328
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
329
- myConnections,
330
- config
331
- );
193
+ const tool = t.createTool(myConnections, config);
194
+ const originalToModelOutput = tool.toModelOutput;
195
+ result[`${this.connectorKey}_${t.name}`] = {
196
+ ...tool,
197
+ toModelOutput: async (options) => {
198
+ if (!originalToModelOutput) {
199
+ return opts.truncateOutput(options.output);
200
+ }
201
+ const modelOutput = await originalToModelOutput(options);
202
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
203
+ return opts.truncateOutput(modelOutput.value);
204
+ }
205
+ return modelOutput;
206
+ }
207
+ };
332
208
  }
333
209
  return result;
334
210
  }
@@ -350,27 +226,61 @@ var AUTH_TYPES = {
350
226
  // ../connectors/src/connectors/google-sheets/setup.ts
351
227
  var googleSheetsOnboarding = new ConnectorOnboarding({
352
228
  dataOverviewInstructions: {
353
- en: `1. Call google-sheets_request with GET /{spreadsheetId} to get spreadsheet metadata (sheet names and properties)
354
- 2. Call google-sheets_request with GET /{spreadsheetId}/values/{sheetName}!A1:Z5 to sample data from key sheets`,
355
- ja: `1. google-sheets_request \u3067 GET /{spreadsheetId} \u3092\u547C\u3073\u51FA\u3057\u3001\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\uFF08\u30B7\u30FC\u30C8\u540D\u3068\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09\u3092\u53D6\u5F97
356
- 2. google-sheets_request \u3067 GET /{spreadsheetId}/values/{sheetName}!A1:Z5 \u3092\u547C\u3073\u51FA\u3057\u3001\u4E3B\u8981\u30B7\u30FC\u30C8\u306E\u30C7\u30FC\u30BF\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0`
229
+ en: `1. Create a new spreadsheet with google-sheets_request (POST with body { properties: { title: "..." } }) or use an existing spreadsheet ID.
230
+ 2. Call google-sheets_request with GET /{spreadsheetId} to fetch spreadsheet metadata (sheet names and properties).`,
231
+ ja: `1. google-sheets_request \u3092 POST\uFF08Body: { properties: { title: "..." } }\uFF09\u3067\u547C\u3073\u51FA\u3057\u3066\u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u4F5C\u6210\u3059\u308B\u304B\u3001\u65E2\u5B58\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3092\u5229\u7528\u3057\u307E\u3059\u3002
232
+ 2. google-sheets_request \u3067 GET /{spreadsheetId} \u3092\u547C\u3073\u51FA\u3057\u3001\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\uFF08\u30B7\u30FC\u30C8\u540D\u3068\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002`
357
233
  }
358
234
  });
359
235
 
236
+ // ../connectors/src/connectors/google-sheets/parameters.ts
237
+ var parameters = {};
238
+
360
239
  // ../connectors/src/connectors/google-sheets/tools/request.ts
361
240
  import { z } from "zod";
362
- init_utils();
363
- var BASE_URL2 = "https://sheets.googleapis.com/v4/spreadsheets";
241
+ var SHEETS_BASE_URL2 = "https://sheets.googleapis.com/v4/spreadsheets";
364
242
  var REQUEST_TIMEOUT_MS = 6e4;
243
+ var cachedToken = null;
244
+ async function getProxyToken(config) {
245
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
246
+ return cachedToken.token;
247
+ }
248
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
249
+ const res = await fetch(url, {
250
+ method: "POST",
251
+ headers: {
252
+ "Content-Type": "application/json",
253
+ "x-api-key": config.appApiKey,
254
+ "project-id": config.projectId
255
+ },
256
+ body: JSON.stringify({
257
+ sandboxId: config.sandboxId,
258
+ issuedBy: "coding-agent"
259
+ })
260
+ });
261
+ if (!res.ok) {
262
+ const errorText = await res.text().catch(() => res.statusText);
263
+ throw new Error(
264
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
265
+ );
266
+ }
267
+ const data = await res.json();
268
+ cachedToken = {
269
+ token: data.token,
270
+ expiresAt: new Date(data.expiresAt).getTime()
271
+ };
272
+ return data.token;
273
+ }
365
274
  var inputSchema = z.object({
366
275
  toolUseIntent: z.string().optional().describe(
367
276
  "Brief description of what you intend to accomplish with this tool call"
368
277
  ),
369
278
  connectionId: z.string().describe("ID of the Google Sheets connection to use"),
370
- method: z.enum(["GET"]).describe("HTTP method (read-only, GET only)"),
279
+ method: z.enum(["GET", "POST", "PUT"]).describe("HTTP method"),
371
280
  path: z.string().describe(
372
- "API path appended to https://sheets.googleapis.com/v4/spreadsheets (e.g., '/{spreadsheetId}', '/{spreadsheetId}/values/Sheet1!A1:D10'). {spreadsheetId} is automatically replaced if a default is configured."
281
+ "API path appended to https://sheets.googleapis.com/v4/spreadsheets (e.g., '', '/{spreadsheetId}', '/{spreadsheetId}/values/Sheet1!A1:D10')."
373
282
  ),
283
+ body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PUT requests"),
374
284
  queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL")
375
285
  });
376
286
  var outputSchema = z.discriminatedUnion("success", [
@@ -386,12 +296,12 @@ var outputSchema = z.discriminatedUnion("success", [
386
296
  ]);
387
297
  var requestTool = new ConnectorTool({
388
298
  name: "request",
389
- description: `Send authenticated GET requests to the Google Sheets API v4.
390
- Authentication is handled automatically using a service account.
391
- {spreadsheetId} in the path is automatically replaced with the connection's default spreadsheet ID if configured.`,
299
+ description: `Send authenticated requests to the Google Sheets API v4.
300
+ Supports GET (read), POST (create/append), and PUT (update) methods.
301
+ Authentication is handled automatically via OAuth proxy.`,
392
302
  inputSchema,
393
303
  outputSchema,
394
- async execute({ connectionId, method, path: path2, queryParams }, connections) {
304
+ async execute({ connectionId, method, path: path2, body, queryParams }, connections, config) {
395
305
  const connection2 = connections.find((c) => c.id === connectionId);
396
306
  if (!connection2) {
397
307
  return {
@@ -403,47 +313,33 @@ Authentication is handled automatically using a service account.
403
313
  `[connector-request] google-sheets/${connection2.name}: ${method} ${path2}`
404
314
  );
405
315
  try {
406
- const { GoogleAuth } = await import("google-auth-library");
407
- const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
408
- const spreadsheetUrl = parameters.spreadsheetUrl.tryGetValue(connection2);
409
- const spreadsheetId = spreadsheetUrl ? extractSpreadsheetId(spreadsheetUrl) : void 0;
410
- const credentials = JSON.parse(
411
- Buffer.from(keyJsonBase64, "base64").toString("utf-8")
412
- );
413
- const auth = new GoogleAuth({
414
- credentials,
415
- scopes: ["https://www.googleapis.com/auth/spreadsheets.readonly"]
416
- });
417
- const token = await auth.getAccessToken();
418
- if (!token) {
419
- return {
420
- success: false,
421
- error: "Failed to obtain access token"
422
- };
423
- }
424
- const resolvedPath = spreadsheetId ? path2.replace(/\{spreadsheetId\}/g, spreadsheetId) : path2;
425
- let url = `${BASE_URL2}${resolvedPath.startsWith("/") ? "" : "/"}${resolvedPath}`;
316
+ let url = `${SHEETS_BASE_URL2}${path2 === "" || path2.startsWith("/") ? "" : "/"}${path2}`;
426
317
  if (queryParams) {
427
318
  const searchParams = new URLSearchParams(queryParams);
428
319
  url += `?${searchParams.toString()}`;
429
320
  }
321
+ const token = await getProxyToken(config.oauthProxy);
322
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
430
323
  const controller = new AbortController();
431
324
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
432
325
  try {
433
- const response = await fetch(url, {
434
- method,
326
+ const response = await fetch(proxyUrl, {
327
+ method: "POST",
435
328
  headers: {
329
+ "Content-Type": "application/json",
436
330
  Authorization: `Bearer ${token}`
437
331
  },
332
+ body: JSON.stringify({
333
+ url,
334
+ method,
335
+ ...body != null ? { body: JSON.stringify(body) } : {}
336
+ }),
438
337
  signal: controller.signal
439
338
  });
440
339
  const data = await response.json();
441
340
  if (!response.ok) {
442
- const errorObj = data?.error;
443
- return {
444
- success: false,
445
- error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
446
- };
341
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
342
+ return { success: false, error: errorMessage };
447
343
  }
448
344
  return { success: true, status: response.status, data };
449
345
  } finally {
@@ -460,25 +356,39 @@ Authentication is handled automatically using a service account.
460
356
  var tools = { request: requestTool };
461
357
  var googleSheetsConnector = new ConnectorPlugin({
462
358
  slug: "google-sheets",
463
- authType: AUTH_TYPES.SERVICE_ACCOUNT,
359
+ authType: AUTH_TYPES.OAUTH,
464
360
  name: "Google Sheets",
465
- description: "Connect to Google Sheets for spreadsheet data access using a service account.",
361
+ description: "Connect to Google Sheets for spreadsheet data access and creation using OAuth.",
466
362
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
467
363
  parameters,
468
364
  releaseFlag: { dev1: true, dev2: false, prod: false },
469
365
  onboarding: googleSheetsOnboarding,
366
+ proxyPolicy: {
367
+ allowlist: [
368
+ {
369
+ host: "sheets.googleapis.com",
370
+ methods: ["GET", "POST", "PUT"]
371
+ }
372
+ ]
373
+ },
470
374
  systemPrompt: {
471
375
  en: `### Tools
472
376
 
473
- - \`google-sheets_request\`: The only way to call the Google Sheets API (read-only). Use it to get spreadsheet metadata, cell values, and batch values. Authentication is configured automatically via service account. The {spreadsheetId} placeholder in paths is automatically replaced with the configured default spreadsheet ID.
377
+ - \`google-sheets_request\`: The way to call the Google Sheets API. Supports read and write operations. Use it to get/update spreadsheet metadata, cell values, create new spreadsheets, and more. Authentication is configured automatically via OAuth.
474
378
 
475
379
  ### Google Sheets API Reference
476
380
 
477
- #### Available Endpoints
381
+ #### Read Endpoints
478
382
  - GET \`/{spreadsheetId}\` \u2014 Get spreadsheet metadata (title, sheets, properties)
479
383
  - GET \`/{spreadsheetId}/values/{range}\` \u2014 Get cell values for a range
480
384
  - GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 Get values for multiple ranges
481
385
 
386
+ #### Write Endpoints
387
+ - POST \`\` (empty path, with body) \u2014 Create a new spreadsheet. Body: \`{ "properties": { "title": "My Sheet" }, "sheets": [{ "properties": { "title": "Sheet1" } }] }\`
388
+ - PUT \`/{spreadsheetId}/values/{range}?valueInputOption=USER_ENTERED\` \u2014 Update cell values for a range. Body: \`{ "range": "Sheet1!A1:B2", "majorDimension": "ROWS", "values": [["a","b"],["c","d"]] }\`
389
+ - POST \`/{spreadsheetId}/values/{range}:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS\` \u2014 Append rows after the last row. Body: \`{ "range": "Sheet1!A1", "majorDimension": "ROWS", "values": [["a","b"]] }\`
390
+ - POST \`/{spreadsheetId}:batchUpdate\` \u2014 Apply multiple updates (formatting, add sheets, merge cells, etc.). Body: \`{ "requests": [...] }\`
391
+
482
392
  ### Range Notation (A1 notation)
483
393
  - \`Sheet1!A1:D10\` \u2014 Specific range on Sheet1
484
394
  - \`Sheet1!A:A\` \u2014 Entire column A on Sheet1
@@ -487,11 +397,12 @@ var googleSheetsConnector = new ConnectorPlugin({
487
397
  - \`A1:D10\` \u2014 Range on the first sheet (when only one sheet exists)
488
398
 
489
399
  ### Tips
490
- - Use \`{spreadsheetId}\` placeholder in paths \u2014 it is automatically replaced with the configured default spreadsheet ID
491
400
  - To explore a spreadsheet, first get metadata to see available sheet names
492
401
  - Use \`valueRenderOption=FORMATTED_VALUE\` query param to get display values
493
402
  - Use \`valueRenderOption=UNFORMATTED_VALUE\` for raw numeric values
494
403
  - Use \`majorDimension=COLUMNS\` to get data organized by columns instead of rows
404
+ - For write operations, always use \`valueInputOption=USER_ENTERED\` so values are parsed as if typed by a user (dates, numbers, formulas are auto-detected)
405
+ - Sharing (permissions) cannot be done via this connector; only the OAuth user has access to the created spreadsheets
495
406
 
496
407
  ### Business Logic
497
408
 
@@ -504,29 +415,41 @@ import { connection } from "@squadbase/vite-server/connectors/google-sheets";
504
415
 
505
416
  const sheets = connection("<connectionId>");
506
417
 
418
+ // Create a new spreadsheet
419
+ const newSheet = await sheets.createSpreadsheet("Sales Report", ["Q1", "Q2", "Q3", "Q4"]);
420
+ const spreadsheetId = newSheet.spreadsheetId;
421
+
507
422
  // Get spreadsheet metadata
508
- const metadata = await sheets.getSpreadsheet();
423
+ const metadata = await sheets.getSpreadsheet(spreadsheetId);
509
424
  console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
510
425
 
511
426
  // Get cell values
512
- const values = await sheets.getValues("Sheet1!A1:D10");
427
+ const values = await sheets.getValues(spreadsheetId, "Sheet1!A1:D10");
513
428
  console.log(values.values); // 2D array
514
429
 
515
- // Get multiple ranges at once
516
- const batch = await sheets.batchGetValues(["Sheet1!A1:B5", "Sheet2!A1:C3"]);
517
- batch.valueRanges.forEach(vr => console.log(vr.range, vr.values));
430
+ // Update cell values
431
+ await sheets.updateValues(spreadsheetId, "Sheet1!A1:B2", [["Name", "Score"], ["Alice", "100"]]);
432
+
433
+ // Append rows
434
+ await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie", "88"]]);
518
435
  \`\`\``,
519
436
  ja: `### \u30C4\u30FC\u30EB
520
437
 
521
- - \`google-sheets_request\`: Google Sheets API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\uFF08\u8AAD\u307F\u53D6\u308A\u5C02\u7528\uFF09\u3002\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3001\u30BB\u30EB\u5024\u3001\u30D0\u30C3\u30C1\u5024\u306E\u53D6\u5F97\u306B\u4F7F\u7528\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\u30D1\u30B9\u5185\u306E{spreadsheetId}\u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u306F\u8A2D\u5B9A\u6E08\u307F\u306E\u30C7\u30D5\u30A9\u30EB\u30C8\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3067\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002
438
+ - \`google-sheets_request\`: Google Sheets API\u3092\u547C\u3073\u51FA\u3059\u624B\u6BB5\u3067\u3059\u3002\u8AAD\u307F\u53D6\u308A\u3068\u66F8\u304D\u8FBC\u307F\u306E\u4E21\u65B9\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u30FB\u30BB\u30EB\u5024\u306E\u53D6\u5F97/\u66F4\u65B0\u3001\u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u4F5C\u6210\u306A\u3069\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002OAuth\u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
522
439
 
523
440
  ### Google Sheets API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
524
441
 
525
- #### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
442
+ #### \u8AAD\u307F\u53D6\u308A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
526
443
  - GET \`/{spreadsheetId}\` \u2014 \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\uFF08\u30BF\u30A4\u30C8\u30EB\u3001\u30B7\u30FC\u30C8\u3001\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09
527
444
  - GET \`/{spreadsheetId}/values/{range}\` \u2014 \u7BC4\u56F2\u306E\u30BB\u30EB\u5024\u3092\u53D6\u5F97
528
445
  - GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 \u8907\u6570\u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97
529
446
 
447
+ #### \u66F8\u304D\u8FBC\u307F\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
448
+ - POST \`\`\uFF08\u7A7A\u30D1\u30B9\u3001\u30DC\u30C7\u30A3\u4ED8\u304D\uFF09\u2014 \u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u4F5C\u6210\u3002Body: \`{ "properties": { "title": "\u30DE\u30A4\u30B7\u30FC\u30C8" }, "sheets": [{ "properties": { "title": "Sheet1" } }] }\`
449
+ - PUT \`/{spreadsheetId}/values/{range}?valueInputOption=USER_ENTERED\` \u2014 \u7BC4\u56F2\u306E\u30BB\u30EB\u5024\u3092\u66F4\u65B0\u3002Body: \`{ "range": "Sheet1!A1:B2", "majorDimension": "ROWS", "values": [["a","b"],["c","d"]] }\`
450
+ - POST \`/{spreadsheetId}/values/{range}:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS\` \u2014 \u6700\u7D42\u884C\u306E\u5F8C\u306B\u884C\u3092\u8FFD\u52A0\u3002Body: \`{ "range": "Sheet1!A1", "majorDimension": "ROWS", "values": [["a","b"]] }\`
451
+ - POST \`/{spreadsheetId}:batchUpdate\` \u2014 \u8907\u6570\u306E\u66F4\u65B0\u3092\u9069\u7528\uFF08\u66F8\u5F0F\u8A2D\u5B9A\u3001\u30B7\u30FC\u30C8\u8FFD\u52A0\u3001\u30BB\u30EB\u7D50\u5408\u306A\u3069\uFF09\u3002Body: \`{ "requests": [...] }\`
452
+
530
453
  ### \u7BC4\u56F2\u306E\u8868\u8A18\u6CD5\uFF08A1\u8868\u8A18\u6CD5\uFF09
531
454
  - \`Sheet1!A1:D10\` \u2014 Sheet1\u4E0A\u306E\u7279\u5B9A\u7BC4\u56F2
532
455
  - \`Sheet1!A:A\` \u2014 Sheet1\u306EA\u5217\u5168\u4F53
@@ -535,11 +458,12 @@ batch.valueRanges.forEach(vr => console.log(vr.range, vr.values));
535
458
  - \`A1:D10\` \u2014 \u6700\u521D\u306E\u30B7\u30FC\u30C8\u306E\u7BC4\u56F2\uFF08\u30B7\u30FC\u30C8\u304C1\u3064\u306E\u307F\u306E\u5834\u5408\uFF09
536
459
 
537
460
  ### \u30D2\u30F3\u30C8
538
- - \u30D1\u30B9\u306B \`{spreadsheetId}\` \u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u30FC\u3092\u4F7F\u7528 \u2014 \u8A2D\u5B9A\u6E08\u307F\u306E\u30C7\u30D5\u30A9\u30EB\u30C8\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3067\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059
539
461
  - \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u63A2\u7D22\u3059\u308B\u306B\u306F\u3001\u307E\u305A\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u3066\u5229\u7528\u53EF\u80FD\u306A\u30B7\u30FC\u30C8\u540D\u3092\u78BA\u8A8D\u3057\u307E\u3059
540
462
  - \u8868\u793A\u5024\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F \`valueRenderOption=FORMATTED_VALUE\` \u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4F7F\u7528\u3057\u307E\u3059
541
463
  - \u751F\u306E\u6570\u5024\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F \`valueRenderOption=UNFORMATTED_VALUE\` \u3092\u4F7F\u7528\u3057\u307E\u3059
542
464
  - \u5217\u3054\u3068\u306B\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F \`majorDimension=COLUMNS\` \u3092\u4F7F\u7528\u3057\u307E\u3059
465
+ - \u66F8\u304D\u8FBC\u307F\u64CD\u4F5C\u3067\u306F\u5E38\u306B \`valueInputOption=USER_ENTERED\` \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u5024\u304C\u30E6\u30FC\u30B6\u30FC\u5165\u529B\u306E\u3088\u3046\u306B\u89E3\u6790\u3055\u308C\u307E\u3059\uFF08\u65E5\u4ED8\u3001\u6570\u5024\u3001\u6570\u5F0F\u304C\u81EA\u52D5\u691C\u51FA\uFF09
466
+ - \u5171\u6709\uFF08permissions\uFF09\u306F\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u7D4C\u7531\u3067\u306F\u884C\u3048\u307E\u305B\u3093\u3002\u4F5C\u6210\u3057\u305F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3078\u306F\u63A5\u7D9A\u3057\u305FOAuth\u30E6\u30FC\u30B6\u30FC\u306E\u307F\u304C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u3067\u3059
543
467
 
544
468
  ### Business Logic
545
469
 
@@ -552,17 +476,23 @@ import { connection } from "@squadbase/vite-server/connectors/google-sheets";
552
476
 
553
477
  const sheets = connection("<connectionId>");
554
478
 
555
- // Get spreadsheet metadata
556
- const metadata = await sheets.getSpreadsheet();
479
+ // \u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u4F5C\u6210
480
+ const newSheet = await sheets.createSpreadsheet("\u58F2\u4E0A\u30EC\u30DD\u30FC\u30C8", ["Q1", "Q2", "Q3", "Q4"]);
481
+ const spreadsheetId = newSheet.spreadsheetId;
482
+
483
+ // \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
484
+ const metadata = await sheets.getSpreadsheet(spreadsheetId);
557
485
  console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
558
486
 
559
- // Get cell values
560
- const values = await sheets.getValues("Sheet1!A1:D10");
487
+ // \u30BB\u30EB\u5024\u3092\u53D6\u5F97
488
+ const values = await sheets.getValues(spreadsheetId, "Sheet1!A1:D10");
561
489
  console.log(values.values); // 2D array
562
490
 
563
- // Get multiple ranges at once
564
- const batch = await sheets.batchGetValues(["Sheet1!A1:B5", "Sheet2!A1:C3"]);
565
- batch.valueRanges.forEach(vr => console.log(vr.range, vr.values));
491
+ // \u30BB\u30EB\u5024\u3092\u66F4\u65B0
492
+ await sheets.updateValues(spreadsheetId, "Sheet1!A1:B2", [["\u540D\u524D", "\u30B9\u30B3\u30A2"], ["Alice", "100"]]);
493
+
494
+ // \u884C\u3092\u8FFD\u52A0
495
+ await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie", "88"]]);
566
496
  \`\`\``
567
497
  },
568
498
  tools