@squadbase/vite-server 0.1.6 → 0.1.7-dev.1
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.
- package/dist/cli/index.js +238 -147
- package/dist/connectors/google-sheets.js +95 -138
- package/dist/connectors/influxdb.js +119 -29
- package/dist/connectors/sentry.js +1 -1
- package/dist/connectors/shopify.js +2 -0
- package/dist/index.js +238 -147
- package/dist/main.js +238 -147
- package/dist/vite-plugin.js +238 -147
- package/package.json +1 -1
|
@@ -42,63 +42,11 @@ function createClient(_params, fetchFn = fetch) {
|
|
|
42
42
|
}
|
|
43
43
|
return await response.json();
|
|
44
44
|
}
|
|
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
|
-
);
|
|
57
|
-
}
|
|
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, {
|
|
63
|
-
method: "POST",
|
|
64
|
-
headers: { "Content-Type": "application/json" },
|
|
65
|
-
body: JSON.stringify({ range, majorDimension: "ROWS", values })
|
|
66
|
-
});
|
|
67
|
-
if (!response.ok) {
|
|
68
|
-
const body = await response.text();
|
|
69
|
-
throw new Error(
|
|
70
|
-
`google-sheets: appendValues failed (${response.status}): ${body}`
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
return await response.json();
|
|
74
|
-
}
|
|
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();
|
|
88
|
-
throw new Error(
|
|
89
|
-
`google-sheets: createSpreadsheet failed (${response.status}): ${body}`
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
return await response.json();
|
|
93
|
-
}
|
|
94
45
|
return {
|
|
95
46
|
request,
|
|
96
47
|
getSpreadsheet,
|
|
97
48
|
getValues,
|
|
98
|
-
batchGetValues
|
|
99
|
-
updateValues,
|
|
100
|
-
appendValues,
|
|
101
|
-
createSpreadsheet
|
|
49
|
+
batchGetValues
|
|
102
50
|
};
|
|
103
51
|
}
|
|
104
52
|
|
|
@@ -249,19 +197,6 @@ var AUTH_TYPES = {
|
|
|
249
197
|
USER_PASSWORD: "user-password"
|
|
250
198
|
};
|
|
251
199
|
|
|
252
|
-
// ../connectors/src/connectors/google-sheets/setup.ts
|
|
253
|
-
var googleSheetsOnboarding = new ConnectorOnboarding({
|
|
254
|
-
dataOverviewInstructions: {
|
|
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`
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// ../connectors/src/connectors/google-sheets/parameters.ts
|
|
263
|
-
var parameters = {};
|
|
264
|
-
|
|
265
200
|
// ../connectors/src/connectors/google-sheets/tools/request.ts
|
|
266
201
|
import { z } from "zod";
|
|
267
202
|
var SHEETS_BASE_URL2 = "https://sheets.googleapis.com/v4/spreadsheets";
|
|
@@ -302,11 +237,10 @@ var inputSchema = z.object({
|
|
|
302
237
|
"Brief description of what you intend to accomplish with this tool call"
|
|
303
238
|
),
|
|
304
239
|
connectionId: z.string().describe("ID of the Google Sheets connection to use"),
|
|
305
|
-
method: z.enum(["GET"
|
|
240
|
+
method: z.enum(["GET"]).describe("HTTP method. Only GET is supported (read-only analysis)."),
|
|
306
241
|
path: z.string().describe(
|
|
307
|
-
"API path appended to https://sheets.googleapis.com/v4/spreadsheets (e.g., '
|
|
242
|
+
"API path appended to https://sheets.googleapis.com/v4/spreadsheets (e.g., '/{spreadsheetId}', '/{spreadsheetId}/values/Sheet1!A1:D10'). The `{spreadsheetId}` placeholder is automatically replaced with the connection's configured spreadsheet ID."
|
|
308
243
|
),
|
|
309
|
-
body: z.record(z.string(), z.unknown()).optional().describe("JSON request body for POST/PUT requests"),
|
|
310
244
|
queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL")
|
|
311
245
|
});
|
|
312
246
|
var outputSchema = z.discriminatedUnion("success", [
|
|
@@ -322,12 +256,12 @@ var outputSchema = z.discriminatedUnion("success", [
|
|
|
322
256
|
]);
|
|
323
257
|
var requestTool = new ConnectorTool({
|
|
324
258
|
name: "request",
|
|
325
|
-
description: `Send authenticated requests to the Google Sheets API v4.
|
|
326
|
-
|
|
259
|
+
description: `Send authenticated GET requests to the Google Sheets API v4 for read-only analysis.
|
|
260
|
+
The \`{spreadsheetId}\` placeholder in the path is automatically replaced with the connection's configured spreadsheet ID.
|
|
327
261
|
Authentication is handled automatically via OAuth proxy.`,
|
|
328
262
|
inputSchema,
|
|
329
263
|
outputSchema,
|
|
330
|
-
async execute({ connectionId, method, path: path2,
|
|
264
|
+
async execute({ connectionId, method, path: path2, queryParams }, connections, config) {
|
|
331
265
|
const connection2 = connections.find((c) => c.id === connectionId);
|
|
332
266
|
if (!connection2) {
|
|
333
267
|
return {
|
|
@@ -357,8 +291,7 @@ Authentication is handled automatically via OAuth proxy.`,
|
|
|
357
291
|
},
|
|
358
292
|
body: JSON.stringify({
|
|
359
293
|
url,
|
|
360
|
-
method
|
|
361
|
-
...body != null ? { body: JSON.stringify(body) } : {}
|
|
294
|
+
method
|
|
362
295
|
}),
|
|
363
296
|
signal: controller.signal
|
|
364
297
|
});
|
|
@@ -378,13 +311,69 @@ Authentication is handled automatically via OAuth proxy.`,
|
|
|
378
311
|
}
|
|
379
312
|
});
|
|
380
313
|
|
|
314
|
+
// ../connectors/src/connectors/google-sheets/setup.ts
|
|
315
|
+
var requestToolName = `google-sheets-oauth_${requestTool.name}`;
|
|
316
|
+
var googleSheetsOnboarding = new ConnectorOnboarding({
|
|
317
|
+
connectionSetupInstructions: {
|
|
318
|
+
ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Google Sheets (OAuth) \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002\u5206\u6790\u5BFE\u8C61\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306F\u30E6\u30FC\u30B6\u30FC\u304B\u3089\u53D7\u3051\u53D6\u3063\u305FURL\u3067\u6307\u5B9A\u3057\u307E\u3059\uFF08\u65B0\u3057\u3044\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306F\u4F5C\u6210\u3057\u307E\u305B\u3093\uFF09\u3002
|
|
319
|
+
|
|
320
|
+
1. \`askUserQuestion\` \u3067\u5206\u6790\u5BFE\u8C61\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306EURL\u3092\u30D2\u30A2\u30EA\u30F3\u30B0\u3059\u308B:
|
|
321
|
+
- \`type\`: \`"freeText"\`
|
|
322
|
+
- \`question\`: \u300C\u5206\u6790\u3057\u305F\u3044Google Sheets\u306EURL\u3092\u8CBC\u308A\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044\u300D
|
|
323
|
+
- \`placeholder\`: \`"https://docs.google.com/spreadsheets/d/.../edit"\`
|
|
324
|
+
2. \u53D7\u3051\u53D6\u3063\u305FURL\u304B\u3089\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3092\u62BD\u51FA\u3059\u308B\u3002URL\u306E \`/d/\` \u3068 \`/edit\`\uFF08\u307E\u305F\u306F\u672B\u5C3E\uFF09\u306E\u9593\u306B\u3042\u308B\u6587\u5B57\u5217\u304C\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3067\u3059\uFF08\u4F8B: \`https://docs.google.com/spreadsheets/d/1AbCxyz.../edit\` \u2192 \`1AbCxyz...\`\uFF09\u3002URL\u3067\u306F\u306A\u304FID\u3060\u3051\u304C\u6E21\u3055\u308C\u305F\u5834\u5408\u306F\u305D\u306E\u307E\u307E\u5229\u7528\u3057\u307E\u3059\u3002
|
|
325
|
+
3. \u62BD\u51FA\u3057\u305FID\u3092 \`updateConnectionParameters\` \u3067\u4FDD\u5B58\u3059\u308B:
|
|
326
|
+
- \`parameterSlug\`: \`"spreadsheet-id"\`
|
|
327
|
+
- \`options\`: \`[{ value: <\u62BD\u51FA\u3057\u305FID>, label: <\u540C\u3058\u5024> }]\`\uFF081\u4EF6\u306E\u307F\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u81EA\u52D5\u9078\u629E\u3055\u308C\u308B\uFF09
|
|
328
|
+
4. \`${requestToolName}\` \u3067\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3059\u308B:
|
|
329
|
+
- \`method\`: \`"GET"\`
|
|
330
|
+
- \`path\`: \`"/{spreadsheetId}"\`
|
|
331
|
+
5. \u30A8\u30E9\u30FC\u304C\u8FD4\u3055\u308C\u305F\u5834\u5408\u3001\u4EE5\u4E0B\u3092\u78BA\u8A8D\u3059\u308B\u3088\u3046\u30E6\u30FC\u30B6\u30FC\u306B\u4F1D\u3048\u308B:
|
|
332
|
+
- OAuth\u3067\u63A5\u7D9A\u3057\u305FGoogle\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u305D\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306B\u95B2\u89A7\u6A29\u9650\u3092\u6301\u3063\u3066\u3044\u308B\u304B
|
|
333
|
+
- \u5165\u529B\u3055\u308C\u305FURL\u304C\u6B63\u3057\u3044\u304B
|
|
334
|
+
|
|
335
|
+
#### \u5236\u7D04
|
|
336
|
+
- **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30BB\u30EB\u5024\u3092\u5927\u91CF\u306B\u53D6\u5F97\u3057\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u306E\u307F
|
|
337
|
+
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u3002\u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
|
|
338
|
+
en: `Follow these steps to set up the Google Sheets (OAuth) connection. The spreadsheet to analyze is specified by the URL provided by the user (no new spreadsheet is created).
|
|
339
|
+
|
|
340
|
+
1. Call \`askUserQuestion\` to ask for the spreadsheet URL to analyze:
|
|
341
|
+
- \`type\`: \`"freeText"\`
|
|
342
|
+
- \`question\`: "Please paste the URL of the Google Sheet you want to analyze"
|
|
343
|
+
- \`placeholder\`: \`"https://docs.google.com/spreadsheets/d/.../edit"\`
|
|
344
|
+
2. Extract the spreadsheet ID from the URL. It is the segment between \`/d/\` and \`/edit\` (or the end of the URL), e.g. \`https://docs.google.com/spreadsheets/d/1AbCxyz.../edit\` \u2192 \`1AbCxyz...\`. If the user pasted just the ID, use it as-is.
|
|
345
|
+
3. Save the extracted ID via \`updateConnectionParameters\`:
|
|
346
|
+
- \`parameterSlug\`: \`"spreadsheet-id"\`
|
|
347
|
+
- \`options\`: \`[{ value: <extracted ID>, label: <same value> }]\` (a single option is auto-selected)
|
|
348
|
+
4. Verify access by calling \`${requestToolName}\`:
|
|
349
|
+
- \`method\`: \`"GET"\`
|
|
350
|
+
- \`path\`: \`"/{spreadsheetId}"\`
|
|
351
|
+
5. If an error is returned, ask the user to verify:
|
|
352
|
+
- The OAuthed Google account has read access to the spreadsheet
|
|
353
|
+
- The URL they entered is correct
|
|
354
|
+
|
|
355
|
+
#### Constraints
|
|
356
|
+
- **Do NOT read large amounts of cell data during setup**. Only the metadata request specified above is allowed
|
|
357
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
358
|
+
},
|
|
359
|
+
dataOverviewInstructions: {
|
|
360
|
+
en: `1. Call ${requestToolName} with GET /{spreadsheetId} to fetch spreadsheet metadata (sheet names, grid properties)
|
|
361
|
+
2. For each sheet of interest, call ${requestToolName} with GET /{spreadsheetId}/values/{SheetName}!A1:Z5 to sample the first rows and understand the column layout`,
|
|
362
|
+
ja: `1. ${requestToolName} \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\u3001\u30B0\u30EA\u30C3\u30C9\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09\u3092\u53D6\u5F97
|
|
363
|
+
2. \u4E3B\u8981\u306A\u30B7\u30FC\u30C8\u306B\u3064\u3044\u3066 ${requestToolName} \u3067 GET /{spreadsheetId}/values/{\u30B7\u30FC\u30C8\u540D}!A1:Z5 \u3092\u547C\u3073\u51FA\u3057\u3001\u5148\u982D\u6570\u884C\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3057\u3066\u30AB\u30E9\u30E0\u69CB\u9020\u3092\u628A\u63E1`
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// ../connectors/src/connectors/google-sheets/parameters.ts
|
|
368
|
+
var parameters = {};
|
|
369
|
+
|
|
381
370
|
// ../connectors/src/connectors/google-sheets/index.ts
|
|
382
371
|
var tools = { request: requestTool };
|
|
383
372
|
var googleSheetsConnector = new ConnectorPlugin({
|
|
384
373
|
slug: "google-sheets",
|
|
385
374
|
authType: AUTH_TYPES.OAUTH,
|
|
386
375
|
name: "Google Sheets",
|
|
387
|
-
description: "Connect to Google Sheets for
|
|
376
|
+
description: "Connect to an existing Google Sheets spreadsheet for read-only data analysis using OAuth.",
|
|
388
377
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/1UPQuggyiZmbb26CuaSr2h/032770e8739b183fa00b7625f024e536/google-sheets.svg",
|
|
389
378
|
parameters,
|
|
390
379
|
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
@@ -393,30 +382,25 @@ var googleSheetsConnector = new ConnectorPlugin({
|
|
|
393
382
|
allowlist: [
|
|
394
383
|
{
|
|
395
384
|
host: "sheets.googleapis.com",
|
|
396
|
-
methods: ["GET"
|
|
385
|
+
methods: ["GET"]
|
|
397
386
|
}
|
|
398
387
|
]
|
|
399
388
|
},
|
|
400
389
|
systemPrompt: {
|
|
401
390
|
en: `### Tools (setup-time only)
|
|
402
391
|
|
|
403
|
-
- \`google-sheets-oauth_request\`: Call the Google Sheets API during setup / data overview.
|
|
392
|
+
- \`google-sheets-oauth_request\`: Call the Google Sheets API during setup / data overview. Read-only (GET only). Use it to fetch spreadsheet metadata and sample cell values. The \`{spreadsheetId}\` placeholder in the path is automatically replaced with the spreadsheet configured at setup time. Authentication is configured automatically via OAuth.
|
|
404
393
|
|
|
405
394
|
> **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.
|
|
406
395
|
|
|
407
|
-
|
|
396
|
+
> **Connection scope**: Each connection is bound to a single spreadsheet selected at setup time via URL. This connector does NOT create new spreadsheets and does NOT write to spreadsheets. The OAuth scope is \`spreadsheets.readonly\`.
|
|
397
|
+
|
|
398
|
+
### Google Sheets API Reference (read-only)
|
|
408
399
|
|
|
409
|
-
#### Read Endpoints
|
|
410
400
|
- GET \`/{spreadsheetId}\` \u2014 Get spreadsheet metadata (title, sheets, properties)
|
|
411
401
|
- GET \`/{spreadsheetId}/values/{range}\` \u2014 Get cell values for a range
|
|
412
402
|
- GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 Get values for multiple ranges
|
|
413
403
|
|
|
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
|
-
|
|
420
404
|
### Range Notation (A1 notation)
|
|
421
405
|
- \`Sheet1!A1:D10\` \u2014 Specific range on Sheet1
|
|
422
406
|
- \`Sheet1!A:A\` \u2014 Entire column A on Sheet1
|
|
@@ -429,21 +413,17 @@ var googleSheetsConnector = new ConnectorPlugin({
|
|
|
429
413
|
- Use \`valueRenderOption=FORMATTED_VALUE\` query param to get display values
|
|
430
414
|
- Use \`valueRenderOption=UNFORMATTED_VALUE\` for raw numeric values
|
|
431
415
|
- 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
|
|
434
416
|
|
|
435
417
|
### Business Logic
|
|
436
418
|
|
|
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.
|
|
419
|
+
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. The spreadsheet ID is bound to the connection at setup time; do NOT ask handler callers to pass it.
|
|
438
420
|
|
|
439
421
|
SDK surface (client created via \`connection(connectionId)\`):
|
|
440
|
-
- \`client.
|
|
441
|
-
- \`client.
|
|
442
|
-
- \`client.
|
|
443
|
-
- \`client.
|
|
444
|
-
- \`client.
|
|
445
|
-
- \`client.appendValues(spreadsheetId, range, values)\` \u2014 append rows after the last row.
|
|
446
|
-
- \`client.createSpreadsheet(title, sheetNames?)\` \u2014 create a new spreadsheet.
|
|
422
|
+
- \`client.spreadsheetId\` \u2014 the spreadsheet ID configured for this connection.
|
|
423
|
+
- \`client.request(path, init?)\` \u2014 low-level authenticated fetch (\`path\` is appended to \`https://sheets.googleapis.com/v4/spreadsheets\`; \`{spreadsheetId}\` is auto-replaced).
|
|
424
|
+
- \`client.getSpreadsheet()\` \u2014 fetch spreadsheet metadata for the configured spreadsheet.
|
|
425
|
+
- \`client.getValues(range)\` \u2014 read a range (A1 notation) from the configured spreadsheet.
|
|
426
|
+
- \`client.batchGetValues(ranges)\` \u2014 read multiple ranges from the configured spreadsheet.
|
|
447
427
|
|
|
448
428
|
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.
|
|
449
429
|
|
|
@@ -454,43 +434,31 @@ import { connection } from "@squadbase/vite-server/connectors/google-sheets";
|
|
|
454
434
|
|
|
455
435
|
const sheets = connection("<connectionId>");
|
|
456
436
|
|
|
457
|
-
//
|
|
458
|
-
const
|
|
459
|
-
const spreadsheetId = newSheet.spreadsheetId;
|
|
460
|
-
|
|
461
|
-
// Get spreadsheet metadata
|
|
462
|
-
const metadata = await sheets.getSpreadsheet(spreadsheetId);
|
|
437
|
+
// Get metadata for the configured spreadsheet
|
|
438
|
+
const metadata = await sheets.getSpreadsheet();
|
|
463
439
|
console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
|
|
464
440
|
|
|
465
441
|
// Get cell values
|
|
466
|
-
const values = await sheets.getValues(
|
|
442
|
+
const values = await sheets.getValues("Sheet1!A1:D10");
|
|
467
443
|
console.log(values.values); // 2D array
|
|
468
444
|
|
|
469
|
-
//
|
|
470
|
-
await sheets.
|
|
471
|
-
|
|
472
|
-
// Append rows
|
|
473
|
-
await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie", "88"]]);
|
|
445
|
+
// Batch-get multiple ranges
|
|
446
|
+
const batch = await sheets.batchGetValues(["Sheet1!A:A", "Sheet2!B2:C100"]);
|
|
474
447
|
\`\`\``,
|
|
475
448
|
ja: `### \u30C4\u30FC\u30EB\uFF08\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306E\u307F\uFF09
|
|
476
449
|
|
|
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\
|
|
450
|
+
- \`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\u5C02\u7528\uFF08GET \u306E\u307F\uFF09\u3067\u3059\u3002\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u3084\u30BB\u30EB\u5024\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u30D1\u30B9\u5185\u306E \`{spreadsheetId}\` \u30D7\u30EC\u30FC\u30B9\u30DB\u30EB\u30C0\u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306B\u6307\u5B9A\u3055\u308C\u305F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u306B\u81EA\u52D5\u7684\u306B\u7F6E\u63DB\u3055\u308C\u307E\u3059\u3002OAuth \u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
|
|
478
451
|
|
|
479
452
|
> **\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
|
|
480
453
|
|
|
481
|
-
|
|
454
|
+
> **\u63A5\u7D9A\u30B9\u30B3\u30FC\u30D7**: \u5404\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306BURL\u3067\u6307\u5B9A\u3055\u308C\u305F1\u3064\u306E\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306B\u7D10\u3065\u304D\u307E\u3059\u3002\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u4F5C\u6210\u3084\u66F8\u304D\u8FBC\u307F\u306F\u884C\u3044\u307E\u305B\u3093\u3002OAuth \u30B9\u30B3\u30FC\u30D7\u306F \`spreadsheets.readonly\` \u3067\u3059\u3002
|
|
455
|
+
|
|
456
|
+
### Google Sheets API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\uFF08\u8AAD\u307F\u53D6\u308A\u5C02\u7528\uFF09
|
|
482
457
|
|
|
483
|
-
#### \u8AAD\u307F\u53D6\u308A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
484
458
|
- 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
|
|
485
459
|
- GET \`/{spreadsheetId}/values/{range}\` \u2014 \u7BC4\u56F2\u306E\u30BB\u30EB\u5024\u3092\u53D6\u5F97
|
|
486
460
|
- GET \`/{spreadsheetId}/values:batchGet?ranges={range1}&ranges={range2}\` \u2014 \u8907\u6570\u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97
|
|
487
461
|
|
|
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
|
-
|
|
494
462
|
### \u7BC4\u56F2\u306E\u8868\u8A18\u6CD5\uFF08A1\u8868\u8A18\u6CD5\uFF09
|
|
495
463
|
- \`Sheet1!A1:D10\` \u2014 Sheet1\u4E0A\u306E\u7279\u5B9A\u7BC4\u56F2
|
|
496
464
|
- \`Sheet1!A:A\` \u2014 Sheet1\u306EA\u5217\u5168\u4F53
|
|
@@ -503,21 +471,17 @@ await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie"
|
|
|
503
471
|
- \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
|
|
504
472
|
- \u751F\u306E\u6570\u5024\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F \`valueRenderOption=UNFORMATTED_VALUE\` \u3092\u4F7F\u7528\u3057\u307E\u3059
|
|
505
473
|
- \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
|
|
508
474
|
|
|
509
475
|
### Business Logic
|
|
510
476
|
|
|
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
|
|
477
|
+
\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\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u306F\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u6642\u306B\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306B\u7D10\u3065\u3051\u3089\u308C\u3066\u3044\u308B\u306E\u3067\u3001\u30CF\u30F3\u30C9\u30E9\u306E\u547C\u3073\u51FA\u3057\u5143\u306B\u6E21\u3055\u305B\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
512
478
|
|
|
513
479
|
SDK\uFF08\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\uFF09:
|
|
514
|
-
- \`client.
|
|
515
|
-
- \`client.
|
|
516
|
-
- \`client.
|
|
517
|
-
- \`client.
|
|
518
|
-
- \`client.
|
|
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
|
|
480
|
+
- \`client.spreadsheetId\` \u2014 \u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306B\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8ID\u3002
|
|
481
|
+
- \`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\u3001\`{spreadsheetId}\` \u306F\u81EA\u52D5\u7F6E\u63DB\u3055\u308C\u307E\u3059\uFF09\u3002
|
|
482
|
+
- \`client.getSpreadsheet()\` \u2014 \u8A2D\u5B9A\u6E08\u307F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3002
|
|
483
|
+
- \`client.getValues(range)\` \u2014 \u8A2D\u5B9A\u6E08\u307F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97\uFF08A1 \u8868\u8A18\uFF09\u3002
|
|
484
|
+
- \`client.batchGetValues(ranges)\` \u2014 \u8A2D\u5B9A\u6E08\u307F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u8907\u6570\u7BC4\u56F2\u306E\u5024\u3092\u53D6\u5F97\u3002
|
|
521
485
|
|
|
522
486
|
\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
|
|
523
487
|
|
|
@@ -528,23 +492,16 @@ import { connection } from "@squadbase/vite-server/connectors/google-sheets";
|
|
|
528
492
|
|
|
529
493
|
const sheets = connection("<connectionId>");
|
|
530
494
|
|
|
531
|
-
// \
|
|
532
|
-
const
|
|
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);
|
|
495
|
+
// \u8A2D\u5B9A\u6E08\u307F\u30B9\u30D7\u30EC\u30C3\u30C9\u30B7\u30FC\u30C8\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u53D6\u5F97
|
|
496
|
+
const metadata = await sheets.getSpreadsheet();
|
|
537
497
|
console.log(metadata.properties.title, metadata.sheets.map(s => s.properties.title));
|
|
538
498
|
|
|
539
499
|
// \u30BB\u30EB\u5024\u3092\u53D6\u5F97
|
|
540
|
-
const values = await sheets.getValues(
|
|
500
|
+
const values = await sheets.getValues("Sheet1!A1:D10");
|
|
541
501
|
console.log(values.values); // 2D array
|
|
542
502
|
|
|
543
|
-
// \
|
|
544
|
-
await sheets.
|
|
545
|
-
|
|
546
|
-
// \u884C\u3092\u8FFD\u52A0
|
|
547
|
-
await sheets.appendValues(spreadsheetId, "Sheet1!A1", [["Bob", "95"], ["Charlie", "88"]]);
|
|
503
|
+
// \u8907\u6570\u7BC4\u56F2\u3092\u30D0\u30C3\u30C1\u53D6\u5F97
|
|
504
|
+
const batch = await sheets.batchGetValues(["Sheet1!A:A", "Sheet2!B2:C100"]);
|
|
548
505
|
\`\`\``
|
|
549
506
|
},
|
|
550
507
|
tools
|
|
@@ -47,7 +47,7 @@ var parameters = {
|
|
|
47
47
|
url: new ParameterDefinition({
|
|
48
48
|
slug: "url",
|
|
49
49
|
name: "InfluxDB URL",
|
|
50
|
-
description: "The base URL of your InfluxDB instance (e.g., '
|
|
50
|
+
description: "The base URL of your InfluxDB instance. Do not include a trailing slash. Works with both InfluxDB 2 (e.g., InfluxDB Cloud on '*.cloud2.influxdata.com', OSS 2.x) and InfluxDB 3 (Cloud Serverless, Enterprise, OSS 3.x).",
|
|
51
51
|
envVarBaseKey: "INFLUXDB_URL",
|
|
52
52
|
type: "text",
|
|
53
53
|
secret: false,
|
|
@@ -74,7 +74,7 @@ var parameters = {
|
|
|
74
74
|
org: new ParameterDefinition({
|
|
75
75
|
slug: "org",
|
|
76
76
|
name: "Organization",
|
|
77
|
-
description: "The InfluxDB organization name. Required for InfluxDB 2
|
|
77
|
+
description: "The InfluxDB organization name. Required for InfluxDB 2 Flux queries and writes (including InfluxDB Cloud on '*.cloud2.influxdata.com'). Optional for InfluxDB 3 when only using SQL.",
|
|
78
78
|
envVarBaseKey: "INFLUXDB_ORG",
|
|
79
79
|
type: "text",
|
|
80
80
|
secret: false,
|
|
@@ -110,12 +110,21 @@ function createClient(params) {
|
|
|
110
110
|
return headers;
|
|
111
111
|
}
|
|
112
112
|
async function assertOk(res, label) {
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
if (res.ok) return;
|
|
114
|
+
const body = await res.text().catch(() => "(unreadable body)");
|
|
115
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
116
|
+
const isHtml = contentType.includes("text/html") || body.trimStart().startsWith("<");
|
|
117
|
+
const v3Endpoints = /* @__PURE__ */ new Set([
|
|
118
|
+
"querySql",
|
|
119
|
+
"queryInfluxql",
|
|
120
|
+
"writeLineProtocol"
|
|
121
|
+
]);
|
|
122
|
+
const looksLikeMissingV3 = (res.status === 405 || res.status === 404 || isHtml) && v3Endpoints.has(label);
|
|
123
|
+
const hint = looksLikeMissingV3 ? " \u2014 This InfluxDB instance does not support the v3 API at this path. It is likely InfluxDB 2 (e.g. InfluxDB Cloud on '*.cloud2.influxdata.com'). Use queryFlux() via '/api/v2/query?org={org}' instead." : isHtml ? " \u2014 Received HTML instead of a JSON/CSV API response; verify the URL points to the InfluxDB API host." : "";
|
|
124
|
+
const snippet = isHtml ? body.replace(/\s+/g, " ").slice(0, 200) : body;
|
|
125
|
+
throw new Error(
|
|
126
|
+
`influxdb ${label}: ${res.status} ${res.statusText}${hint} \u2014 ${snippet}`
|
|
127
|
+
);
|
|
119
128
|
}
|
|
120
129
|
return {
|
|
121
130
|
database,
|
|
@@ -345,11 +354,11 @@ var influxdbOnboarding = new ConnectorOnboarding({
|
|
|
345
354
|
|
|
346
355
|
#### Confirm the Database (or Bucket) Name
|
|
347
356
|
- InfluxDB 3: use the database name
|
|
348
|
-
- InfluxDB 2: use the bucket name (buckets act as databases in the v1/v3 compatibility endpoints)
|
|
357
|
+
- InfluxDB 2 (includes InfluxDB Cloud on \`*.cloud2.influxdata.com\`): use the bucket name (buckets act as databases in the v1/v3 compatibility endpoints)
|
|
349
358
|
|
|
350
|
-
#### Organization
|
|
351
|
-
-
|
|
352
|
-
-
|
|
359
|
+
#### Organization
|
|
360
|
+
- InfluxDB 2: set the Organization parameter to the org that owns the bucket (required for Flux queries and writes)
|
|
361
|
+
- InfluxDB 3 Cloud Serverless: you can leave Organization blank when only using SQL`,
|
|
353
362
|
ja: `#### API \u30C8\u30FC\u30AF\u30F3\u306E\u767A\u884C
|
|
354
363
|
1. InfluxDB Cloud / OSS \u306B\u30B5\u30A4\u30F3\u30A4\u30F3
|
|
355
364
|
2. Load Data \u2192 API Tokens \u2192 Generate API Token
|
|
@@ -358,19 +367,37 @@ var influxdbOnboarding = new ConnectorOnboarding({
|
|
|
358
367
|
|
|
359
368
|
#### Database (\u307E\u305F\u306F Bucket) \u540D\u306E\u78BA\u8A8D
|
|
360
369
|
- InfluxDB 3: database \u540D\u3092\u4F7F\u7528
|
|
361
|
-
- InfluxDB 2: bucket \u540D\u3092\u4F7F\u7528\uFF08v1/v3 \u4E92\u63DB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u306F bucket \u304C database \u3068\u3057\u3066\u6271\u308F\u308C\u308B\uFF09
|
|
370
|
+
- InfluxDB 2\uFF08\`*.cloud2.influxdata.com\` \u306E InfluxDB Cloud \u3092\u542B\u3080\uFF09: bucket \u540D\u3092\u4F7F\u7528\uFF08v1/v3 \u4E92\u63DB\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u306F bucket \u304C database \u3068\u3057\u3066\u6271\u308F\u308C\u308B\uFF09
|
|
362
371
|
|
|
363
|
-
#### Organization
|
|
364
|
-
- InfluxDB 2
|
|
365
|
-
- InfluxDB 3 Cloud \u306E\u5834\u5408\u306F\u7A7A\u306E\u307E\u307E\u3067\u554F\u984C\u306A\u3044`
|
|
372
|
+
#### Organization
|
|
373
|
+
- InfluxDB 2: bucket \u3092\u4FDD\u6709\u3059\u308B\u7D44\u7E54\u540D\u3092 Organization \u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u8A2D\u5B9A\uFF08Flux \u30AF\u30A8\u30EA\u3068\u66F8\u304D\u8FBC\u307F\u306B\u306F\u5FC5\u9808\uFF09
|
|
374
|
+
- InfluxDB 3 Cloud Serverless: SQL \u306E\u307F\u3092\u4F7F\u3046\u5834\u5408\u306F\u7A7A\u306E\u307E\u307E\u3067\u554F\u984C\u306A\u3044`
|
|
366
375
|
},
|
|
367
376
|
dataOverviewInstructions: {
|
|
368
|
-
en: `
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
377
|
+
en: `The instance may be either InfluxDB 3 (supports SQL) or InfluxDB 2 (Flux only; includes InfluxDB Cloud on '*.cloud2.influxdata.com'). Detect the variant first, then pick the matching endpoints.
|
|
378
|
+
|
|
379
|
+
1. Probe for InfluxDB 3: call influxdb_request with POST /api/v3/query_sql, body { "db": "<database>", "q": "SELECT 1" }
|
|
380
|
+
- 200 with JSON rows \u2192 InfluxDB 3. Continue with SQL.
|
|
381
|
+
- 405 Method Not Allowed, or an HTML body like "<html>...405 Not Allowed..." \u2192 InfluxDB 2. Fall back to Flux (step 3).
|
|
382
|
+
2. InfluxDB 3 data overview:
|
|
383
|
+
a. POST /api/v3/query_sql, body { "db": "<database>", "q": "SHOW TABLES" } to list measurements
|
|
384
|
+
b. POST /api/v3/query_sql, body { "db": "<database>", "q": "SELECT * FROM <measurement> ORDER BY time DESC LIMIT 5" } to inspect a sample
|
|
385
|
+
3. InfluxDB 2 data overview (Organization parameter required):
|
|
386
|
+
a. POST /api/v2/query?org=<org>, contentType 'application/vnd.flux', body 'buckets()' to list buckets
|
|
387
|
+
b. POST /api/v2/query?org=<org>, contentType 'application/vnd.flux', body 'from(bucket:"<bucket>") |> range(start: -1h) |> limit(n:5)' to inspect data
|
|
388
|
+
- If the Organization parameter was not provided but v3 probing failed, ask the user to set it using updateConnectionParameters before continuing.`,
|
|
389
|
+
ja: `\u63A5\u7D9A\u5148\u306F InfluxDB 3\uFF08SQL \u5BFE\u5FDC\uFF09\u3068 InfluxDB 2\uFF08Flux \u306E\u307F\u3002\`*.cloud2.influxdata.com\` \u306E InfluxDB Cloud \u3092\u542B\u3080\uFF09\u306E\u3069\u3061\u3089\u306E\u53EF\u80FD\u6027\u3082\u3042\u308A\u307E\u3059\u3002\u307E\u305A\u30D0\u30EA\u30A2\u30F3\u30C8\u3092\u5224\u5225\u3057\u3001\u305D\u308C\u306B\u5408\u3046\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
390
|
+
|
|
391
|
+
1. InfluxDB 3 \u306E\u5224\u5225: influxdb_request \u3067 POST /api/v3/query_sql\u3001body { "db": "<database>", "q": "SELECT 1" } \u3092\u5B9F\u884C
|
|
392
|
+
- 200 + JSON \u884C\u304C\u8FD4\u308B \u2192 InfluxDB 3\u3002\u305D\u306E\u307E\u307E SQL \u3067\u7D9A\u884C\u3002
|
|
393
|
+
- 405 Method Not Allowed\u3001\u307E\u305F\u306F "<html>...405 Not Allowed..." \u306E\u3088\u3046\u306A HTML \u672C\u6587\u304C\u8FD4\u308B \u2192 InfluxDB 2\u3002Flux \u306B\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\uFF08\u624B\u9806 3\uFF09\u3002
|
|
394
|
+
2. InfluxDB 3 \u306E\u5834\u5408\u306E\u30C7\u30FC\u30BF\u6982\u8981:
|
|
395
|
+
a. POST /api/v3/query_sql\u3001body { "db": "<database>", "q": "SHOW TABLES" } \u3067 measurement \u4E00\u89A7\u3092\u53D6\u5F97
|
|
396
|
+
b. POST /api/v3/query_sql\u3001body { "db": "<database>", "q": "SELECT * FROM <measurement> ORDER BY time DESC LIMIT 5" } \u3067\u4EE3\u8868\u7684\u306A measurement \u3092\u78BA\u8A8D
|
|
397
|
+
3. InfluxDB 2 \u306E\u5834\u5408\u306E\u30C7\u30FC\u30BF\u6982\u8981\uFF08Organization \u30D1\u30E9\u30E1\u30FC\u30BF\u5FC5\u9808\uFF09:
|
|
398
|
+
a. POST /api/v2/query?org=<org>\u3001contentType 'application/vnd.flux'\u3001body 'buckets()' \u3067 bucket \u4E00\u89A7\u3092\u53D6\u5F97
|
|
399
|
+
b. POST /api/v2/query?org=<org>\u3001contentType 'application/vnd.flux'\u3001body 'from(bucket:"<bucket>") |> range(start: -1h) |> limit(n:5)' \u3067\u30C7\u30FC\u30BF\u3092\u78BA\u8A8D
|
|
400
|
+
- Organization \u30D1\u30E9\u30E1\u30FC\u30BF\u304C\u672A\u8A2D\u5B9A\u3067 v3 \u5224\u5225\u3082\u5931\u6557\u3057\u305F\u5834\u5408\u306F\u3001updateConnectionParameters \u3067\u30E6\u30FC\u30B6\u30FC\u306B\u8A2D\u5B9A\u3092\u4FC3\u3057\u3066\u304B\u3089\u7D9A\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
374
401
|
}
|
|
375
402
|
});
|
|
376
403
|
|
|
@@ -458,10 +485,17 @@ For read-only data exploration prefer SQL (InfluxDB 3) or InfluxQL queries \u201
|
|
|
458
485
|
}
|
|
459
486
|
if (!response.ok) {
|
|
460
487
|
let errorMessage = `HTTP ${response.status} ${response.statusText}`;
|
|
488
|
+
const bodyText = typeof data === "string" ? data : void 0;
|
|
489
|
+
const isHtml = resContentType.includes("text/html") || bodyText !== void 0 && bodyText.trimStart().startsWith("<");
|
|
461
490
|
if (data && typeof data === "object" && !Array.isArray(data) && typeof data.message === "string") {
|
|
462
491
|
errorMessage = data.message;
|
|
463
|
-
} else if (
|
|
464
|
-
errorMessage =
|
|
492
|
+
} else if (bodyText) {
|
|
493
|
+
errorMessage = isHtml ? bodyText.replace(/\s+/g, " ").slice(0, 200) : bodyText;
|
|
494
|
+
}
|
|
495
|
+
const hitsV3Path = path2.includes("/api/v3/");
|
|
496
|
+
const looksLikeMissingV3 = hitsV3Path && (response.status === 405 || response.status === 404 || isHtml);
|
|
497
|
+
if (looksLikeMissingV3) {
|
|
498
|
+
errorMessage += " \u2014 This InfluxDB instance does not support the v3 API at this path. It is likely InfluxDB 2 (e.g. InfluxDB Cloud on '*.cloud2.influxdata.com'). Retry via Flux on '/api/v2/query?org={org}' with contentType 'application/vnd.flux'.";
|
|
465
499
|
}
|
|
466
500
|
return { success: false, error: errorMessage };
|
|
467
501
|
}
|
|
@@ -483,14 +517,22 @@ var influxdbConnector = new ConnectorPlugin({
|
|
|
483
517
|
authType: AUTH_TYPES.API_KEY,
|
|
484
518
|
name: "InfluxDB",
|
|
485
519
|
description: "Connect to InfluxDB (Cloud or OSS) to query time-series data with SQL, InfluxQL, or Flux and to write line protocol.",
|
|
486
|
-
iconUrl: "https://
|
|
520
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/J1JauVRNmahSVTVrpPfQK/18350d8d3f2dc3be25e8e36ee52914a0/influxdb.png",
|
|
487
521
|
parameters,
|
|
488
522
|
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
489
523
|
onboarding: influxdbOnboarding,
|
|
490
524
|
systemPrompt: {
|
|
491
|
-
en: `###
|
|
525
|
+
en: `### Variant Detection
|
|
492
526
|
|
|
493
|
-
|
|
527
|
+
The configured instance may be **InfluxDB 3** (supports SQL via \`/api/v3/query_sql\`) or **InfluxDB 2** (Flux only; includes InfluxDB Cloud on \`*.cloud2.influxdata.com\`). Always probe first, then use the matching endpoints:
|
|
528
|
+
|
|
529
|
+
1. Call \`influxdb_request\` POST \`/api/v3/query_sql\` with body \`{ "db": "<database>", "q": "SELECT 1" }\`
|
|
530
|
+
2. 200 + JSON rows \u2192 InfluxDB 3. Use SQL endpoints.
|
|
531
|
+
3. 405 Method Not Allowed or HTML body (e.g. \`<html>...405 Not Allowed...</html>\`) \u2192 InfluxDB 2. Use Flux via \`/api/v2/query?org={org}\`. Require the \`org\` parameter; if missing, ask the user via \`updateConnectionParameters\`.
|
|
532
|
+
|
|
533
|
+
### Tools
|
|
534
|
+
|
|
535
|
+
- \`influxdb_request\`: The only way to call the InfluxDB HTTP API. Use it to run SQL / InfluxQL / Flux queries, write line protocol, and inspect buckets / databases. Authentication (\`Authorization: Token {token}\`) and the instance URL are configured automatically. On InfluxDB 3 prefer SQL (\`POST /api/v3/query_sql\`) \u2014 it returns JSON rows that are directly usable. On InfluxDB 2 use Flux (\`POST /api/v2/query?org={org}\`) \u2014 the response is annotated CSV. Writes use \`POST /api/v3/write_lp?db={db}\` (v3) or \`POST /api/v2/write?org={org}&bucket={bucket}\` (v2) with a line-protocol body and \`contentType\` set to \`text/plain; charset=utf-8\`.
|
|
494
536
|
|
|
495
537
|
### Business Logic
|
|
496
538
|
|
|
@@ -551,7 +593,15 @@ export default async function handler(c: Context) {
|
|
|
551
593
|
- Time filtering uses standard SQL \`time\` column comparisons (\`time >= now() - INTERVAL '...' \`)
|
|
552
594
|
- Aggregates: \`AVG\`, \`SUM\`, \`MIN\`, \`MAX\`, \`COUNT\`; bucket time with \`date_bin('5 minutes', time)\`
|
|
553
595
|
- List measurements: \`SHOW TABLES\`; list columns: \`SHOW COLUMNS FROM <measurement>\``,
|
|
554
|
-
ja: `### \
|
|
596
|
+
ja: `### \u30D0\u30EA\u30A2\u30F3\u30C8\u5224\u5225
|
|
597
|
+
|
|
598
|
+
\u63A5\u7D9A\u5148\u306F **InfluxDB 3**\uFF08\`/api/v3/query_sql\` \u306E SQL \u5BFE\u5FDC\uFF09\u3068 **InfluxDB 2**\uFF08Flux \u306E\u307F\u3002\`*.cloud2.influxdata.com\` \u306E InfluxDB Cloud \u3092\u542B\u3080\uFF09\u306E\u3069\u3061\u3089\u306E\u53EF\u80FD\u6027\u3082\u3042\u308A\u307E\u3059\u3002\u5FC5\u305A\u6700\u521D\u306B\u30D7\u30ED\u30FC\u30D6\u3057\u3066\u304B\u3089\u3001\u5BFE\u5FDC\u3059\u308B\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044:
|
|
599
|
+
|
|
600
|
+
1. \`influxdb_request\` \u3067 POST \`/api/v3/query_sql\`\u3001body \`{ "db": "<database>", "q": "SELECT 1" }\` \u3092\u547C\u3073\u51FA\u3059
|
|
601
|
+
2. 200 + JSON \u884C \u2192 InfluxDB 3\u3002SQL \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3092\u4F7F\u7528\u3002
|
|
602
|
+
3. 405 Method Not Allowed\u3001\u307E\u305F\u306F HTML \u672C\u6587\uFF08\u4F8B: \`<html>...405 Not Allowed...</html>\`\uFF09\u2192 InfluxDB 2\u3002\`/api/v2/query?org={org}\` \u304B\u3089 Flux \u3092\u4F7F\u7528\u3002\`org\` \u30D1\u30E9\u30E1\u30FC\u30BF\u5FC5\u9808\u3002\u672A\u8A2D\u5B9A\u306A\u3089 \`updateConnectionParameters\` \u3067\u30E6\u30FC\u30B6\u30FC\u306B\u8A2D\u5B9A\u3092\u4F9D\u983C\u3059\u308B\u3002
|
|
603
|
+
|
|
604
|
+
### \u30C4\u30FC\u30EB
|
|
555
605
|
|
|
556
606
|
- \`influxdb_request\`: InfluxDB HTTP API \u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002SQL / InfluxQL / Flux \u30AF\u30A8\u30EA\u306E\u5B9F\u884C\u3001line protocol \u66F8\u304D\u8FBC\u307F\u3001bucket / database \u306E\u78BA\u8A8D\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08\`Authorization: Token {token}\`\uFF09\u3068 instance URL \u306F\u81EA\u52D5\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002InfluxDB 3 \u3067\u306F SQL (\`POST /api/v3/query_sql\`) \u304C JSON \u884C\u3092\u8FD4\u3059\u305F\u3081\u6700\u3082\u6271\u3044\u3084\u3059\u3044\u3067\u3059\u3002InfluxDB 2 \u3067\u306F Flux (\`POST /api/v2/query?org={org}\`) \u3092\u4F7F\u7528\u3057\u3001\u30EC\u30B9\u30DD\u30F3\u30B9\u306F\u6CE8\u91C8\u4ED8\u304D CSV \u3067\u3059\u3002\u66F8\u304D\u8FBC\u307F\u306F \`POST /api/v3/write_lp?db={db}\` (v3) \u307E\u305F\u306F \`POST /api/v2/write?org={org}&bucket={bucket}\` (v2) \u306B line protocol \u3092\u9001\u308A\u307E\u3059\uFF08\`contentType\` \u306F \`text/plain; charset=utf-8\`\uFF09\u3002
|
|
557
607
|
|
|
@@ -615,7 +665,47 @@ export default async function handler(c: Context) {
|
|
|
615
665
|
- \u96C6\u8A08: \`AVG\`, \`SUM\`, \`MIN\`, \`MAX\`, \`COUNT\`\u3002\u6642\u9593\u30D0\u30B1\u30C3\u30C8: \`date_bin('5 minutes', time)\`
|
|
616
666
|
- measurement \u4E00\u89A7: \`SHOW TABLES\`\u3001\u5217\u4E00\u89A7: \`SHOW COLUMNS FROM <measurement>\``
|
|
617
667
|
},
|
|
618
|
-
tools
|
|
668
|
+
tools,
|
|
669
|
+
async checkConnection(params) {
|
|
670
|
+
const url = (params.url ?? "").replace(/\/$/, "");
|
|
671
|
+
const token = params.token;
|
|
672
|
+
if (!url) {
|
|
673
|
+
return { success: false, error: "InfluxDB URL is not configured" };
|
|
674
|
+
}
|
|
675
|
+
if (!token) {
|
|
676
|
+
return { success: false, error: "API Token is not configured" };
|
|
677
|
+
}
|
|
678
|
+
try {
|
|
679
|
+
const res = await fetch(`${url}/api/v2/orgs`, {
|
|
680
|
+
method: "GET",
|
|
681
|
+
headers: {
|
|
682
|
+
Authorization: `Token ${token}`,
|
|
683
|
+
Accept: "application/json"
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
if (res.status === 401 || res.status === 403) {
|
|
687
|
+
return {
|
|
688
|
+
success: false,
|
|
689
|
+
error: `Authentication failed (HTTP ${res.status}). Check the API token and its permissions.`
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
if (!res.ok) {
|
|
693
|
+
const body = await res.text().catch(() => res.statusText);
|
|
694
|
+
const snippet = body.replace(/\s+/g, " ").slice(0, 200);
|
|
695
|
+
return {
|
|
696
|
+
success: false,
|
|
697
|
+
error: `Connection check failed: HTTP ${res.status} ${res.statusText} \u2014 ${snippet}`
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
return { success: true };
|
|
701
|
+
} catch (error) {
|
|
702
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
703
|
+
return {
|
|
704
|
+
success: false,
|
|
705
|
+
error: `Failed to reach InfluxDB at ${url}: ${message}`
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
619
709
|
});
|
|
620
710
|
|
|
621
711
|
// src/connectors/create-connector-sdk.ts
|