@squadbase/vite-server 0.1.3-dev.8 → 0.1.3

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 (63) hide show
  1. package/dist/cli/index.js +14229 -29321
  2. package/dist/connectors/airtable-oauth.js +43 -6
  3. package/dist/connectors/airtable.js +43 -6
  4. package/dist/connectors/amplitude.js +43 -6
  5. package/dist/connectors/anthropic.js +43 -6
  6. package/dist/connectors/asana.js +43 -6
  7. package/dist/connectors/attio.js +43 -6
  8. package/dist/connectors/{google-ads-oauth.d.ts → backlog-api-key.d.ts} +1 -1
  9. package/dist/connectors/backlog-api-key.js +629 -0
  10. package/dist/connectors/customerio.js +43 -6
  11. package/dist/connectors/dbt.js +43 -6
  12. package/dist/connectors/{google-sheets-oauth.d.ts → gamma.d.ts} +1 -1
  13. package/dist/connectors/gamma.js +866 -0
  14. package/dist/connectors/gemini.js +43 -6
  15. package/dist/connectors/gmail-oauth.js +65 -8
  16. package/dist/connectors/gmail.js +104 -44
  17. package/dist/connectors/google-ads.d.ts +1 -1
  18. package/dist/connectors/google-ads.js +410 -332
  19. package/dist/connectors/google-analytics-oauth.js +61 -8
  20. package/dist/connectors/google-analytics.js +107 -292
  21. package/dist/connectors/google-calendar-oauth.js +61 -8
  22. package/dist/connectors/google-calendar.js +111 -58
  23. package/dist/connectors/{linkedin-ads-oauth.d.ts → google-docs.d.ts} +1 -1
  24. package/dist/connectors/google-docs.js +631 -0
  25. package/dist/connectors/google-drive.d.ts +5 -0
  26. package/dist/connectors/google-drive.js +875 -0
  27. package/dist/connectors/google-sheets.d.ts +1 -1
  28. package/dist/connectors/google-sheets.js +267 -285
  29. package/dist/connectors/google-slides.d.ts +5 -0
  30. package/dist/connectors/google-slides.js +663 -0
  31. package/dist/connectors/grafana.js +43 -6
  32. package/dist/connectors/hubspot-oauth.js +43 -6
  33. package/dist/connectors/hubspot.js +43 -6
  34. package/dist/connectors/intercom-oauth.js +43 -6
  35. package/dist/connectors/intercom.js +43 -6
  36. package/dist/connectors/jira-api-key.js +43 -6
  37. package/dist/connectors/kintone-api-token.js +256 -82
  38. package/dist/connectors/kintone.js +43 -6
  39. package/dist/connectors/linkedin-ads.js +188 -168
  40. package/dist/connectors/mailchimp-oauth.js +43 -6
  41. package/dist/connectors/mailchimp.js +43 -6
  42. package/dist/connectors/mixpanel.d.ts +5 -0
  43. package/dist/connectors/mixpanel.js +779 -0
  44. package/dist/connectors/notion-oauth.js +43 -6
  45. package/dist/connectors/notion.js +43 -6
  46. package/dist/connectors/openai.js +43 -6
  47. package/dist/connectors/sentry.d.ts +5 -0
  48. package/dist/connectors/sentry.js +761 -0
  49. package/dist/connectors/shopify-oauth.js +43 -6
  50. package/dist/connectors/shopify.js +43 -6
  51. package/dist/connectors/stripe-api-key.js +46 -7
  52. package/dist/connectors/stripe-oauth.js +43 -6
  53. package/dist/connectors/wix-store.js +43 -6
  54. package/dist/connectors/zendesk-oauth.js +43 -6
  55. package/dist/connectors/zendesk.js +43 -6
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +4419 -3855
  58. package/dist/main.js +5481 -4918
  59. package/dist/vite-plugin.js +4474 -3948
  60. package/package.json +30 -12
  61. package/dist/connectors/google-ads-oauth.js +0 -890
  62. package/dist/connectors/google-sheets-oauth.js +0 -718
  63. package/dist/connectors/linkedin-ads-oauth.js +0 -848
