@squadbase/vite-server 0.1.3-dev.9 → 0.1.4-dev.0

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 +14539 -29447
  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 +522 -118
  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 +4574 -3863
  58. package/dist/main.js +4572 -3862
  59. package/dist/vite-plugin.js +4572 -3862
  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
@@ -61,6 +61,15 @@ var parameters = {
61
61
  type: "text",
62
62
  secret: true,
63
63
  required: true
64
+ }),
65
+ appId: new ParameterDefinition({
66
+ slug: "app-id",
67
+ name: "kintone App ID",
68
+ description: "The numeric ID of the kintone app this token is scoped to (visible in the app URL: https://{subdomain}.cybozu.com/k/{appId}/). API tokens are always scoped to a single app.",
69
+ envVarBaseKey: "KINTONE_APP_ID",
70
+ type: "text",
71
+ secret: false,
72
+ required: true
64
73
  })
65
74
  };
66
75
 
@@ -68,19 +77,58 @@ var parameters = {
68
77
  function createClient(params) {
69
78
  const baseUrl = params[parameters.baseUrl.slug];
70
79
  const apiToken = params[parameters.apiToken.slug];
71
- if (!baseUrl || !apiToken) {
72
- const required = [parameters.baseUrl.slug, parameters.apiToken.slug];
73
- const missing = required.filter((s) => !params[s]);
80
+ const appId = params[parameters.appId.slug];
81
+ const required = [
82
+ parameters.baseUrl.slug,
83
+ parameters.apiToken.slug,
84
+ parameters.appId.slug
85
+ ];
86
+ const missing = required.filter((s) => !params[s]);
87
+ if (missing.length > 0) {
74
88
  throw new Error(
75
89
  `kintone: missing required parameters: ${missing.join(", ")}`
76
90
  );
77
91
  }
92
+ let _restClient = null;
93
+ async function getRestClient() {
94
+ if (!_restClient) {
95
+ const { KintoneRestAPIClient } = await import("@kintone/rest-api-client");
96
+ _restClient = new KintoneRestAPIClient({
97
+ baseUrl,
98
+ auth: { apiToken }
99
+ });
100
+ }
101
+ return _restClient;
102
+ }
78
103
  return {
104
+ appId,
79
105
  request(path2, init) {
80
106
  const url = `${baseUrl.replace(/\/+$/, "")}${path2}`;
81
107
  const headers = new Headers(init?.headers);
82
108
  headers.set("X-Cybozu-API-Token", apiToken);
83
109
  return fetch(url, { ...init, headers });
110
+ },
111
+ async getRecords(targetAppId, options) {
112
+ const client = await getRestClient();
113
+ const result = await client.record.getRecords({
114
+ app: targetAppId ?? appId,
115
+ query: options?.query,
116
+ fields: options?.fields,
117
+ totalCount: options?.totalCount
118
+ });
119
+ return {
120
+ records: result.records,
121
+ totalCount: result.totalCount ? Number(result.totalCount) : null
122
+ };
123
+ },
124
+ async getRecord(appIdOrRecordId, recordId) {
125
+ const client = await getRestClient();
126
+ const [targetAppId, targetRecordId] = recordId === void 0 ? [appId, appIdOrRecordId] : [appIdOrRecordId, recordId];
127
+ const result = await client.record.getRecord({
128
+ app: targetAppId,
129
+ id: targetRecordId
130
+ });
131
+ return { record: result.record };
84
132
  }
85
133
  };
86
134
  }
@@ -167,21 +215,58 @@ var ConnectorPlugin = class _ConnectorPlugin {
167
215
  * Filters connections by connectorKey internally.
168
216
  * Returns tools keyed as `${connectorKey}_${toolName}`.
169
217
  */
170
- createTools(connections, config) {
218
+ createTools(connections, config, opts) {
171
219
  const myConnections = connections.filter(
172
220
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
173
221
  );
174
222
  const result = {};
175
223
  for (const t of Object.values(this.tools)) {
176
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
177
- myConnections,
178
- config
179
- );
224
+ const tool = t.createTool(myConnections, config);
225
+ const originalToModelOutput = tool.toModelOutput;
226
+ result[`${this.connectorKey}_${t.name}`] = {
227
+ ...tool,
228
+ toModelOutput: async (options) => {
229
+ if (!originalToModelOutput) {
230
+ return opts.truncateOutput(options.output);
231
+ }
232
+ const modelOutput = await originalToModelOutput(options);
233
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
234
+ return opts.truncateOutput(modelOutput.value);
235
+ }
236
+ return modelOutput;
237
+ }
238
+ };
180
239
  }
181
240
  return result;
182
241
  }
183
242
  static deriveKey(slug, authType) {
184
- return authType ? `${slug}-${authType}` : slug;
243
+ if (authType) return `${slug}-${authType}`;
244
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
245
+ // user-password
246
+ "postgresql": "user-password",
247
+ "mysql": "user-password",
248
+ "clickhouse": "user-password",
249
+ "kintone": "user-password",
250
+ "squadbase-db": "user-password",
251
+ // service-account
252
+ "snowflake": "service-account",
253
+ "bigquery": "service-account",
254
+ "google-analytics": "service-account",
255
+ "google-calendar": "service-account",
256
+ "aws-athena": "service-account",
257
+ "redshift": "service-account",
258
+ // api-key
259
+ "databricks": "api-key",
260
+ "dbt": "api-key",
261
+ "airtable": "api-key",
262
+ "openai": "api-key",
263
+ "gemini": "api-key",
264
+ "anthropic": "api-key",
265
+ "wix-store": "api-key"
266
+ };
267
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
268
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
269
+ return slug;
185
270
  }
186
271
  };
