Skip to content

Commit 99c1903

Browse files
committed
feat(calendly): extend tools with booking, availability, no-shows, and routing forms
Adds 12 tools verified against the Calendly OpenAPI spec: get_user, get_event_invitee, create_event_invitee, list_event_type_available_times, list_user_busy_times, list_user_availability_schedules, create_scheduling_link, create/delete_invitee_no_show, list_organization_memberships, list_routing_forms, and list_routing_form_submissions. Also fixes issues found while validating the existing tools: - list_webhooks dropped the scope query param the API requires, so every call with scope unset returned 400 - list_event_types could only send active=true, making inactive event types unlistable - user and organization filters now accept a bare UUID or a full URI consistently across every operation - json array params (eventGuests, events) are normalized whether they arrive as an array or a JSON string
1 parent fee45e2 commit 99c1903

33 files changed

Lines changed: 2836 additions & 85 deletions

apps/docs/content/docs/en/integrations/calendly.mdx

Lines changed: 397 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Guards the block/tool contract: the operation dropdown, `tools.access`, the tool params, and the
3+
* declared inputs all describe the same set of operations, and drift in any one of them fails here.
4+
*
5+
* @vitest-environment node
6+
*/
7+
import { describe, expect, it } from 'vitest'
8+
import { CalendlyBlock } from '@/blocks/blocks/calendly'
9+
import * as calendlyTools from '@/tools/calendly'
10+
11+
const block: any = CalendlyBlock
12+
const byId = new Map<string, any>(Object.values(calendlyTools).map((t: any) => [t.id, t]))
13+
const ops: string[] = block.subBlocks
14+
.find((s: any) => s.id === 'operation')
15+
.options.map((o: any) => o.id)
16+
const access: string[] = block.tools.access
17+
const opSubs = block.subBlocks.filter(
18+
(s: any) => s.id === 'operation' || !s.condition || s.condition.field === 'operation'
19+
)
20+
const visibleFor = (op: string) =>
21+
opSubs
22+
.filter((s: any) => {
23+
const c = s.condition
24+
if (!c) return true
25+
return Array.isArray(c.value) ? c.value.includes(op) : c.value === op
26+
})
27+
.map((s: any) => s.id)
28+
29+
describe('calendly block/tool alignment', () => {
30+
it('every operation maps to a real tool and vice versa', () => {
31+
expect(ops.filter((o) => !access.includes(o))).toEqual([])
32+
expect(access.filter((t) => !ops.includes(t))).toEqual([])
33+
expect(access.filter((t) => !byId.has(t))).toEqual([])
34+
})
35+
36+
it('operation-gated subBlock ids are unique', () => {
37+
const ids = opSubs.map((s: any) => s.id)
38+
expect(ids.filter((v: string, i: number) => ids.indexOf(v) !== i)).toEqual([])
39+
})
40+
41+
it('every required tool param has a visible subBlock for its operation', () => {
42+
const missing: string[] = []
43+
for (const op of ops) {
44+
const tool = byId.get(op)
45+
const visible = visibleFor(op)
46+
for (const [name, p] of Object.entries<any>(tool.params)) {
47+
if (p.visibility === 'hidden' || !p.required) continue
48+
if (!visible.includes(name)) missing.push(`${op}.${name}`)
49+
}
50+
}
51+
expect(missing).toEqual([])
52+
})
53+
54+
it('every visible subBlock corresponds to a param on its operation tool', () => {
55+
const stray: string[] = []
56+
for (const op of ops) {
57+
const tool = byId.get(op)
58+
for (const id of visibleFor(op)) {
59+
if (id === 'operation' || id === 'selectedTriggerId') continue
60+
if (!tool.params[id]) stray.push(`${op}.${id}`)
61+
}
62+
}
63+
expect(stray).toEqual([])
64+
})
65+
66+
it('every operation-gated subBlock is declared in block.inputs', () => {
67+
const declared = Object.keys(block.inputs)
68+
const undeclared = opSubs
69+
.filter((s: any) => s.id !== 'operation' && s.id !== 'selectedTriggerId' && s.condition)
70+
.map((s: any) => s.id)
71+
.filter((id: string) => !declared.includes(id))
72+
expect(undeclared).toEqual([])
73+
})
74+
})

0 commit comments

Comments
 (0)