@@ -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,21 +184,58 @@ 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
  }
335
211
  static deriveKey(slug, authType) {
336
- return authType ? `${slug}-${authType}` : slug;
212
+ if (authType) return `${slug}-${authType}`;
213
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
214
+ // user-password
215
+ "postgresql": "user-password",
216
+ "mysql": "user-password",
217
+ "clickhouse": "user-password",
218
+ "kintone": "user-password",
219
+ "squadbase-db": "user-password",
220
+ // service-account
221
+ "snowflake": "service-account",
222
+ "bigquery": "service-account",
223
+ "google-analytics": "service-account",
224
+ "google-calendar": "service-account",
225
+ "aws-athena": "service-account",
226
+ "redshift": "service-account",
227
+ // api-key
228
+ "databricks": "api-key",
229
+ "dbt": "api-key",
230
+ "airtable": "api-key",
231
+ "openai": "api-key",
232
+ "gemini": "api-key",
233
+ "anthropic": "api-key",
234
+ "wix-store": "api-key"
235
+ };
236
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
237
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
238
+ return slug;
337
239
  }
338
240
  };
339
241
 
@@ -350,27 +252,61 @@ var AUTH_TYPES = {
350
252
  // ../connectors/src/connectors/google-sheets/setup.ts
351
253
  var googleSheetsOnboarding = new ConnectorOnboarding({
352
254
  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`
255
+ en: `1. Create a new spreadsheet with google-sheets-oauth_request (POST with body { properties: { title: "..." } }) or use an existing spreadsheet ID.
256
+ 2. Call google-sheets-oauth_request with GET /{spreadsheetId} to fetch spreadsheet metadata (sheet names and properties).`,
257
+ ja: `1. google-sheets-oauth_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
258
+ 2. google-sheets-oauth_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
259
  }
358
260
  });
359
261
 
262
+ // ../connectors/src/connectors/google-sheets/parameters.ts
263
+ var parameters = {};
264
+
360
265
  // ../connectors/src/connectors/google-sheets/tools/request.ts
361
266
  import { z } from "zod";
362
- init_utils();
363
- var BASE_URL2 = "https://sheets.googleapis.com/v4/spreadsheets";
267
+ var SHEETS_BASE_URL2 = "https://sheets.googleapis.com/v4/spreadsheets";
364
268
  var REQUEST_TIMEOUT_MS = 6e4;
269
+ var cachedToken = null;
270
+ async function getProxyToken(config) {
271
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
272
+ return cachedToken.token;
273
+ }
274
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
275
+ const res = await fetch(url, {
276
+ method: "POST",
277
+ headers: {
278
+ "Content-Type": "application/json",
279
+ "x-api-key": config.appApiKey,
280
+ "project-id": config.projectId
281
+ },
282
+ body: JSON.stringify({
283
+ sandboxId: config.sandboxId,
284
+ issuedBy: "coding-agent"
285
+ })
286
+ });
287
+ if (!res.ok) {
288
+ const errorText = await res.text().catch(() => res.statusText);
289
+ throw new Error(
290
+ `Failed to get proxy token: HTTP ${res.status} ${errorText}`
291
+ );
292
+ }
293
+ const data = await res.json();
294
+ cachedToken = {
295
+ token: data.token,
296
+ expiresAt: new Date(data.expiresAt).getTime()
297
+ };
298
+ return data.token;
299
+ }
365
300
  var inputSchema = z.object({
366
301
  toolUseIntent: z.string().optional().describe(
367
302
  "Brief description of what you intend to accomplish with this tool call"
368
303
  ),
369
304
  connectionId: z.string().describe("ID of the Google Sheets connection to use"),
370
- method: z.enum(["GET"]).describe("HTTP method (read-only, GET only)"),
305
+ method: z.enum(["GET", "POST", "PUT"]).describe("HTTP method"),
371
306
  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."
307
+ "API path appended to https://sheets.googleapis.com/v4/spreadsheets (e.g., '', '/{spreadsheetId}', '/{spreadsheetId}/values/Sheet1!A1:D10')."
373
308
  ),
309
+ body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PUT requests"),
374
310
  queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL")
375
311
  });
