runline 0.12.0 → 0.14.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.
@@ -28,7 +28,9 @@
28
28
  * call `event.listInstances`.
29
29
  */
30
30
  import rrulePkg from "rrule";
31
+ import * as t from "typebox";
31
32
  import { googleAccessToken } from "../../_shared/googleAuth.js";
33
+ import { Id, NonEmptyString, NonEmptyStringArray, PositiveInteger, StringOrStringArray, stringEnum, } from "../../_shared/googleSchemas.js";
32
34
  // `rrule` ships as CJS; named imports fail under Node ESM.
33
35
  const { RRule } = rrulePkg;
34
36
  // ─── Auth ────────────────────────────────────────────────────────
@@ -234,9 +236,9 @@ function applyEventFields(body, p) {
234
236
  body.guestsCanModify = p.guestsCanModify;
235
237
  if (typeof p.guestsCanSeeOtherGuests === "boolean")
236
238
  body.guestsCanSeeOtherGuests = p.guestsCanSeeOtherGuests;
237
- const attendees = splitAttendees(p.attendees);
238
- if (attendees)
239
- body.attendees = attendees;
239
+ if (p.attendees !== undefined) {
240
+ body.attendees = splitAttendees(p.attendees) ?? [];
241
+ }
240
242
  if (p.reminders !== undefined || p.useDefaultReminders !== undefined) {
241
243
  const useDefault = p.useDefaultReminders !== false && !Array.isArray(p.reminders);
242
244
  body.reminders = { useDefault };
@@ -255,6 +257,286 @@ function applyEventFields(body, p) {
255
257
  }
256
258
  // ─── Plugin ──────────────────────────────────────────────────────
257
259
  const SCOPES = ["https://www.googleapis.com/auth/calendar"];
260
+ const strictObject = (properties, options = {}) => t.Object(properties, { ...options, additionalProperties: false });
261
+ const optionalString = (description) => t.Optional(t.String(description ? { description } : {}));
262
+ const optionalBoolean = t.Optional(t.Boolean());
263
+ const optionalPositiveInteger = t.Optional(PositiveInteger);
264
+ const calendarId = NonEmptyString;
265
+ const accessRole = stringEnum([
266
+ "freeBusyReader",
267
+ "reader",
268
+ "writer",
269
+ "owner",
270
+ ]);
271
+ const sendUpdates = stringEnum(["all", "externalOnly", "none"]);
272
+ const reminder = strictObject({
273
+ method: stringEnum(["email", "popup"]),
274
+ minutes: t.Integer({ minimum: 0 }),
275
+ });
276
+ const reminders = t.Array(reminder);
277
+ const attendees = StringOrStringArray;
278
+ const recurrenceFields = {
279
+ rrule: t.Optional(NonEmptyString),
280
+ repeatFrequency: t.Optional(stringEnum(["daily", "weekly", "monthly", "yearly"])),
281
+ repeatHowManyTimes: t.Optional(PositiveInteger),
282
+ repeatUntil: t.Optional(NonEmptyString),
283
+ };
284
+ const recurrenceConstraints = [
285
+ { not: { required: ["repeatHowManyTimes", "repeatUntil"] } },
286
+ { not: { required: ["rrule", "repeatFrequency"] } },
287
+ { not: { required: ["rrule", "repeatHowManyTimes"] } },
288
+ { not: { required: ["rrule", "repeatUntil"] } },
289
+ {
290
+ anyOf: [
291
+ {
292
+ not: {
293
+ anyOf: [
294
+ { required: ["repeatHowManyTimes"] },
295
+ { required: ["repeatUntil"] },
296
+ ],
297
+ },
298
+ },
299
+ { required: ["repeatFrequency"] },
300
+ ],
301
+ },
302
+ ];
303
+ const eventMutableFields = {
304
+ summary: optionalString(),
305
+ description: optionalString(),
306
+ location: optionalString(),
307
+ colorId: optionalString(),
308
+ transparency: t.Optional(stringEnum(["opaque", "transparent"])),
309
+ visibility: t.Optional(stringEnum(["default", "public", "private", "confidential"])),
310
+ guestsCanInviteOthers: optionalBoolean,
311
+ guestsCanModify: optionalBoolean,
312
+ guestsCanSeeOtherGuests: optionalBoolean,
313
+ attendees: t.Optional(attendees),
314
+ reminders: t.Optional(reminders),
315
+ useDefaultReminders: optionalBoolean,
316
+ };
317
+ const eventListFields = {
318
+ q: optionalString(),
319
+ timeMin: optionalString("ISO datetime"),
320
+ timeMax: optionalString("ISO datetime"),
321
+ updatedMin: optionalString("ISO datetime"),
322
+ timeZone: optionalString(),
323
+ iCalUID: optionalString(),
324
+ orderBy: t.Optional(stringEnum(["startTime", "updated"])),
325
+ singleEvents: optionalBoolean,
326
+ showDeleted: optionalBoolean,
327
+ showHiddenInvitations: optionalBoolean,
328
+ maxAttendees: optionalPositiveInteger,
329
+ maxResults: optionalPositiveInteger,
330
+ pageToken: optionalString(),
331
+ returnAll: optionalBoolean,
332
+ fields: optionalString(),
333
+ nextOccurrence: optionalBoolean,
334
+ };
335
+ const calendarSchemas = {
336
+ list: strictObject({
337
+ returnAll: optionalBoolean,
338
+ maxResults: optionalPositiveInteger,
339
+ pageToken: optionalString(),
340
+ showHidden: optionalBoolean,
341
+ showDeleted: optionalBoolean,
342
+ minAccessRole: t.Optional(accessRole),
343
+ }),
344
+ get: strictObject({ calendarId }),
345
+ availability: strictObject({
346
+ calendarId: t.Optional(calendarId),
347
+ calendarIds: t.Optional(NonEmptyStringArray),
348
+ timeMin: NonEmptyString,
349
+ timeMax: NonEmptyString,
350
+ timeZone: optionalString(),
351
+ outputFormat: t.Optional(stringEnum(["availability", "bookedSlots", "raw"])),
352
+ }, {
353
+ oneOf: [
354
+ {
355
+ required: ["calendarId"],
356
+ not: { required: ["calendarIds"] },
357
+ },
358
+ {
359
+ required: ["calendarIds"],
360
+ not: { required: ["calendarId"] },
361
+ },
362
+ ],
363
+ }),
364
+ listColors: strictObject({}),
365
+ };
366
+ const eventSchemas = {
367
+ create: strictObject({
368
+ calendarId,
369
+ ...eventMutableFields,
370
+ start: NonEmptyString,
371
+ end: NonEmptyString,
372
+ allDay: optionalBoolean,
373
+ timeZone: optionalString(),
374
+ id: optionalString("Custom event ID"),
375
+ ...recurrenceFields,
376
+ conferenceSolution: t.Optional(stringEnum([
377
+ "eventHangout",
378
+ "eventNamedHangout",
379
+ "hangoutsMeet",
380
+ ])),
381
+ sendUpdates: t.Optional(sendUpdates),
382
+ maxAttendees: optionalPositiveInteger,
383
+ }, { allOf: recurrenceConstraints }),
384
+ get: strictObject({
385
+ calendarId,
386
+ eventId: Id,
387
+ timeZone: optionalString(),
388
+ maxAttendees: optionalPositiveInteger,
389
+ nextOccurrence: optionalBoolean,
390
+ }),
391
+ list: strictObject({ calendarId, ...eventListFields }),
392
+ listInstances: strictObject({
393
+ calendarId,
394
+ eventId: Id,
395
+ timeMin: optionalString(),
396
+ timeMax: optionalString(),
397
+ timeZone: optionalString(),
398
+ showDeleted: optionalBoolean,
399
+ maxResults: optionalPositiveInteger,
400
+ pageToken: optionalString(),
401
+ returnAll: optionalBoolean,
402
+ }),
403
+ update: strictObject({
404
+ calendarId,
405
+ eventId: Id,
406
+ modifyTarget: t.Optional(stringEnum(["instance", "series"])),
407
+ ...eventMutableFields,
408
+ start: optionalString(),
409
+ end: optionalString(),
410
+ allDay: optionalBoolean,
411
+ timeZone: optionalString(),
412
+ ...recurrenceFields,
413
+ sendUpdates: t.Optional(sendUpdates),
414
+ maxAttendees: optionalPositiveInteger,
415
+ sendNotifications: optionalBoolean,
416
+ }, {
417
+ allOf: [
418
+ ...recurrenceConstraints,
419
+ {
420
+ anyOf: [
421
+ {
422
+ not: {
423
+ anyOf: [{ required: ["start"] }, { required: ["end"] }],
424
+ },
425
+ },
426
+ { required: ["start", "end"] },
427
+ ],
428
+ },
429
+ {
430
+ not: {
431
+ required: ["allDay"],
432
+ not: { required: ["start"] },
433
+ },
434
+ },
435
+ {
436
+ not: {
437
+ required: ["timeZone"],
438
+ not: { required: ["start"] },
439
+ },
440
+ },
441
+ ],
442
+ anyOf: [
443
+ ...Object.keys(eventMutableFields).map((key) => ({ required: [key] })),
444
+ { required: ["start"] },
445
+ { required: ["rrule"] },
446
+ { required: ["repeatFrequency"] },
447
+ ],
448
+ }),
449
+ delete: strictObject({
450
+ calendarId,
451
+ eventId: Id,
452
+ sendUpdates: t.Optional(sendUpdates),
453
+ }),
454
+ move: strictObject({
455
+ calendarId,
456
+ eventId: Id,
457
+ destinationCalendarId: calendarId,
458
+ sendUpdates: t.Optional(sendUpdates),
459
+ }),
460
+ };
461
+ const freeBusySchema = strictObject({
462
+ calendarIds: NonEmptyStringArray,
463
+ timeMin: NonEmptyString,
464
+ timeMax: NonEmptyString,
465
+ timeZone: optionalString(),
466
+ groupExpansionMax: optionalPositiveInteger,
467
+ calendarExpansionMax: optionalPositiveInteger,
468
+ });
469
+ const calendarListSchemas = {
470
+ list: strictObject({
471
+ minAccessRole: t.Optional(accessRole),
472
+ showDeleted: optionalBoolean,
473
+ showHidden: optionalBoolean,
474
+ returnAll: optionalBoolean,
475
+ }),
476
+ insert: strictObject({
477
+ calendarId,
478
+ colorRgbFormat: optionalBoolean,
479
+ defaultReminders: t.Optional(reminders),
480
+ summaryOverride: optionalString(),
481
+ }),
482
+ patch: strictObject({
483
+ calendarId,
484
+ colorId: optionalString(),
485
+ backgroundColor: optionalString(),
486
+ foregroundColor: optionalString(),
487
+ summaryOverride: optionalString(),
488
+ selected: optionalBoolean,
489
+ hidden: optionalBoolean,
490
+ defaultReminders: t.Optional(reminders),
491
+ }, {
492
+ anyOf: [
493
+ { required: ["colorId"] },
494
+ { required: ["backgroundColor"] },
495
+ { required: ["foregroundColor"] },
496
+ { required: ["summaryOverride"] },
497
+ { required: ["selected"] },
498
+ { required: ["hidden"] },
499
+ { required: ["defaultReminders"] },
500
+ ],
501
+ }),
502
+ delete: strictObject({ calendarId }),
503
+ };
504
+ const aclRole = stringEnum([
505
+ "none",
506
+ "freeBusyReader",
507
+ "reader",
508
+ "writer",
509
+ "owner",
510
+ ]);
511
+ const aclSchemas = {
512
+ list: strictObject({ calendarId, returnAll: optionalBoolean }),
513
+ insert: strictObject({
514
+ calendarId,
515
+ role: aclRole,
516
+ scopeType: stringEnum(["default", "user", "group", "domain"]),
517
+ scopeValue: optionalString(),
518
+ sendNotifications: optionalBoolean,
519
+ }, {
520
+ anyOf: [
521
+ {
522
+ properties: { scopeType: { const: "default" } },
523
+ not: { required: ["scopeValue"] },
524
+ },
525
+ {
526
+ properties: {
527
+ scopeType: { enum: ["user", "group", "domain"] },
528
+ },
529
+ required: ["scopeValue"],
530
+ },
531
+ ],
532
+ }),
533
+ update: strictObject({ calendarId, ruleId: Id, role: aclRole }),
534
+ delete: strictObject({ calendarId, ruleId: Id }),
535
+ };
536
+ const settingsSchemas = {
537
+ list: strictObject({ returnAll: optionalBoolean }),
538
+ get: strictObject({ setting: NonEmptyString }),
539
+ };
258
540
  export default function googleCalendar(rl) {
259
541
  rl.setName("googleCalendar");
260
542
  rl.setVersion("0.1.0");
@@ -347,18 +629,7 @@ export default function googleCalendar(rl) {
347
629
  rl.registerAction("calendar.list", {
348
630
  access: "read",
349
631
  description: "List calendars the authenticated user has access to",
350
- inputSchema: {
351
- returnAll: { type: "boolean", required: false },
352
- maxResults: { type: "number", required: false },
353
- pageToken: { type: "string", required: false },
354
- showHidden: { type: "boolean", required: false },
355
- showDeleted: { type: "boolean", required: false },
356
- minAccessRole: {
357
- type: "string",
358
- required: false,
359
- description: "freeBusyReader | reader | writer | owner",
360
- },
361
- },
632
+ inputSchema: calendarSchemas.list,
362
633
  async execute(input, ctx) {
363
634
  const p = (input ?? {});
364
635
  const qs = {};
@@ -380,13 +651,7 @@ export default function googleCalendar(rl) {
380
651
  rl.registerAction("calendar.get", {
381
652
  access: "read",
382
653
  description: "Get a calendar's metadata (including conference solutions)",
383
- inputSchema: {
384
- calendarId: {
385
- type: "string",
386
- required: true,
387
- description: 'Calendar ID (email) or "primary"',
388
- },
389
- },
654
+ inputSchema: calendarSchemas.get,
390
655
  async execute(input, ctx) {
391
656
  const { calendarId } = input;
392
657
  return calRequest(ctx, "GET", `/users/me/calendarList/${encodeCalendarId(calendarId)}`);
@@ -395,34 +660,7 @@ export default function googleCalendar(rl) {
395
660
  rl.registerAction("calendar.availability", {
396
661
  access: "read",
397
662
  description: "Check free/busy information for one or more calendars over a time range",
398
- inputSchema: {
399
- calendarId: {
400
- type: "string",
401
- required: false,
402
- description: 'Single calendar ID (email) or "primary"',
403
- },
404
- calendarIds: {
405
- type: "array",
406
- required: false,
407
- description: "Multiple calendar IDs (takes precedence over calendarId)",
408
- },
409
- timeMin: {
410
- type: "string",
411
- required: true,
412
- description: "ISO datetime — start of the interval",
413
- },
414
- timeMax: {
415
- type: "string",
416
- required: true,
417
- description: "ISO datetime — end of the interval",
418
- },
419
- timeZone: { type: "string", required: false },
420
- outputFormat: {
421
- type: "string",
422
- required: false,
423
- description: "availability | bookedSlots | raw (default: raw)",
424
- },
425
- },
663
+ inputSchema: calendarSchemas.availability,
426
664
  async execute(input, ctx) {
427
665
  const p = (input ?? {});
428
666
  const ids = Array.isArray(p.calendarIds)
@@ -471,6 +709,7 @@ export default function googleCalendar(rl) {
471
709
  rl.registerAction("calendar.listColors", {
472
710
  access: "read",
473
711
  description: "List event and calendar color palettes available in Google Calendar",
712
+ inputSchema: calendarSchemas.listColors,
474
713
  async execute(_input, ctx) {
475
714
  return calRequest(ctx, "GET", "/colors");
476
715
  },
@@ -479,61 +718,7 @@ export default function googleCalendar(rl) {
479
718
  rl.registerAction("event.create", {
480
719
  access: "write",
481
720
  description: "Create a calendar event",
482
- inputSchema: {
483
- calendarId: { type: "string", required: true },
484
- summary: { type: "string", required: false },
485
- description: { type: "string", required: false },
486
- location: { type: "string", required: false },
487
- start: {
488
- type: "string",
489
- required: true,
490
- description: "ISO datetime (or YYYY-MM-DD when allDay)",
491
- },
492
- end: { type: "string", required: true },
493
- allDay: { type: "boolean", required: false },
494
- timeZone: { type: "string", required: false },
495
- attendees: {
496
- type: "array",
497
- required: false,
498
- description: "Array of email addresses, or a comma-separated string",
499
- },
500
- colorId: { type: "string", required: false },
501
- id: { type: "string", required: false, description: "Custom event ID" },
502
- transparency: {
503
- type: "string",
504
- required: false,
505
- description: 'Show me as: "opaque" (busy) | "transparent" (free)',
506
- },
507
- visibility: { type: "string", required: false },
508
- guestsCanInviteOthers: { type: "boolean", required: false },
509
- guestsCanModify: { type: "boolean", required: false },
510
- guestsCanSeeOtherGuests: { type: "boolean", required: false },
511
- reminders: {
512
- type: "array",
513
- required: false,
514
- description: '[{method: "email"|"popup", minutes: number}]',
515
- },
516
- useDefaultReminders: { type: "boolean", required: false },
517
- rrule: { type: "string", required: false, description: "e.g. FREQ=WEEKLY;COUNT=5" },
518
- repeatFrequency: {
519
- type: "string",
520
- required: false,
521
- description: "daily | weekly | monthly | yearly",
522
- },
523
- repeatHowManyTimes: { type: "number", required: false },
524
- repeatUntil: { type: "string", required: false, description: "ISO datetime" },
525
- conferenceSolution: {
526
- type: "string",
527
- required: false,
528
- description: "eventHangout | eventNamedHangout | hangoutsMeet",
529
- },
530
- sendUpdates: {
531
- type: "string",
532
- required: false,
533
- description: "all | externalOnly | none",
534
- },
535
- maxAttendees: { type: "number", required: false },
536
- },
721
+ inputSchema: eventSchemas.create,
537
722
  async execute(input, ctx) {
538
723
  const p = (input ?? {});
539
724
  const body = {};
@@ -557,17 +742,7 @@ export default function googleCalendar(rl) {
557
742
  rl.registerAction("event.get", {
558
743
  access: "read",
559
744
  description: "Get a single event",
560
- inputSchema: {
561
- calendarId: { type: "string", required: true },
562
- eventId: { type: "string", required: true },
563
- timeZone: { type: "string", required: false },
564
- maxAttendees: { type: "number", required: false },
565
- nextOccurrence: {
566
- type: "boolean",
567
- required: false,
568
- description: "Attach nextOccurrence for recurring events (default: true)",
569
- },
570
- },
745
+ inputSchema: eventSchemas.get,
571
746
  async execute(input, ctx) {
572
747
  const p = (input ?? {});
573
748
  const qs = {};
@@ -584,33 +759,7 @@ export default function googleCalendar(rl) {
584
759
  rl.registerAction("event.list", {
585
760
  access: "read",
586
761
  description: "List events in a calendar. Set `singleEvents=true` to expand recurring events into instances.",
587
- inputSchema: {
588
- calendarId: { type: "string", required: true },
589
- q: { type: "string", required: false, description: "Free-text query" },
590
- timeMin: { type: "string", required: false, description: "ISO datetime" },
591
- timeMax: { type: "string", required: false },
592
- updatedMin: { type: "string", required: false },
593
- timeZone: { type: "string", required: false },
594
- iCalUID: { type: "string", required: false },
595
- orderBy: {
596
- type: "string",
597
- required: false,
598
- description: "startTime (requires singleEvents=true) | updated",
599
- },
600
- singleEvents: { type: "boolean", required: false },
601
- showDeleted: { type: "boolean", required: false },
602
- showHiddenInvitations: { type: "boolean", required: false },
603
- maxAttendees: { type: "number", required: false },
604
- maxResults: { type: "number", required: false },
605
- pageToken: { type: "string", required: false },
606
- returnAll: { type: "boolean", required: false },
607
- fields: { type: "string", required: false },
608
- nextOccurrence: {
609
- type: "boolean",
610
- required: false,
611
- description: "Attach nextOccurrence to recurring events (default: true; ignored when singleEvents=true)",
612
- },
613
- },
762
+ inputSchema: eventSchemas.list,
614
763
  async execute(input, ctx) {
615
764
  const p = (input ?? {});
616
765
  const qs = {};
@@ -654,17 +803,7 @@ export default function googleCalendar(rl) {
654
803
  rl.registerAction("event.listInstances", {
655
804
  access: "read",
656
805
  description: "List instances of a recurring event",
657
- inputSchema: {
658
- calendarId: { type: "string", required: true },
659
- eventId: { type: "string", required: true },
660
- timeMin: { type: "string", required: false },
661
- timeMax: { type: "string", required: false },
662
- timeZone: { type: "string", required: false },
663
- showDeleted: { type: "boolean", required: false },
664
- maxResults: { type: "number", required: false },
665
- pageToken: { type: "string", required: false },
666
- returnAll: { type: "boolean", required: false },
667
- },
806
+ inputSchema: eventSchemas.listInstances,
668
807
  async execute(input, ctx) {
669
808
  const p = (input ?? {});
670
809
  const qs = {};
@@ -689,38 +828,7 @@ export default function googleCalendar(rl) {
689
828
  rl.registerAction("event.update", {
690
829
  access: "write",
691
830
  description: "Patch an event (only supplied fields are changed). Set modifyTarget='series' to edit the entire recurrence instead of a single instance.",
692
- inputSchema: {
693
- calendarId: { type: "string", required: true },
694
- eventId: { type: "string", required: true },
695
- modifyTarget: {
696
- type: "string",
697
- required: false,
698
- description: "instance (default) | series",
699
- },
700
- summary: { type: "string", required: false },
701
- description: { type: "string", required: false },
702
- location: { type: "string", required: false },
703
- start: { type: "string", required: false },
704
- end: { type: "string", required: false },
705
- allDay: { type: "boolean", required: false },
706
- timeZone: { type: "string", required: false },
707
- attendees: { type: "array", required: false },
708
- colorId: { type: "string", required: false },
709
- transparency: { type: "string", required: false },
710
- visibility: { type: "string", required: false },
711
- guestsCanInviteOthers: { type: "boolean", required: false },
712
- guestsCanModify: { type: "boolean", required: false },
713
- guestsCanSeeOtherGuests: { type: "boolean", required: false },
714
- reminders: { type: "array", required: false },
715
- useDefaultReminders: { type: "boolean", required: false },
716
- rrule: { type: "string", required: false },
717
- repeatFrequency: { type: "string", required: false },
718
- repeatHowManyTimes: { type: "number", required: false },
719
- repeatUntil: { type: "string", required: false },
720
- sendUpdates: { type: "string", required: false },
721
- maxAttendees: { type: "number", required: false },
722
- sendNotifications: { type: "boolean", required: false },
723
- },
831
+ inputSchema: eventSchemas.update,
724
832
  async execute(input, ctx) {
725
833
  const p = (input ?? {});
726
834
  let eventId = p.eventId;
@@ -759,11 +867,7 @@ export default function googleCalendar(rl) {
759
867
  rl.registerAction("event.delete", {
760
868
  access: "write",
761
869
  description: "Delete an event",
762
- inputSchema: {
763
- calendarId: { type: "string", required: true },
764
- eventId: { type: "string", required: true },
765
- sendUpdates: { type: "string", required: false },
766
- },
870
+ inputSchema: eventSchemas.delete,
767
871
  async execute(input, ctx) {
768
872
  const p = (input ?? {});
769
873
  const qs = {};
@@ -775,12 +879,7 @@ export default function googleCalendar(rl) {
775
879
  rl.registerAction("event.move", {
776
880
  access: "write",
777
881
  description: "Move an event from one calendar to another",
778
- inputSchema: {
779
- calendarId: { type: "string", required: true, description: "Source calendar" },
780
- eventId: { type: "string", required: true },
781
- destinationCalendarId: { type: "string", required: true },
782
- sendUpdates: { type: "string", required: false },
783
- },
882
+ inputSchema: eventSchemas.move,
784
883
  async execute(input, ctx) {
785
884
  const p = (input ?? {});
786
885
  const qs = {
@@ -795,14 +894,7 @@ export default function googleCalendar(rl) {
795
894
  rl.registerAction("freeBusy.query", {
796
895
  access: "read",
797
896
  description: "Query free/busy windows across one or more calendars in a time range. Returns an array of busy intervals per calendar id, plus any errors.",
798
- inputSchema: {
799
- calendarIds: { type: "array", required: true, description: "Calendar ids to query (use 'primary' for the user's own)." },
800
- timeMin: { type: "string", required: true, description: "RFC 3339 lower bound." },
801
- timeMax: { type: "string", required: true, description: "RFC 3339 upper bound." },
802
- timeZone: { type: "string", required: false },
803
- groupExpansionMax: { type: "number", required: false },
804
- calendarExpansionMax: { type: "number", required: false },
805
- },
897
+ inputSchema: freeBusySchema,
806
898
  async execute(input, ctx) {
807
899
  const p = (input ?? {});
808
900
  const body = {
@@ -820,12 +912,7 @@ export default function googleCalendar(rl) {
820
912
  rl.registerAction("calendarList.list", {
821
913
  access: "read",
822
914
  description: "List calendars on the user's calendar list (the user's left sidebar).",
823
- inputSchema: {
824
- minAccessRole: { type: "string", required: false, description: "freeBusyReader | reader | writer | owner" },
825
- showDeleted: { type: "boolean", required: false },
826
- showHidden: { type: "boolean", required: false },
827
- returnAll: { type: "boolean", required: false, default: true },
828
- },
915
+ inputSchema: calendarListSchemas.list,
829
916
  async execute(input, ctx) {
830
917
  const p = (input ?? {});
831
918
  const qs = {
@@ -843,12 +930,7 @@ export default function googleCalendar(rl) {
843
930
  rl.registerAction("calendarList.insert", {
844
931
  access: "write",
845
932
  description: "Add a calendar (by id) to the user's calendar list.",
846
- inputSchema: {
847
- calendarId: { type: "string", required: true },
848
- colorRgbFormat: { type: "boolean", required: false },
849
- defaultReminders: { type: "array", required: false },
850
- summaryOverride: { type: "string", required: false },
851
- },
933
+ inputSchema: calendarListSchemas.insert,
852
934
  async execute(input, ctx) {
853
935
  const p = (input ?? {});
854
936
  const body = { id: p.calendarId };
@@ -862,16 +944,7 @@ export default function googleCalendar(rl) {
862
944
  rl.registerAction("calendarList.patch", {
863
945
  access: "write",
864
946
  description: "Patch a calendar entry on the user's calendar list (colors, summary override, reminders, selected).",
865
- inputSchema: {
866
- calendarId: { type: "string", required: true },
867
- colorId: { type: "string", required: false },
868
- backgroundColor: { type: "string", required: false },
869
- foregroundColor: { type: "string", required: false },
870
- summaryOverride: { type: "string", required: false },
871
- selected: { type: "boolean", required: false },
872
- hidden: { type: "boolean", required: false },
873
- defaultReminders: { type: "array", required: false },
874
- },
947
+ inputSchema: calendarListSchemas.patch,
875
948
  async execute(input, ctx) {
876
949
  const p = (input ?? {});
877
950
  const body = {};
@@ -885,7 +958,7 @@ export default function googleCalendar(rl) {
885
958
  rl.registerAction("calendarList.delete", {
886
959
  access: "write",
887
960
  description: "Remove a calendar from the user's calendar list (does not delete the underlying calendar).",
888
- inputSchema: { calendarId: { type: "string", required: true } },
961
+ inputSchema: calendarListSchemas.delete,
889
962
  async execute(input, ctx) {
890
963
  const p = (input ?? {});
891
964
  await calRequest(ctx, "DELETE", `/users/me/calendarList/${encodeCalendarId(p.calendarId)}`);
@@ -896,10 +969,7 @@ export default function googleCalendar(rl) {
896
969
  rl.registerAction("acl.list", {
897
970
  access: "read",
898
971
  description: "List ACL rules on a calendar.",
899
- inputSchema: {
900
- calendarId: { type: "string", required: true },
901
- returnAll: { type: "boolean", required: false, default: true },
902
- },
972
+ inputSchema: aclSchemas.list,
903
973
  async execute(input, ctx) {
904
974
  const p = (input ?? {});
905
975
  const path = `/calendars/${encodeCalendarId(p.calendarId)}/acl`;
@@ -912,13 +982,7 @@ export default function googleCalendar(rl) {
912
982
  rl.registerAction("acl.insert", {
913
983
  access: "write",
914
984
  description: "Add an ACL rule to a calendar. Roles: 'none' | 'freeBusyReader' | 'reader' | 'writer' | 'owner'.",
915
- inputSchema: {
916
- calendarId: { type: "string", required: true },
917
- role: { type: "string", required: true },
918
- scopeType: { type: "string", required: true, description: "'default' | 'user' | 'group' | 'domain'" },
919
- scopeValue: { type: "string", required: false, description: "Email / domain depending on scopeType." },
920
- sendNotifications: { type: "boolean", required: false },
921
- },
985
+ inputSchema: aclSchemas.insert,
922
986
  async execute(input, ctx) {
923
987
  const p = (input ?? {});
924
988
  const body = { role: p.role, scope: { type: p.scopeType, value: p.scopeValue } };
@@ -928,11 +992,7 @@ export default function googleCalendar(rl) {
928
992
  rl.registerAction("acl.update", {
929
993
  access: "write",
930
994
  description: "Patch an ACL rule's role.",
931
- inputSchema: {
932
- calendarId: { type: "string", required: true },
933
- ruleId: { type: "string", required: true },
934
- role: { type: "string", required: true },
935
- },
995
+ inputSchema: aclSchemas.update,
936
996
  async execute(input, ctx) {
937
997
  const p = (input ?? {});
938
998
  return calRequest(ctx, "PATCH", `/calendars/${encodeCalendarId(p.calendarId)}/acl/${encodeURIComponent(p.ruleId)}`, { role: p.role });
@@ -941,10 +1001,7 @@ export default function googleCalendar(rl) {
941
1001
  rl.registerAction("acl.delete", {
942
1002
  access: "write",
943
1003
  description: "Remove an ACL rule.",
944
- inputSchema: {
945
- calendarId: { type: "string", required: true },
946
- ruleId: { type: "string", required: true },
947
- },
1004
+ inputSchema: aclSchemas.delete,
948
1005
  async execute(input, ctx) {
949
1006
  const p = (input ?? {});
950
1007
  await calRequest(ctx, "DELETE", `/calendars/${encodeCalendarId(p.calendarId)}/acl/${encodeURIComponent(p.ruleId)}`);
@@ -955,7 +1012,7 @@ export default function googleCalendar(rl) {
955
1012
  rl.registerAction("settings.list", {
956
1013
  access: "read",
957
1014
  description: "List the user's calendar settings (timezone, week start, working location, etc.).",
958
- inputSchema: { returnAll: { type: "boolean", required: false, default: true } },
1015
+ inputSchema: settingsSchemas.list,
959
1016
  async execute(_input, ctx) {
960
1017
  return paginateAll(ctx, "/users/me/settings", "items", { maxResults: 100 });
961
1018
  },
@@ -963,7 +1020,7 @@ export default function googleCalendar(rl) {
963
1020
  rl.registerAction("settings.get", {
964
1021
  access: "read",
965
1022
  description: "Get a single setting by key (e.g. 'timezone', 'weekStart', 'locale').",
966
- inputSchema: { setting: { type: "string", required: true } },
1023
+ inputSchema: settingsSchemas.get,
967
1024
  async execute(input, ctx) {
968
1025
  const p = (input ?? {});
969
1026
  return calRequest(ctx, "GET", `/users/me/settings/${encodeURIComponent(p.setting)}`);