187
272
 
@@ -198,23 +283,49 @@ var AUTH_TYPES = {
198
283
  // ../connectors/src/connectors/kintone-api-token/setup.ts
199
284
  var kintoneApiTokenOnboarding = new ConnectorOnboarding({
200
285
  dataOverviewInstructions: {
201
- en: `1. Call kintone-api-token_request with GET apps.json to list available apps
202
- 2. For key apps, call kintone-api-token_request with GET app/form/fields.json?app={appId} to get field definitions
203
- 3. Call kintone-api-token_request with GET records.json?app={appId}&query=limit 5 to sample records`,
204
- ja: `1. kintone-api-token_request \u3067 GET apps.json \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30A2\u30D7\u30EA\u4E00\u89A7\u3092\u53D6\u5F97
205
- 2. \u4E3B\u8981\u30A2\u30D7\u30EA\u306B\u3064\u3044\u3066 kintone-api-token_request \u3067 GET app/form/fields.json?app={appId} \u3092\u547C\u3073\u51FA\u3057\u3001\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u3092\u53D6\u5F97
206
- 3. kintone-api-token_request \u3067 GET records.json?app={appId}&query=limit 5 \u3092\u547C\u3073\u51FA\u3057\u3001\u30EC\u30B3\u30FC\u30C9\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0`
286
+ en: `Each connection is scoped to a single kintone app (configured via the "app-id" parameter). The request tool auto-injects the configured app id, so you do NOT need to specify "app=" in paths or "app" in bodies. apps.json is NOT available with API Token auth.
287
+
288
+ 1. Call kintone-api-key_request with GET app.json to fetch the scoped app's metadata (name, description, creator)
289
+ 2. Call kintone-api-key_request with GET app/form/fields.json to get field definitions
290
+ 3. Call kintone-api-key_request with GET records.json with query=limit 5 to sample records`,
291
+ ja: `\u5404\u63A5\u7D9A\u306F1\u3064\u306Ekintone\u30A2\u30D7\u30EA\u306B\u30B9\u30B3\u30FC\u30D7\u3055\u308C\u3066\u3044\u307E\u3059\uFF08"app-id" \u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u8A2D\u5B9A\uFF09\u3002request \u30C4\u30FC\u30EB\u306F\u8A2D\u5B9A\u3055\u308C\u305F\u30A2\u30D7\u30EAID\u3092\u81EA\u52D5\u6CE8\u5165\u3059\u308B\u305F\u3081\u3001\u30D1\u30B9\u306B "app=" \u3084 body \u306B "app" \u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u306F\u3042\u308A\u307E\u305B\u3093\u3002API Token \u8A8D\u8A3C\u3067\u306F apps.json \u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002
292
+
293
+ 1. kintone-api-key_request \u3067 GET app.json \u3092\u547C\u3073\u51FA\u3057\u3001\u30B9\u30B3\u30FC\u30D7\u5BFE\u8C61\u30A2\u30D7\u30EA\u306E\u30E1\u30BF\u60C5\u5831\uFF08\u30A2\u30D7\u30EA\u540D\u3001\u8AAC\u660E\u3001\u4F5C\u6210\u8005\uFF09\u3092\u53D6\u5F97
294
+ 2. kintone-api-key_request \u3067 GET app/form/fields.json \u3092\u547C\u3073\u51FA\u3057\u3001\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u3092\u53D6\u5F97
295
+ 3. kintone-api-key_request \u3067 GET records.json \u3092 query=limit 5 \u3067\u547C\u3073\u51FA\u3057\u3001\u30EC\u30B3\u30FC\u30C9\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0`
207
296
  }
208
297
  });
209
298
 
210
299
  // ../connectors/src/connectors/kintone-api-token/tools/request.ts
211
300
  import { z } from "zod";
212
301
  var REQUEST_TIMEOUT_MS = 6e4;
302
+ var APP_PARAM_KEY_BY_ENDPOINT = {
303
+ "app.json": "id"
304
+ };
305
+ var DEFAULT_APP_PARAM_KEY = "app";
306
+ function injectAppIntoPath(path2, appId) {
307
+ const [head, query = ""] = path2.split("?", 2);
308
+ const endpoint = head.toLowerCase();
309
+ const paramKey = APP_PARAM_KEY_BY_ENDPOINT[endpoint] ?? DEFAULT_APP_PARAM_KEY;
310
+ const params = new URLSearchParams(query);
311
+ if (!params.has(paramKey)) {
312
+ params.set(paramKey, appId);
313
+ }
314
+ const serialized = params.toString();
315
+ return serialized ? `${head}?${serialized}` : head;
316
+ }
317
+ function injectAppIntoBody(body, appId) {
318
+ if (!body) return body;
319
+ if ("app" in body) return body;
320
+ return { app: appId, ...body };
321
+ }
213
322
  var inputSchema = z.object({
214
323
  toolUseIntent: z.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
215
324
  connectionId: z.string().describe("ID of the kintone connection to use"),
216
325
  method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
217
- path: z.string().describe("API path (e.g., 'apps.json', 'records.json?app=1&query=...')"),
326
+ path: z.string().describe(
327
+ "API path (e.g., 'app.json', 'app/form/fields.json', 'records.json?query=limit 5'). The connection's app id is auto-injected; you do not need to include 'app=' in the query string. 'apps.json' is not supported with API Token auth."
328
+ ),
218
329
  body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON)")
219
330
  });