376
312
  var outputSchema = z.discriminatedUnion("success", [
@@ -386,12 +322,12 @@ var outputSchema = z.discriminatedUnion("success", [
386
322
  ]);
387
323
  var requestTool = new ConnectorTool({
388
324
  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.`,
325
+ description: `Send authenticated requests to the Google Sheets API v4.
326
+ Supports GET (read), POST (create/append), and PUT (update) methods.
327
+ Authentication is handled automatically via OAuth proxy.`,
392
328
  inputSchema,
393
329
  outputSchema,
394
- async execute({ connectionId, method, path: path2, queryParams }, connections) {
330
+ async execute({ connectionId, method, path: path2, body, queryParams }, connections, config) {
395
331
  const connection2 = connections.find((c) => c.id === connectionId);
396
332
  if (!connection2) {
397
333
  return {
@@ -403,47 +339,33 @@ Authentication is handled automatically using a service account.
403
339
  `[connector-request] google-sheets/${connection2.name}: ${method} ${path2}`
404
340
  );
405
341
  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}`;
342
+ let url = `${SHEETS_BASE_URL2}${path2 === "" || path2.startsWith("/") ? "" : "/"}${path2}`;
426
343
  if (queryParams) {
427
344
  const searchParams = new URLSearchParams(queryParams);
428
345
  url += `?${searchParams.toString()}`;
429
346
  }
347
+ const token = await getProxyToken(config.oauthProxy);
348
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
430
349
  const controller = new AbortController();
431
350
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
432
351
  try {
433
- const response = await fetch(url, {
434
- method,
352
+ const response = await fetch(proxyUrl, {
353
+ method: "POST",
435
354
  headers: {
355
+ "Content-Type": "application/json",
436
356
  Authorization: `Bearer ${token}`
437
357
  },
358
+ body: JSON.stringify({
359
+ url,
360
+ method,
361
+ ...body != null ? { body: JSON.stringify(body) } : {}
362
+ }),
438
363
  signal: controller.signal
439
364
  });
440
365
  const data = await response.json();
441
366
  if (!response.ok) {
442
- const errorObj = data?.error;
443
- return {
444
- success: false,
445
- error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
446
- };
367
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
368
+ return { success: false, error: errorMessage };
447
369
  }
448
370
  return { success: true, status: response.status, data };
449
371
  } finally {
@@ -460,25 +382,41 @@ Authentication is handled automatically using a service account.
460
382
  var tools = { request: requestTool };
461
383
  var googleSheetsConnector = new ConnectorPlugin({
462
384
  slug: "google-sheets",
463
- authType: AUTH_TYPES.SERVICE_ACCOUNT,
385
+ authType: AUTH_TYPES.OAUTH,
464
386
  name: "Google Sheets",
465
- description: "Connect to Google Sheets for spreadsheet data access using a service account.",
387
+ description: "Connect to Google Sheets for spreadsheet data access and creation using OAuth.",
466
388
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
467
389
  parameters,
468
390
  releaseFlag: { dev1: true, dev2: false, prod: false },
469
391
  onboarding: googleSheetsOnboarding,
392
+ proxyPolicy: {
393
+ allowlist: [
394
+ {
395
+ host: "sheets.googleapis.com",
396
+ methods: ["GET", "POST", "PUT"]
397
+ }
398
+ ]
399
+ },
470
400
  systemPrompt: {
471
- en: `### Tools
401
+ en: `### Tools (setup-time only)
402
+
403
+ - \`google-sheets-oauth_request\`: Call the Google Sheets API during setup / data overview. 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.
472
404
 
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.
405
+ > **Important**: The \`google-sheets-oauth_request\` tool is only available at setup time. Inside server-logic handlers, use the SDK (\`connection(id).getValues\`, etc.) \u2014 the SDK's fetch is already wired through the OAuth proxy. **Do NOT** hand-roll HTTP calls to \`_sqcore/connections/*/request\` from a handler.
474
406
 
475
407
  ### Google Sheets API Reference
476
408
 
477
- #### Available Endpoints
409
+ #### Read Endpoints
478
410
  - GET \`/{spreadsheetId}\` \u2014 Get spreadsheet metadata (title, sheets, properties)
479
411
  - GET \`/{spreadsheetId}/values/{range}\` \u2014 Get cell values for a range
480
412
  - GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 Get values for multiple ranges
481
413
 
414
+ #### Write Endpoints
415
+ - POST \`\` (empty path, with body) \u2014 Create a new spreadsheet. Body: \`{ "properties": { "title": "My Sheet" }, "sheets": [{ "properties": { "title": "Sheet1" } }] }\`
416
+ - 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"]] }\`
417
+ - 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"]] }\`
418
+ - POST \`/{spreadsheetId}:batchUpdate\` \u2014 Apply multiple updates (formatting, add sheets, merge cells, etc.). Body: \`{ "requests": [...] }\`
419
+
482
420
  ### Range Notation (A1 notation)
483
421
  - \`Sheet1!A1:D10\` \u2014 Specific range on Sheet1
484
422
  - \`Sheet1!A:A\` \u2014 Entire column A on Sheet1
@@ -487,15 +425,27 @@ var googleSheetsConnector = new ConnectorPlugin({
487
425
  - \`A1:D10\` \u2014 Range on the first sheet (when only one sheet exists)
488
426
 
489
427
  ### Tips
490
- - Use \`{spreadsheetId}\` placeholder in paths \u2014 it is automatically replaced with the configured default spreadsheet ID
491
428
  - To explore a spreadsheet, first get metadata to see available sheet names
492
429
  - Use \`valueRenderOption=FORMATTED_VALUE\` query param to get display values
493
430
  - Use \`valueRenderOption=UNFORMATTED_VALUE\` for raw numeric values
494
431
  - Use \`majorDimension=COLUMNS\` to get data organized by columns instead of rows
432
+ - For write operations, always use \`valueInputOption=USER_ENTERED\` so values are parsed as if typed by a user (dates, numbers, formulas are auto-detected)
433
+ - Sharing (permissions) cannot be done via this connector; only the OAuth user has access to the created spreadsheets
495
434
 
496
435
  ### Business Logic
497
436
 
498
- 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.
437
+ 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 and do NOT read \`INTERNAL_SQUADBASE_*\` env vars \u2014 the SDK takes care of OAuth.
438
+
439
+ SDK surface (client created via \`connection(connectionId)\`):
440
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch (\`path\` is appended to \`https://sheets.googleapis.com/v4/spreadsheets\`).
441
+ - \`client.getSpreadsheet(spreadsheetId)\` \u2014 fetch spreadsheet metadata.
442
+ - \`client.getValues(spreadsheetId, range)\` \u2014 read a range (A1 notation).
443
+ - \`client.batchGetValues(spreadsheetId, ranges)\` \u2014 read multiple ranges.
444
+ - \`client.updateValues(spreadsheetId, range, values)\` \u2014 write values to a range.
445
+ - \`client.appendValues(spreadsheetId, range, values)\` \u2014 append rows after the last row.
446
+ - \`client.createSpreadsheet(title, sheetNames?)\` \u2014 create a new spreadsheet.
447
+
448
+ If a handler test fails with \`Connection proxy is not configured\`, retry \u2014 the sandbox is still initializing. Do NOT abandon the SDK and construct OAuth proxy URLs manually.
499
449
 
500
450
  #### Example
501
451
 
@@ -504,29 +454,43 @@ import { connection } from "@squadbase/vite-server/connectors/google-sheets";
504
454
 
505
455
  const sheets = connection("<connectionId>");
506
456
 
457
+ // Create a new spreadsheet
458
+ const newSheet = await sheets.createSpreadsheet("Sales Report", ["Q1", "Q2", "Q3", "Q4"]);
459
+ const spreadsheetId = newSheet.spreadsheetId;
460
+
507
461
  // Get spreadsheet metadata
508
- const metadata = await sheets.getSpreadsheet();
462
+ const metadata = await sheets.getSpreadsheet(spreadsheetId);
509
463
  console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
510
464
 
511
465
  // Get cell values
512
- const values = await sheets.getValues("Sheet1!A1:D10");
466
+ const values = await sheets.getValues(spreadsheetId, "Sheet1!A1:D10");
513
467
  console.log(values.values); // 2D array
514
468
 
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));
469
+ // Update cell values
470
+ await sheets.updateValues(spreadsheetId, "Sheet1!A1:B2", [["Name", "Score"], ["Alice", "100"]]);
471
+
472
+ // Append rows
473
+ await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie", "88"]]);
518
474
  \`\`\``,
519
- ja: `### \u30C4\u30FC\u30EB
475
+ ja: `### \u30C4\u30FC\u30EB\uFF08\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306E\u307F\uFF09
476
+
477
+ - \`google-sheets-oauth_request\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3084\u30C7\u30FC\u30BF\u6982\u8981\u628A\u63E1\u6642\u306B Google Sheets API \u3092\u547C\u3073\u51FA\u3059\u30C4\u30FC\u30EB\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
520
478
 
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
479
+ > **\u91CD\u8981**: \`google-sheets-oauth_request\` \u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306E\u307F\u5229\u7528\u53EF\u80FD\u3067\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u30ED\u30B8\u30C3\u30AF\u306E\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u5FC5\u305A SDK\uFF08\`connection(id).getValues\` \u306A\u3069\uFF09\u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002SDK \u306E fetch \u306F OAuth \u30D7\u30ED\u30AD\u30B7\u7D4C\u7531\u3067\u65E2\u306B\u914D\u7DDA\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u304B\u3089 \`_sqcore/connections/*/request\` \u3092\u624B\u66F8\u304D\u3067\u547C\u3073\u51FA\u3055\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
522
480
 
523
481
  ### Google Sheets API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
524
482
 
525
- #### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
483
+ #### \u8AAD\u307F\u53D6\u308A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
526
484
  - 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
485
  - GET \`/{spreadsheetId}/values/{range}\` \u2014 \u7BC4\u56F2\u306E\u30BB\u30EB\u5024\u3092\u53D6\u5F97
528
486
  - GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 \u8907\u6570\u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97
529
487
 
488
+ #### \u66F8\u304D\u8FBC\u307F\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
489
+ - 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" } }] }\`
490
+ - 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"]] }\`
491
+ - 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"]] }\`
492
+ - 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": [...] }\`
493
+
530
494
  ### \u7BC4\u56F2\u306E\u8868\u8A18\u6CD5\uFF08A1\u8868\u8A18\u6CD5\uFF09
531
495
  - \`Sheet1!A1:D10\` \u2014 Sheet1\u4E0A\u306E\u7279\u5B9A\u7BC4\u56F2
532
496
  - \`Sheet1!A:A\` \u2014 Sheet1\u306EA\u5217\u5168\u4F53
@@ -535,15 +499,27 @@ batch.valueRanges.forEach(vr => console.log(vr.range, vr.values));
535
499
  - \`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
500
 
537
501
  ### \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
502
  - \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
503
  - \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
504
  - \u751F\u306E\u6570\u5024\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F \`valueRenderOption=UNFORMATTED_VALUE\` \u3092\u4F7F\u7528\u3057\u307E\u3059
542
505
  - \u5217\u3054\u3068\u306B\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F \`majorDimension=COLUMNS\` \u3092\u4F7F\u7528\u3057\u307E\u3059
506
+ - \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
507
+ - \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
508
 
544
509
  ### Business Logic
545
510
 
546
- \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
511
+ \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\u30BF SDK \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\`INTERNAL_SQUADBASE_*\` \u306E\u74B0\u5883\u5909\u6570\u3092\u4F7F\u3063\u3066\u624B\u52D5\u3067 OAuth \u30D7\u30ED\u30AD\u30B7\u3092\u53E9\u304F\u3053\u3068\u3082\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044 \u2014 SDK \u304C OAuth \u3092\u51E6\u7406\u3057\u307E\u3059\u3002
512
+
513
+ SDK\uFF08\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\uFF09:
514
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304D fetch\uFF08\`path\` \u306F \`https://sheets.googleapis.com/v4/spreadsheets\` \u306B\u8FFD\u52A0\u3055\u308C\u307E\u3059\uFF09\u3002
515
+ - \`client.getSpreadsheet(spreadsheetId)\` \u2014 \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3002
516
+ - \`client.getValues(spreadsheetId, range)\` \u2014 \u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97\uFF08A1 \u8868\u8A18\uFF09\u3002
517
+ - \`client.batchGetValues(spreadsheetId, ranges)\` \u2014 \u8907\u6570\u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97\u3002
518
+ - \`client.updateValues(spreadsheetId, range, values)\` \u2014 \u7BC4\u56F2\u306B\u5024\u3092\u66F8\u304D\u8FBC\u307F\u3002
519
+ - \`client.appendValues(spreadsheetId, range, values)\` \u2014 \u6700\u7D42\u884C\u306E\u5F8C\u306B\u884C\u3092\u8FFD\u52A0\u3002
520
+ - \`client.createSpreadsheet(title, sheetNames?)\` \u2014 \u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u4F5C\u6210\u3002
521
+
522
+ \u30CF\u30F3\u30C9\u30E9\u306E\u30C6\u30B9\u30C8\u304C \`Connection proxy is not configured\` \u3067\u5931\u6557\u3059\u308B\u5834\u5408\u306F\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u901A\u5E38\u306F\u30B5\u30F3\u30C9\u30DC\u30C3\u30AF\u30B9\u306E\u521D\u671F\u5316\u4E2D\u306B\u8D77\u304D\u307E\u3059\u3002SDK \u3092\u8AE6\u3081\u3066 OAuth \u30D7\u30ED\u30AD\u30B7\u306E URL \u3092\u81EA\u5206\u3067\u7D44\u307F\u7ACB\u3066\u308B\u3053\u3068\u306F **\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044**\u3002
547
523
 
548
524
  #### Example
549
525
 
@@ -552,17 +528,23 @@ import { connection } from "@squadbase/vite-server/connectors/google-sheets";
552
528
 
553
529
  const sheets = connection("<connectionId>");
554
530
 
555
- // Get spreadsheet metadata
556
- const metadata = await sheets.getSpreadsheet();
531
+ // \u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u3092\u4F5C\u6210
532
+ const newSheet = await sheets.createSpreadsheet("\u58F2\u4E0A\u30EC\u30DD\u30FC\u30C8", ["Q1", "Q2", "Q3", "Q4"]);
533
+ const spreadsheetId = newSheet.spreadsheetId;
534
+
535
+ // \u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
536
+ const metadata = await sheets.getSpreadsheet(spreadsheetId);
557
537
  console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
558
538
 
559
- // Get cell values
560
- const values = await sheets.getValues("Sheet1!A1:D10");
539
+ // \u30BB\u30EB\u5024\u3092\u53D6\u5F97
540
+ const values = await sheets.getValues(spreadsheetId, "Sheet1!A1:D10");
561
541
  console.log(values.values); // 2D array
562
542
 
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));
543
+ // \u30BB\u30EB\u5024\u3092\u66F4\u65B0
544
+ await sheets.updateValues(spreadsheetId, "Sheet1!A1:B2", [["\u540D\u524D", "\u30B9\u30B3\u30A2"], ["Alice", "100"]]);
545
+
546
+ // \u884C\u3092\u8FFD\u52A0
547
+ await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie", "88"]]);
566
548
  \`\`\``
567
549
  },
568
550
  tools