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

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.
@@ -64,6 +64,15 @@ var parameters = {
64
64
  type: "text",
65
65
  secret: false,
66
66
  required: false
67
+ }),
68
+ sharedDriveId: new ParameterDefinition({
69
+ slug: "shared-drive-id",
70
+ name: "Shared Drive ID",
71
+ description: "The ID of the Google Shared Drive where new presentations will be created. Required for service accounts that do not have their own Drive storage. You can find the ID in the Shared Drive URL: https://drive.google.com/drive/folders/{sharedDriveId}",
72
+ envVarBaseKey: "GOOGLE_SLIDES_SHARED_DRIVE_ID",
73
+ type: "text",
74
+ secret: false,
75
+ required: false
67
76
  })
68
77
  };
69
78
 
@@ -81,7 +90,8 @@ function extractPresentationId(urlOrId) {
81
90
  // ../connectors/src/connectors/google-slides/sdk/index.ts
82
91
  var TOKEN_URL = "https://oauth2.googleapis.com/token";
83
92
  var SLIDES_BASE_URL = "https://slides.googleapis.com/v1/presentations";
84
- var SCOPE = "https://www.googleapis.com/auth/presentations";
93
+ var DRIVE_FILES_URL = "https://www.googleapis.com/drive/v3/files";
94
+ var SCOPE = "https://www.googleapis.com/auth/presentations https://www.googleapis.com/auth/drive";
85
95
  function base64url(input) {
86
96
  const buf = typeof input === "string" ? Buffer.from(input) : input;
87
97
  return buf.toString("base64url");
@@ -108,6 +118,7 @@ function createClient(params) {
108
118
  const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
109
119
  const presentationUrl = params[parameters.presentationUrl.slug];
110
120
  const defaultPresentationId = presentationUrl ? extractPresentationId(presentationUrl) : void 0;
121
+ const sharedDriveId = params[parameters.sharedDriveId.slug] || void 0;
111
122
  if (!serviceAccountKeyJsonBase64) {
112
123
  throw new Error(
113
124
  `google-slides: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
@@ -216,6 +227,36 @@ function createClient(params) {
216
227
  return await response.json();
217
228
  },
218
229
  async createPresentation(title) {
230
+ if (sharedDriveId) {
231
+ const driveResponse = await authenticatedFetch(
232
+ `${DRIVE_FILES_URL}?supportsAllDrives=true`,
233
+ {
234
+ method: "POST",
235
+ body: JSON.stringify({
236
+ name: title,
237
+ mimeType: "application/vnd.google-apps.presentation",
238
+ parents: [sharedDriveId]
239
+ })
240
+ }
241
+ );
242
+ if (!driveResponse.ok) {
243
+ const body = await driveResponse.text();
244
+ throw new Error(
245
+ `google-slides: createPresentation (Drive API) failed (${driveResponse.status}): ${body}`
246
+ );
247
+ }
248
+ const driveFile = await driveResponse.json();
249
+ const slidesResponse = await authenticatedFetch(
250
+ `${SLIDES_BASE_URL}/${driveFile.id}`
251
+ );
252
+ if (!slidesResponse.ok) {
253
+ const body = await slidesResponse.text();
254
+ throw new Error(
255
+ `google-slides: getPresentation after create failed (${slidesResponse.status}): ${body}`
256
+ );
257
+ }
258
+ return await slidesResponse.json();
259
+ }
219
260
  const response = await authenticatedFetch(SLIDES_BASE_URL, {
220
261
  method: "POST",
221
262
  body: JSON.stringify({ title })
@@ -405,7 +446,10 @@ Authentication is handled automatically using a service account.
405
446
  );
406
447
  const auth = new GoogleAuth({
407
448
  credentials,
408
- scopes: ["https://www.googleapis.com/auth/presentations"]
449
+ scopes: [
450
+ "https://www.googleapis.com/auth/presentations",
451
+ "https://www.googleapis.com/auth/drive"
452
+ ]
409
453
  });
410
454
  const token = await auth.getAccessToken();
411
455
  if (!token) {
@@ -75,12 +75,44 @@ function createClient(params) {
75
75
  `kintone: missing required parameters: ${missing.join(", ")}`
76
76
  );
77
77
  }
78
+ let _restClient = null;
79
+ async function getRestClient() {
80
+ if (!_restClient) {
81
+ const { KintoneRestAPIClient } = await import("@kintone/rest-api-client");
82
+ _restClient = new KintoneRestAPIClient({
83
+ baseUrl,
84
+ auth: { apiToken }
85
+ });
86
+ }
87
+ return _restClient;
88
+ }
78
89
  return {
79
90
  request(path2, init) {
80
91
  const url = `${baseUrl.replace(/\/+$/, "")}${path2}`;
81
92
  const headers = new Headers(init?.headers);
82
93
  headers.set("X-Cybozu-API-Token", apiToken);
83
94
  return fetch(url, { ...init, headers });
95
+ },
96
+ async getRecords(appId, options) {
97
+ const client = await getRestClient();
98
+ const result = await client.record.getRecords({
99
+ app: appId,
100
+ query: options?.query,
101
+ fields: options?.fields,
102
+ totalCount: options?.totalCount
103
+ });
104
+ return {
105
+ records: result.records,
106
+ totalCount: result.totalCount ? Number(result.totalCount) : null
107
+ };
108
+ },
109
+ async getRecord(appId, recordId) {
110
+ const client = await getRestClient();
111
+ const result = await client.record.getRecord({
112
+ app: appId,
113
+ id: recordId
114
+ });
115
+ return { record: result.record };
84
116
  }
85
117
  };
86
118
  }
@@ -291,98 +323,140 @@ var kintoneApiTokenConnector = new ConnectorPlugin({
291
323
  systemPrompt: {
292
324
  en: `### Tools
293
325
 
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.
326
+ - \`kintone-api-key_request\`: The only way to call the kintone REST API. Use it to list apps, fetch field definitions, and read/write records. Authentication (API Token) and the base URL are configured automatically. API tokens are scoped per app \u2014 combine multiple tokens with commas to access multiple apps. See the kintone REST API Reference below for endpoints and the kintone query syntax.
327
+
328
+ ### Business Logic
329
+
330
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
331
+
332
+ SDK methods (client created via \`connection(connectionId)\`):
333
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
334
+ - \`client.getRecords(appId, options?)\` \u2014 fetch records with query/fields/totalCount (uses @kintone/rest-api-client)
335
+ - \`client.getRecord(appId, recordId)\` \u2014 fetch a single record
336
+
337
+ Note: app listing (\`/k/v1/apps.json\`) requires user-level auth and is not available via API token.
338
+
339
+ \`\`\`ts
340
+ import type { Context } from "hono";
341
+ import { connection } from "@squadbase/vite-server/connectors/kintone-api-token";
342
+
343
+ const kintone = connection("<connectionId>");
344
+
345
+ export default async function handler(c: Context) {
346
+ const { appId, status = "Active" } = await c.req.json<{
347
+ appId: number;
348
+ status?: string;
349
+ }>();
350
+
351
+ const { records, totalCount } = await kintone.getRecords(appId, {
352
+ query: \`status = "\${status}" order by updatedTime desc limit 100\`,
353
+ fields: ["$id", "name", "email", "status", "updatedTime"],
354
+ totalCount: true,
355
+ });
356
+
357
+ return c.json({
358
+ totalCount,
359
+ rows: records.map((r) => ({
360
+ id: r.$id.value,
361
+ name: r.name?.value,
362
+ email: r.email?.value,
363
+ status: r.status?.value,
364
+ updatedTime: r.updatedTime?.value,
365
+ })),
366
+ });
367
+ }
368
+ \`\`\`
295
369
 
296
370
  ### kintone REST API Reference
297
371
 
298
372
  #### List Apps
299
- - GET apps.json
373
+ - \`GET apps.json\`
300
374
 
301
- ### Get Field Definitions
302
- - GET app/form/fields.json?app={appId}
375
+ #### Get Field Definitions
376
+ - \`GET app/form/fields.json?app={appId}\`
303
377
 
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
378
+ #### Get Records
379
+ - \`GET records.json?app={appId}&query={query}\`
380
+ - Query example: \`records.json?app=1&query=updatedTime > "2024-01-01" order by recordNumber asc limit 100\`
307
381
 
308
382
  #### Add Record
309
- - POST record.json
310
- - Body: { "app": 1, "record": { "fieldName": { "value": "value" } } }
383
+ - \`POST record.json\`
384
+ - Body: \`{ "app": 1, "record": { "fieldName": { "value": "value" } } }\`
311
385
 
312
386
  #### 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"
387
+ - Comparison: \`fieldName = "value"\`, \`fieldName > 100\`
388
+ - Operators: \`and\`, \`or\`, \`not\`
389
+ - Sort: \`order by fieldName asc/desc\`
390
+ - Limit: \`limit 100 offset 0\`
391
+ - String: \`like "partial match"\``,
392
+ ja: `### \u30C4\u30FC\u30EB
393
+
394
+ - \`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\u8AAD\u307F\u66F8\u304D\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\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u304A\u3088\u3073kintone\u30AF\u30A8\u30EA\u69CB\u6587\u306F\u4E0B\u90E8\u306E\u300Ckintone REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
318
395
 
319
396
  ### Business Logic
320
397
 
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.
398
+ \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
399
+
400
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
401
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
402
+ - \`client.getRecords(appId, options?)\` \u2014 query/fields/totalCount\u4ED8\u304D\u3067\u30EC\u30B3\u30FC\u30C9\u53D6\u5F97 (@kintone/rest-api-client \u4F7F\u7528)
403
+ - \`client.getRecord(appId, recordId)\` \u2014 \u5358\u4E00\u30EC\u30B3\u30FC\u30C9\u3092\u53D6\u5F97
322
404
 
323
- #### Example
405
+ \u6CE8: \u30A2\u30D7\u30EA\u4E00\u89A7 (\`/k/v1/apps.json\`) \u306F\u30E6\u30FC\u30B6\u30FC\u8A8D\u8A3C\u304C\u5FC5\u8981\u306A\u305F\u3081\u3001API \u30C8\u30FC\u30AF\u30F3\u8A8D\u8A3C\u3067\u306F\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002
324
406
 
325
407
  \`\`\`ts
326
- import { connection } from "@squadbase/vite-server/connectors/kintone-api-key";
408
+ import type { Context } from "hono";
409
+ import { connection } from "@squadbase/vite-server/connectors/kintone-api-token";
327
410
 
328
411
  const kintone = connection("<connectionId>");
329
412
 
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();
333
-
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
340
-
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
413
+ export default async function handler(c: Context) {
414
+ const { appId, status = "Active" } = await c.req.json<{
415
+ appId: number;
416
+ status?: string;
417
+ }>();
418
+
419
+ const { records, totalCount } = await kintone.getRecords(appId, {
420
+ query: \`status = "\${status}" order by updatedTime desc limit 100\`,
421
+ fields: ["$id", "name", "email", "status", "updatedTime"],
422
+ totalCount: true,
423
+ });
424
+
425
+ return c.json({
426
+ totalCount,
427
+ rows: records.map((r) => ({
428
+ id: r.$id.value,
429
+ name: r.name?.value,
430
+ email: r.email?.value,
431
+ status: r.status?.value,
432
+ updatedTime: r.updatedTime?.value,
433
+ })),
434
+ });
435
+ }
436
+ \`\`\`
342
437
 
343
438
  ### kintone REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
344
439
 
345
440
  #### \u30A2\u30D7\u30EA\u4E00\u89A7\u306E\u53D6\u5F97
346
- - GET apps.json
441
+ - \`GET apps.json\`
347
442
 
348
- ### \u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97
349
- - GET app/form/fields.json?app={appId}
443
+ #### \u30D5\u30A3\u30FC\u30EB\u30C9\u5B9A\u7FA9\u306E\u53D6\u5F97
444
+ - \`GET app/form/fields.json?app={appId}\`
350
445
 
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
446
+ #### \u30EC\u30B3\u30FC\u30C9\u306E\u53D6\u5F97
447
+ - \`GET records.json?app={appId}&query={query}\`
448
+ - \u30AF\u30A8\u30EA\u4F8B: \`records.json?app=1&query=updatedTime > "2024-01-01" order by recordNumber asc limit 100\`
354
449
 
355
450
  #### \u30EC\u30B3\u30FC\u30C9\u306E\u8FFD\u52A0
356
- - POST record.json
357
- - Body: { "app": 1, "record": { "fieldName": { "value": "value" } } }
451
+ - \`POST record.json\`
452
+ - Body: \`{ "app": 1, "record": { "fieldName": { "value": "value" } } }\`
358
453
 
359
454
  #### 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"
365
-
366
- ### Business Logic
367
-
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
369
-
370
- #### Example
371
-
372
- \`\`\`ts
373
- import { connection } from "@squadbase/vite-server/connectors/kintone-api-key";
374
-
375
- const kintone = connection("<connectionId>");
376
-
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();
380
-
381
- await kintone.request("/k/v1/record.json", {
382
- method: "POST",
383
- body: JSON.stringify({ app: 1, record: { title: { value: "Hello" } } }),
384
- });
385
- \`\`\``
455
+ - \u6BD4\u8F03: \`fieldName = "value"\`, \`fieldName > 100\`
456
+ - \u6F14\u7B97\u5B50: \`and\`, \`or\`, \`not\`
457
+ - \u30BD\u30FC\u30C8: \`order by fieldName asc/desc\`
458
+ - \u5236\u9650: \`limit 100 offset 0\`
459
+ - \u6587\u5B57\u5217: \`like "\u90E8\u5206\u4E00\u81F4"\``
386
460
  },
387
461
  tools
388
462
  });