220
331
  var outputSchema = z.discriminatedUnion("success", [
@@ -243,20 +354,31 @@ Authentication is handled automatically using the API token.`,
243
354
  try {
244
355
  const baseUrl = parameters.baseUrl.getValue(connection2);
245
356
  const apiToken = parameters.apiToken.getValue(connection2);
246
- const url = `${baseUrl.replace(/\/+$/, "")}/k/v1/${path2}`;
357
+ const appId = parameters.appId.getValue(connection2);
358
+ const normalizedPath = path2.replace(/^\/+/, "");
359
+ const pathHead = normalizedPath.split("?")[0] ?? "";
360
+ if (/^apps\.json$/i.test(pathHead)) {
361
+ return {
362
+ success: false,
363
+ error: `kintone API tokens are scoped to a single app and cannot list apps. This connection is scoped to app ${appId}. Use app-specific endpoints (e.g., app.json, app/form/fields.json, records.json).`
364
+ };
365
+ }
366
+ const injectedPath = injectAppIntoPath(normalizedPath, appId);
367
+ const injectedBody = injectAppIntoBody(body, appId);
368
+ const url = `${baseUrl.replace(/\/+$/, "")}/k/v1/${injectedPath}`;
247
369
  const controller = new AbortController();
248
370
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
249
371
  try {
250
372
  const headers = {
251
373
  "X-Cybozu-API-Token": apiToken
252
374
  };
253
- if (body) {
375
+ if (injectedBody) {
254
376
  headers["Content-Type"] = "application/json";
255
377
  }
256
378
  const response = await fetch(url, {
257
379
  method,
258
380
  headers,
259
- body: body ? JSON.stringify(body) : void 0,
381
+ body: injectedBody ? JSON.stringify(injectedBody) : void 0,
260
382
  signal: controller.signal
261
383
  });
262
384
  const data = await response.json();
@@ -291,98 +413,150 @@ var kintoneApiTokenConnector = new ConnectorPlugin({
291
413
  systemPrompt: {
292
414
  en: `### Tools
293
415
 
294
- - \`kintone-api-key_request\`: The only way to call the kintone REST API. Use it to list apps, get field definitions, query records, and create/update records. Authentication (API Token) and base URL are configured automatically. API tokens are scoped per app \u2014 combine multiple tokens with commas to access multiple apps.
416
+ - \`kintone-api-key_request\`: The only way to call the kintone REST API. Use it to fetch app metadata/field definitions and read/write records. Authentication (API Token), base URL, and the connection's app id are configured automatically. Each connection is scoped to exactly one app (kintone API tokens are per-app).
295
417
 
296
- ### kintone REST API Reference
418
+ ### App scoping (important)
297
419
 
298
- #### List Apps
299
- - GET apps.json
300
-
301
- ### Get Field Definitions
302
- - GET app/form/fields.json?app={appId}
303
-
304
- ### Get Records
305
- - GET records.json?app={appId}&query={query}
306
- - Query example: records.json?app=1&query=updatedTime > "2024-01-01" order by recordNumber asc limit 100
307
-
308
- #### Add Record
309
- - POST record.json
310
- - Body: { "app": 1, "record": { "fieldName": { "value": "value" } } }
311
-
312
- #### kintone Query Syntax
313
- - Comparison: fieldName = "value", fieldName > 100
314
- - Operators: and, or, not
315
- - Sort: order by fieldName asc/desc
316
- - Limit: limit 100 offset 0
317
- - String: like "partial match"
420
+ - Each connection is scoped to one app, configured via the "app-id" parameter.
421
+ - The request tool auto-injects the configured app id:
422
+ - Query string: adds \`app=<appId>\` to paths like \`records.json\`, \`app/form/fields.json\`, etc. when missing. For \`app.json\` (app metadata), adds \`id=<appId>\` instead.
423
+ - Request body: adds \`"app": <appId>\` to POST/PUT bodies when missing.
424
+ - You do NOT need to include "app=" in paths or "app" in bodies \u2014 it is handled for you.
425
+ - \`apps.json\` (list all apps) is NOT callable with API Token auth.
318
426
 
319
427
  ### Business Logic
320
428
 
321
- 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.
429
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
322
430
 
323
- #### Example
431
+ SDK surface (client created via \`connection(connectionId)\`):
432
+ - \`client.appId\` \u2014 the numeric app id this connection is scoped to
433
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch (pass \`?app=\${client.appId}\` yourself)
434
+ - \`client.getRecords(appId?, options?)\` \u2014 fetch records; if \`appId\` is omitted, the connection's app id is used
435
+ - \`client.getRecord(appIdOrRecordId, recordId?)\` \u2014 fetch a single record; if called with one argument it is treated as the record id and the connection's app id is used
324
436
 
325
437
  \`\`\`ts
326
- import { connection } from "@squadbase/vite-server/connectors/kintone-api-key";
438
+ import type { Context } from "hono";
439
+ import { connection } from "@squadbase/vite-server/connectors/kintone-api-token";
327
440
 
328
441
  const kintone = connection("<connectionId>");
329
442
 
330
- // Authenticated fetch (returns standard Response)
331
- const res = await kintone.request("/k/v1/records.json?app=1&query=limit 10");
332
- const data = await res.json();
443
+ export default async function handler(c: Context) {
444
+ const { status = "Active" } = await c.req.json<{ status?: string }>();
445
+
446
+ const { records, totalCount } = await kintone.getRecords(undefined, {
447
+ query: \`status = "\${status}" order by updatedTime desc limit 100\`,
448
+ fields: ["$id", "name", "email", "status", "updatedTime"],
449
+ totalCount: true,
450
+ });
451
+
452
+ return c.json({
453
+ totalCount,
454
+ rows: records.map((r) => ({
455
+ id: r.$id.value,
456
+ name: r.name?.value,
457
+ email: r.email?.value,
458
+ status: r.status?.value,
459
+ updatedTime: r.updatedTime?.value,
460
+ })),
461
+ });
462
+ }
463
+ \`\`\`
333
464
 
334
- await kintone.request("/k/v1/record.json", {
335
- method: "POST",
336
- body: JSON.stringify({ app: 1, record: { title: { value: "Hello" } } }),
337
- });
338
- \`\`\``,
339
- ja: `### \u30C4\u30FC\u30EB
465
+ ### kintone REST API Reference
340
466
 
341
- - \`kintone-api-key_request\`: kintone REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97\u3001\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\u3001\u30EC\u30B3\u30FC\u30C9\u306E\u691C\u7D22\u3001\u30EC\u30B3\u30FC\u30C9\u306E\u4F5C\u6210\u30FB\u66F4\u65B0\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08API\u30C8\u30FC\u30AF\u30F3\uFF09\u3068\u30D9\u30FC\u30B9URL\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002API\u30C8\u30FC\u30AF\u30F3\u306F\u30A2\u30D7\u30EA\u3054\u3068\u306B\u30B9\u30B3\u30FC\u30D7\u3055\u308C\u3066\u3044\u307E\u3059 \u2014 \u8907\u6570\u306E\u30A2\u30D7\u30EA\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\u3067\u30C8\u30FC\u30AF\u30F3\u3092\u7D44\u307F\u5408\u308F\u305B\u3066\u304F\u3060\u3055\u3044\u3002
467
+ #### Get App Metadata
468
+ - \`GET app.json\` \u2192 returns { appId, name, description, createdAt, modifiedAt, creator, ... }
342
469
 
343
- ### kintone REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
470
+ #### Get Field Definitions
471
+ - \`GET app/form/fields.json\`
344
472
 
345
- #### \u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97
346
- - GET apps.json
473
+ #### Get Records
474
+ - \`GET records.json?query={query}\`
475
+ - Query example: \`records.json?query=updatedTime > "2024-01-01" order by recordNumber asc limit 100\`
347
476
 
348
- ### \u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97
349
- - GET app/form/fields.json?app={appId}
477
+ #### Add Record
478
+ - \`POST record.json\`
479
+ - Body: \`{ "record": { "fieldName": { "value": "value" } } }\`
350
480
 
351
- ### \u30EC\u30B3\u30FC\u30C9\u306E\u53D6\u5F97
352
- - GET records.json?app={appId}&query={query}
353
- - \u30AF\u30A8\u30EA\u4F8B: records.json?app=1&query=updatedTime > "2024-01-01" order by recordNumber asc limit 100
481
+ #### kintone Query Syntax
482
+ - Comparison: \`fieldName = "value"\`, \`fieldName > 100\`
483
+ - Operators: \`and\`, \`or\`, \`not\`
484
+ - Sort: \`order by fieldName asc/desc\`
485
+ - Limit: \`limit 100 offset 0\`
486
+ - String: \`like "partial match"\``,
487
+ ja: `### \u30C4\u30FC\u30EB
354
488
 
355
- #### \u30EC\u30B3\u30FC\u30C9\u306E\u8FFD\u52A0
356
- - POST record.json
357
- - Body: { "app": 1, "record": { "fieldName": { "value": "value" } } }
489
+ - \`kintone-api-key_request\`: kintone REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30A2\u30D7\u30EA\u306E\u30E1\u30BF\u60C5\u5831\u30FB\u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97\u3001\u30EC\u30B3\u30FC\u30C9\u306E\u8AAD\u307F\u66F8\u304D\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08API\u30C8\u30FC\u30AF\u30F3\uFF09\u3001\u30D9\u30FC\u30B9URL\u3001\u304A\u3088\u3073\u63A5\u7D9A\u306E\u30A2\u30D7\u30EAID\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002\u5404\u63A5\u7D9A\u306F\u3061\u3087\u3046\u30691\u3064\u306E\u30A2\u30D7\u30EA\u306B\u30B9\u30B3\u30FC\u30D7\u3055\u308C\u3066\u3044\u307E\u3059\uFF08kintone API\u30C8\u30FC\u30AF\u30F3\u306F\u30A2\u30D7\u30EA\u5358\u4F4D\u306E\u305F\u3081\uFF09\u3002
358
490
 
359
- #### kintone \u30AF\u30A8\u30EA\u69CB\u6587
360
- - \u6BD4\u8F03: fieldName = "value", fieldName > 100
361
- - \u6F14\u7B97\u5B50: and, or, not
362
- - \u30BD\u30FC\u30C8: order by fieldName asc/desc
363
- - \u5236\u9650: limit 100 offset 0
364
- - \u6587\u5B57\u5217: like "\u90E8\u5206\u4E00\u81F4"
491
+ ### \u30A2\u30D7\u30EA\u30B9\u30B3\u30FC\u30D7\uFF08\u91CD\u8981\uFF09
492
+
493
+ - \u5404\u63A5\u7D9A\u306F1\u3064\u306E\u30A2\u30D7\u30EA\u306B\u30B9\u30B3\u30FC\u30D7\u3055\u308C\u3066\u3044\u307E\u3059\uFF08"app-id" \u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u8A2D\u5B9A\uFF09\u3002
494
+ - request \u30C4\u30FC\u30EB\u306F\u8A2D\u5B9A\u3055\u308C\u305F\u30A2\u30D7\u30EAID\u3092\u81EA\u52D5\u6CE8\u5165\u3057\u307E\u3059:
495
+ - \u30AF\u30A8\u30EA\u6587\u5B57\u5217: \`records.json\` \u3084 \`app/form/fields.json\` \u7B49\u306E\u30D1\u30B9\u306B \`app=\` \u304C\u7121\u3051\u308C\u3070 \`app=<appId>\` \u3092\u4ED8\u4E0E\u3057\u307E\u3059\u3002\`app.json\`\uFF08\u30A2\u30D7\u30EA\u30E1\u30BF\u60C5\u5831\uFF09\u306E\u5834\u5408\u306F\u4EE3\u308F\u308A\u306B \`id=<appId>\` \u3092\u4ED8\u4E0E\u3057\u307E\u3059\u3002
496
+ - \u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3: POST/PUT \u306E\u30DC\u30C7\u30A3\u306B \`"app"\` \u304C\u7121\u3051\u308C\u3070\u81EA\u52D5\u7684\u306B\u8FFD\u52A0\u3057\u307E\u3059\u3002
497
+ - \u30D1\u30B9\u306B "app=" \u3084\u30DC\u30C7\u30A3\u306B "app" \u3092\u660E\u793A\u3059\u308B\u5FC5\u8981\u306F\u3042\u308A\u307E\u305B\u3093 \u2014 \u81EA\u52D5\u3067\u51E6\u7406\u3055\u308C\u307E\u3059\u3002
498
+ - \`apps.json\`\uFF08\u5168\u30A2\u30D7\u30EA\u4E00\u89A7\uFF09\u306F API Token \u8A8D\u8A3C\u3067\u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093\u3002
365
499
 
366
500
  ### Business Logic
367
501
 
368
- \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
502
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
369
503
 
370
- #### Example
504
+ SDK\uFF08\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\uFF09:
505
+ - \`client.appId\` \u2014 \u3053\u306E\u63A5\u7D9A\u304C\u30B9\u30B3\u30FC\u30D7\u3055\u308C\u3066\u3044\u308B\u30A2\u30D7\u30EAID
506
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch\uFF08\`?app=\${client.appId}\` \u306F\u81EA\u5206\u3067\u4ED8\u3051\u308B\uFF09
507
+ - \`client.getRecords(appId?, options?)\` \u2014 \`appId\` \u3092\u7701\u7565\u3059\u308B\u3068\u63A5\u7D9A\u306E\u30A2\u30D7\u30EAID\u304C\u4F7F\u308F\u308C\u307E\u3059
508
+ - \`client.getRecord(appIdOrRecordId, recordId?)\` \u2014 \u5F15\u65701\u3064\u3067\u547C\u3076\u3068\u305D\u308C\u3092\u30EC\u30B3\u30FC\u30C9ID\u3068\u3057\u3066\u6271\u3044\u3001\u63A5\u7D9A\u306E\u30A2\u30D7\u30EAID\u3092\u4F7F\u3044\u307E\u3059
371
509
 
372
510
  \`\`\`ts
373
- import { connection } from "@squadbase/vite-server/connectors/kintone-api-key";
511
+ import type { Context } from "hono";
512
+ import { connection } from "@squadbase/vite-server/connectors/kintone-api-token";
374
513
 
375
514
  const kintone = connection("<connectionId>");
376
515
 
377
- // Authenticated fetch (returns standard Response)
378
- const res = await kintone.request("/k/v1/records.json?app=1&query=limit 10");
379
- const data = await res.json();
516
+ export default async function handler(c: Context) {
517
+ const { status = "Active" } = await c.req.json<{ status?: string }>();
518
+
519
+ const { records, totalCount } = await kintone.getRecords(undefined, {
520
+ query: \`status = "\${status}" order by updatedTime desc limit 100\`,
521
+ fields: ["$id", "name", "email", "status", "updatedTime"],
522
+ totalCount: true,
523
+ });
524
+
525
+ return c.json({
526
+ totalCount,
527
+ rows: records.map((r) => ({
528
+ id: r.$id.value,
529
+ name: r.name?.value,
530
+ email: r.email?.value,
531
+ status: r.status?.value,
532
+ updatedTime: r.updatedTime?.value,
533
+ })),
534
+ });
535
+ }
536
+ \`\`\`
380
537
 
381
- await kintone.request("/k/v1/record.json", {
382
- method: "POST",
383
- body: JSON.stringify({ app: 1, record: { title: { value: "Hello" } } }),
384
- });
385
- \`\`\``
538
+ ### kintone REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
539
+
540
+ #### \u30A2\u30D7\u30EA\u30E1\u30BF\u60C5\u5831\u306E\u53D6\u5F97
541
+ - \`GET app.json\` \u2192 { appId, name, description, createdAt, modifiedAt, creator, ... } \u3092\u8FD4\u3059
542
+
543
+ #### \u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97
544
+ - \`GET app/form/fields.json\`
545
+
546
+ #### \u30EC\u30B3\u30FC\u30C9\u306E\u53D6\u5F97
547
+ - \`GET records.json?query={query}\`
548
+ - \u30AF\u30A8\u30EA\u4F8B: \`records.json?query=updatedTime > "2024-01-01" order by recordNumber asc limit 100\`
549
+
550
+ #### \u30EC\u30B3\u30FC\u30C9\u306E\u8FFD\u52A0
551
+ - \`POST record.json\`
552
+ - Body: \`{ "record": { "fieldName": { "value": "value" } } }\`
553
+
554
+ #### kintone \u30AF\u30A8\u30EA\u69CB\u6587
555
+ - \u6BD4\u8F03: \`fieldName = "value"\`, \`fieldName > 100\`
556
+ - \u6F14\u7B97\u5B50: \`and\`, \`or\`, \`not\`
557
+ - \u30BD\u30FC\u30C8: \`order by fieldName asc/desc\`
558
+ - \u5236\u9650: \`limit 100 offset 0\`
559
+ - \u6587\u5B57\u5217: \`like "\u90E8\u5206\u4E00\u81F4"\``
386
560
  },
387
561
  tools
388
562
  });
@@ -224,21 +224,58 @@ var ConnectorPlugin = class _ConnectorPlugin {
224
224
  * Filters connections by connectorKey internally.
225
225
  * Returns tools keyed as `${connectorKey}_${toolName}`.
226
226
  */
227
- createTools(connections, config) {
227
+ createTools(connections, config, opts) {
228
228
  const myConnections = connections.filter(
229
229
  (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
230
230
  );
231
231
  const result = {};
232
232
  for (const t of Object.values(this.tools)) {
233
- result[`${this.connectorKey}_${t.name}`] = t.createTool(
234
- myConnections,
235
- config
236
- );
233
+ const tool = t.createTool(myConnections, config);
234
+ const originalToModelOutput = tool.toModelOutput;
235
+ result[`${this.connectorKey}_${t.name}`] = {
236
+ ...tool,
237
+ toModelOutput: async (options) => {
238
+ if (!originalToModelOutput) {
239
+ return opts.truncateOutput(options.output);
240
+ }
241
+ const modelOutput = await originalToModelOutput(options);
242
+ if (modelOutput.type === "text" || modelOutput.type === "json") {
243
+ return opts.truncateOutput(modelOutput.value);
244
+ }
245
+ return modelOutput;
246
+ }
247
+ };
237
248
  }
238
249
  return result;
239
250
  }
240
251
  static deriveKey(slug, authType) {
241
- return authType ? `${slug}-${authType}` : slug;
252
+ if (authType) return `${slug}-${authType}`;
253
+ const LEGACY_NULL_AUTH_TYPE_MAP = {
254
+ // user-password
255
+ "postgresql": "user-password",
256
+ "mysql": "user-password",
257
+ "clickhouse": "user-password",
258
+ "kintone": "user-password",
259
+ "squadbase-db": "user-password",
260
+ // service-account
261
+ "snowflake": "service-account",
262
+ "bigquery": "service-account",
263
+ "google-analytics": "service-account",
264
+ "google-calendar": "service-account",
265
+ "aws-athena": "service-account",
266
+ "redshift": "service-account",
267
+ // api-key
268
+ "databricks": "api-key",
269
+ "dbt": "api-key",
270
+ "airtable": "api-key",
271
+ "openai": "api-key",
272
+ "gemini": "api-key",
273
+ "anthropic": "api-key",
274
+ "wix-store": "api-key"
275
+ };
276
+ const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
277
+ if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
278
+ return slug;
242
279
  }
243
280
  };
244
281