@agent-native/scheduling 0.2.1 → 0.2.2-nightly-20260927013707
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/actions/_helpers.d.ts +0 -13
- package/dist/actions/_helpers.d.ts.map +1 -1
- package/dist/actions/_helpers.js +0 -16
- package/dist/actions/_helpers.js.map +1 -1
- package/dist/actions/create-team.js +0 -1
- package/dist/actions/create-team.js.map +1 -1
- package/dist/actions/list-bookings.js +0 -4
- package/dist/actions/list-bookings.js.map +1 -1
- package/dist/actions/refresh-busy-times.js +0 -1
- package/dist/actions/refresh-busy-times.js.map +1 -1
- package/dist/actions/revoke-private-link.js +0 -2
- package/dist/actions/revoke-private-link.js.map +1 -1
- package/dist/actions/update-profile.js +0 -5
- package/dist/actions/update-profile.js.map +1 -1
- package/dist/core/buffers.d.ts +0 -18
- package/dist/core/buffers.d.ts.map +1 -1
- package/dist/core/buffers.js +0 -6
- package/dist/core/buffers.js.map +1 -1
- package/dist/core/conflicts.d.ts +0 -4
- package/dist/core/conflicts.d.ts.map +1 -1
- package/dist/core/conflicts.js +0 -1
- package/dist/core/conflicts.js.map +1 -1
- package/dist/core/limits.d.ts +0 -8
- package/dist/core/limits.d.ts.map +1 -1
- package/dist/core/limits.js.map +1 -1
- package/dist/core/round-robin.d.ts +0 -17
- package/dist/core/round-robin.d.ts.map +1 -1
- package/dist/core/round-robin.js.map +1 -1
- package/dist/core/rrule.d.ts.map +1 -1
- package/dist/core/rrule.js +0 -7
- package/dist/core/rrule.js.map +1 -1
- package/dist/core/rules.d.ts +0 -17
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js +0 -8
- package/dist/core/rules.js.map +1 -1
- package/dist/core/slots.d.ts +0 -31
- package/dist/core/slots.d.ts.map +1 -1
- package/dist/core/slots.js +0 -9
- package/dist/core/slots.js.map +1 -1
- package/dist/core/time.d.ts +0 -24
- package/dist/core/time.d.ts.map +1 -1
- package/dist/core/time.js +0 -37
- package/dist/core/time.js.map +1 -1
- package/dist/index.d.ts +0 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -10
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +0 -9
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +0 -18
- package/dist/manifest.js.map +1 -1
- package/dist/react/components/SlotPicker.d.ts +0 -8
- package/dist/react/components/SlotPicker.d.ts.map +1 -1
- package/dist/react/components/SlotPicker.js.map +1 -1
- package/dist/react/components/TimezoneSelect.d.ts.map +1 -1
- package/dist/react/components/TimezoneSelect.js +0 -2
- package/dist/react/components/TimezoneSelect.js.map +1 -1
- package/dist/react/components/booking-links/AvailabilityEditor.d.ts +0 -4
- package/dist/react/components/booking-links/AvailabilityEditor.d.ts.map +1 -1
- package/dist/react/components/booking-links/AvailabilityEditor.js +0 -15
- package/dist/react/components/booking-links/AvailabilityEditor.js.map +1 -1
- package/dist/react/components/booking-links/BookingLinkCreateDialog.d.ts +0 -6
- package/dist/react/components/booking-links/BookingLinkCreateDialog.d.ts.map +1 -1
- package/dist/react/components/booking-links/BookingLinkCreateDialog.js +0 -16
- package/dist/react/components/booking-links/BookingLinkCreateDialog.js.map +1 -1
- package/dist/react/components/booking-links/ConferencingSelector.d.ts +0 -2
- package/dist/react/components/booking-links/ConferencingSelector.d.ts.map +1 -1
- package/dist/react/components/booking-links/ConferencingSelector.js +0 -24
- package/dist/react/components/booking-links/ConferencingSelector.js.map +1 -1
- package/dist/react/components/booking-links/CustomFieldsEditor.d.ts +0 -1
- package/dist/react/components/booking-links/CustomFieldsEditor.d.ts.map +1 -1
- package/dist/react/components/booking-links/CustomFieldsEditor.js +0 -14
- package/dist/react/components/booking-links/CustomFieldsEditor.js.map +1 -1
- package/dist/react/components/booking-links/DurationPicker.d.ts +0 -1
- package/dist/react/components/booking-links/DurationPicker.d.ts.map +1 -1
- package/dist/react/components/booking-links/DurationPicker.js +1 -11
- package/dist/react/components/booking-links/DurationPicker.js.map +1 -1
- package/dist/react/components/booking-links/SlugEditor.d.ts +0 -3
- package/dist/react/components/booking-links/SlugEditor.d.ts.map +1 -1
- package/dist/react/components/booking-links/SlugEditor.js +0 -11
- package/dist/react/components/booking-links/SlugEditor.js.map +1 -1
- package/dist/react/components/booking-links/index.d.ts +0 -9
- package/dist/react/components/booking-links/index.d.ts.map +1 -1
- package/dist/react/components/booking-links/index.js +0 -9
- package/dist/react/components/booking-links/index.js.map +1 -1
- package/dist/react/components/index.d.ts +0 -10
- package/dist/react/components/index.d.ts.map +1 -1
- package/dist/react/components/index.js +0 -10
- package/dist/react/components/index.js.map +1 -1
- package/dist/react/hooks/useBookingFlow.d.ts.map +1 -1
- package/dist/react/hooks/useBookingFlow.js +0 -10
- package/dist/react/hooks/useBookingFlow.js.map +1 -1
- package/dist/react/hooks/useEventType.d.ts.map +1 -1
- package/dist/react/hooks/useEventType.js +0 -4
- package/dist/react/hooks/useEventType.js.map +1 -1
- package/dist/react/hooks/useReschedule.d.ts.map +1 -1
- package/dist/react/hooks/useReschedule.js +0 -4
- package/dist/react/hooks/useReschedule.js.map +1 -1
- package/dist/react/hooks/useSlots.d.ts +0 -2
- package/dist/react/hooks/useSlots.d.ts.map +1 -1
- package/dist/react/hooks/useSlots.js +0 -8
- package/dist/react/hooks/useSlots.js.map +1 -1
- package/dist/react/hooks/useTimezone.d.ts.map +1 -1
- package/dist/react/hooks/useTimezone.js +0 -4
- package/dist/react/hooks/useTimezone.js.map +1 -1
- package/dist/react/index.d.ts +0 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +0 -5
- package/dist/react/index.js.map +1 -1
- package/dist/schema/bookings.d.ts +0 -7
- package/dist/schema/bookings.d.ts.map +1 -1
- package/dist/schema/bookings.js +0 -29
- package/dist/schema/bookings.js.map +1 -1
- package/dist/schema/calendar-cache.d.ts.map +1 -1
- package/dist/schema/calendar-cache.js +0 -11
- package/dist/schema/calendar-cache.js.map +1 -1
- package/dist/schema/credentials.d.ts +0 -8
- package/dist/schema/credentials.d.ts.map +1 -1
- package/dist/schema/credentials.js +0 -28
- package/dist/schema/credentials.js.map +1 -1
- package/dist/schema/event-types.d.ts +0 -10
- package/dist/schema/event-types.d.ts.map +1 -1
- package/dist/schema/event-types.js +0 -42
- package/dist/schema/event-types.js.map +1 -1
- package/dist/schema/index.d.ts +0 -11
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +0 -11
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/routing-forms.d.ts.map +1 -1
- package/dist/schema/routing-forms.js +0 -17
- package/dist/schema/routing-forms.js.map +1 -1
- package/dist/schema/schedules.d.ts +0 -12
- package/dist/schema/schedules.d.ts.map +1 -1
- package/dist/schema/schedules.js +0 -25
- package/dist/schema/schedules.js.map +1 -1
- package/dist/schema/teams.d.ts.map +1 -1
- package/dist/schema/teams.js +0 -7
- package/dist/schema/teams.js.map +1 -1
- package/dist/schema/workflows.d.ts +0 -7
- package/dist/schema/workflows.d.ts.map +1 -1
- package/dist/schema/workflows.js +0 -19
- package/dist/schema/workflows.js.map +1 -1
- package/dist/server/availability-engine.d.ts +0 -12
- package/dist/server/availability-engine.d.ts.map +1 -1
- package/dist/server/availability-engine.js +0 -20
- package/dist/server/availability-engine.js.map +1 -1
- package/dist/server/booking-service.d.ts +0 -14
- package/dist/server/booking-service.d.ts.map +1 -1
- package/dist/server/booking-service.js +0 -8
- package/dist/server/booking-service.js.map +1 -1
- package/dist/server/bookings-repo.d.ts +0 -7
- package/dist/server/bookings-repo.d.ts.map +1 -1
- package/dist/server/bookings-repo.js +0 -3
- package/dist/server/bookings-repo.js.map +1 -1
- package/dist/server/context.d.ts +0 -16
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js.map +1 -1
- package/dist/server/db-types.d.ts +0 -11
- package/dist/server/db-types.d.ts.map +1 -1
- package/dist/server/event-types-repo.d.ts +0 -10
- package/dist/server/event-types-repo.d.ts.map +1 -1
- package/dist/server/event-types-repo.js +0 -21
- package/dist/server/event-types-repo.js.map +1 -1
- package/dist/server/hooks.d.ts.map +1 -1
- package/dist/server/hooks.js +0 -11
- package/dist/server/hooks.js.map +1 -1
- package/dist/server/ics.d.ts +0 -7
- package/dist/server/ics.d.ts.map +1 -1
- package/dist/server/ics.js.map +1 -1
- package/dist/server/providers/builtin-video.d.ts +0 -5
- package/dist/server/providers/builtin-video.d.ts.map +1 -1
- package/dist/server/providers/builtin-video.js.map +1 -1
- package/dist/server/providers/google-calendar.d.ts +0 -3
- package/dist/server/providers/google-calendar.d.ts.map +1 -1
- package/dist/server/providers/google-calendar.js +0 -2
- package/dist/server/providers/google-calendar.js.map +1 -1
- package/dist/server/providers/google-meet.d.ts +0 -7
- package/dist/server/providers/google-meet.d.ts.map +1 -1
- package/dist/server/providers/google-meet.js.map +1 -1
- package/dist/server/providers/office365.d.ts +0 -6
- package/dist/server/providers/office365.d.ts.map +1 -1
- package/dist/server/providers/office365.js.map +1 -1
- package/dist/server/providers/registry.d.ts +0 -4
- package/dist/server/providers/registry.d.ts.map +1 -1
- package/dist/server/providers/registry.js.map +1 -1
- package/dist/server/providers/teams.d.ts +0 -6
- package/dist/server/providers/teams.d.ts.map +1 -1
- package/dist/server/providers/teams.js +0 -2
- package/dist/server/providers/teams.js.map +1 -1
- package/dist/server/providers/types.d.ts +0 -27
- package/dist/server/providers/types.d.ts.map +1 -1
- package/dist/server/providers/zoom.d.ts +0 -19
- package/dist/server/providers/zoom.d.ts.map +1 -1
- package/dist/server/providers/zoom.js +0 -2
- package/dist/server/providers/zoom.js.map +1 -1
- package/dist/server/schedules-repo.d.ts.map +1 -1
- package/dist/server/schedules-repo.js +0 -4
- package/dist/server/schedules-repo.js.map +1 -1
- package/dist/server/video-oauth-state.d.ts +0 -5
- package/dist/server/video-oauth-state.d.ts.map +1 -1
- package/dist/server/video-oauth-state.js +1 -9
- package/dist/server/video-oauth-state.js.map +1 -1
- package/dist/server/video-oauth.d.ts +0 -4
- package/dist/server/video-oauth.d.ts.map +1 -1
- package/dist/server/video-oauth.js +0 -23
- package/dist/server/video-oauth.js.map +1 -1
- package/dist/shared/index.d.ts +0 -37
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +0 -4
- package/dist/shared/index.js.map +1 -1
- package/package.json +4 -4
- package/src/actions/_helpers.ts +0 -16
- package/src/actions/booking-authz.spec.ts +0 -6
- package/src/actions/create-team.ts +0 -1
- package/src/actions/event-type-authz.spec.ts +0 -11
- package/src/actions/list-bookings.ts +0 -4
- package/src/actions/refresh-busy-times.ts +0 -1
- package/src/actions/revoke-private-link.ts +0 -2
- package/src/actions/update-profile.ts +0 -5
- package/src/core/buffers.ts +0 -18
- package/src/core/conflicts.ts +0 -4
- package/src/core/limits.ts +0 -8
- package/src/core/round-robin.test.ts +0 -1
- package/src/core/round-robin.ts +0 -17
- package/src/core/rrule.ts +0 -7
- package/src/core/rules.ts +0 -17
- package/src/core/slots.test.ts +1 -11
- package/src/core/slots.ts +0 -40
- package/src/core/time.ts +0 -37
- package/src/index.ts +0 -11
- package/src/manifest.ts +0 -19
- package/src/react/components/SlotPicker.tsx +0 -8
- package/src/react/components/TimezoneSelect.tsx +0 -2
- package/src/react/components/_shadcn-shims.d.ts +0 -35
- package/src/react/components/booking-links/AvailabilityEditor.tsx +0 -15
- package/src/react/components/booking-links/BookingLinkCreateDialog.tsx +0 -22
- package/src/react/components/booking-links/ConferencingSelector.tsx +0 -26
- package/src/react/components/booking-links/CustomFieldsEditor.tsx +0 -15
- package/src/react/components/booking-links/DurationPicker.tsx +1 -12
- package/src/react/components/booking-links/SlugEditor.tsx +0 -14
- package/src/react/components/booking-links/index.ts +0 -9
- package/src/react/components/index.ts +0 -10
- package/src/react/hooks/useBookingFlow.ts +0 -10
- package/src/react/hooks/useEventType.ts +0 -4
- package/src/react/hooks/useReschedule.ts +0 -4
- package/src/react/hooks/useSlots.ts +0 -10
- package/src/react/hooks/useTimezone.ts +0 -4
- package/src/react/index.ts +0 -5
- package/src/schema/bookings.ts +0 -29
- package/src/schema/calendar-cache.ts +0 -11
- package/src/schema/credentials.ts +0 -28
- package/src/schema/event-types.ts +0 -42
- package/src/schema/index.ts +0 -11
- package/src/schema/routing-forms.ts +0 -17
- package/src/schema/schedules.ts +0 -25
- package/src/schema/teams.ts +0 -7
- package/src/schema/workflows.ts +0 -19
- package/src/server/availability-engine.test.ts +0 -1
- package/src/server/availability-engine.ts +0 -22
- package/src/server/booking-service.spec.ts +0 -15
- package/src/server/booking-service.ts +0 -22
- package/src/server/bookings-repo.ts +0 -10
- package/src/server/context.ts +0 -16
- package/src/server/db-types.ts +0 -11
- package/src/server/event-types-repo.ts +0 -31
- package/src/server/hooks.ts +0 -11
- package/src/server/ics.ts +0 -7
- package/src/server/providers/builtin-video.ts +0 -5
- package/src/server/providers/google-calendar.ts +0 -5
- package/src/server/providers/google-meet.ts +0 -7
- package/src/server/providers/office365.ts +0 -6
- package/src/server/providers/registry.ts +0 -4
- package/src/server/providers/teams.ts +0 -8
- package/src/server/providers/types.ts +0 -27
- package/src/server/providers/zoom.ts +0 -21
- package/src/server/schedules-repo.ts +0 -4
- package/src/server/video-oauth-state.ts +1 -10
- package/src/server/video-oauth.ts +0 -23
- package/src/shared/index.ts +0 -38
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import { accessFilter } from "@agent-native/core/sharing";
|
|
2
|
-
/**
|
|
3
|
-
* Data access for event types.
|
|
4
|
-
*
|
|
5
|
-
* All write paths funnel through here so ownership, slug uniqueness, and
|
|
6
|
-
* redirect history are handled consistently.
|
|
7
|
-
*/
|
|
8
2
|
import { eq, and } from "drizzle-orm";
|
|
9
3
|
import { nanoid } from "nanoid";
|
|
10
4
|
|
|
@@ -75,29 +69,15 @@ function parseJson<T = any>(str: string | null | undefined): T | undefined {
|
|
|
75
69
|
}
|
|
76
70
|
|
|
77
71
|
export async function listEventTypes(params: {
|
|
78
|
-
/**
|
|
79
|
-
* If provided and `useAccessFilter` is not true, narrow rows to this owner.
|
|
80
|
-
* For org-aware list calls, prefer `useAccessFilter: true` instead.
|
|
81
|
-
*/
|
|
82
72
|
ownerEmail?: string;
|
|
83
73
|
teamId?: string;
|
|
84
74
|
includeHidden?: boolean;
|
|
85
|
-
/**
|
|
86
|
-
* When true, apply the framework `accessFilter` (owner OR shared OR
|
|
87
|
-
* org-visibility OR public) instead of plain ownerEmail equality. This is
|
|
88
|
-
* the right mode for any UI/agent listing, since it admits org-shared and
|
|
89
|
-
* explicitly-shared event types in addition to the user's own.
|
|
90
|
-
*/
|
|
91
75
|
useAccessFilter?: boolean;
|
|
92
76
|
}): Promise<EventType[]> {
|
|
93
77
|
const { getDb, schema } = getSchedulingContext();
|
|
94
78
|
const db = getDb();
|
|
95
79
|
let rows: any[];
|
|
96
80
|
if (params.teamId) {
|
|
97
|
-
// Team-scoped listings. Callers are responsible for asserting team
|
|
98
|
-
// membership before invoking — the repo does not (it runs without a
|
|
99
|
-
// request context in some paths, e.g. public booking pages that
|
|
100
|
-
// explicitly pass a teamId).
|
|
101
81
|
rows = await db
|
|
102
82
|
.select()
|
|
103
83
|
.from(schema.eventTypes)
|
|
@@ -113,8 +93,6 @@ export async function listEventTypes(params: {
|
|
|
113
93
|
.from(schema.eventTypes)
|
|
114
94
|
.where(eq(schema.eventTypes.ownerEmail, params.ownerEmail));
|
|
115
95
|
} else {
|
|
116
|
-
// Refuse to return unscoped results. Callers must supply at least
|
|
117
|
-
// one of: teamId, useAccessFilter, or ownerEmail.
|
|
118
96
|
return [];
|
|
119
97
|
}
|
|
120
98
|
return rows
|
|
@@ -185,9 +163,6 @@ export async function createEventType(input: {
|
|
|
185
163
|
const db = getDb();
|
|
186
164
|
const now = new Date().toISOString();
|
|
187
165
|
const id = nanoid();
|
|
188
|
-
// Default location: the user's `isDefault` conferencing credential if they
|
|
189
|
-
// have one installed (Zoom, Meet, Teams), otherwise no location — the
|
|
190
|
-
// editor will prompt them to pick.
|
|
191
166
|
const defaultLocations: Location[] =
|
|
192
167
|
input.locations ??
|
|
193
168
|
(input.ownerEmail ? await resolveDefaultLocation(input.ownerEmail) : []);
|
|
@@ -242,7 +217,6 @@ export async function updateEventType(
|
|
|
242
217
|
const dbPatch: Record<string, any> = {};
|
|
243
218
|
if (patch.title != null) dbPatch.title = patch.title;
|
|
244
219
|
if (patch.slug != null && patch.slug !== current.slug) {
|
|
245
|
-
// Record slug redirect
|
|
246
220
|
const oldKey = keyFor(
|
|
247
221
|
current.ownerEmail ?? null,
|
|
248
222
|
current.teamId ?? null,
|
|
@@ -337,11 +311,6 @@ export async function deleteEventType(id: string): Promise<void> {
|
|
|
337
311
|
await getDb().delete(schema.eventTypes).where(eq(schema.eventTypes.id, id));
|
|
338
312
|
}
|
|
339
313
|
|
|
340
|
-
/**
|
|
341
|
-
* Return a sensible default location for a freshly-created event type.
|
|
342
|
-
* Priority: the user's `isDefault` video conferencing credential → the
|
|
343
|
-
* first installed video credential → an empty list (editor prompts user).
|
|
344
|
-
*/
|
|
345
314
|
async function resolveDefaultLocation(ownerEmail: string): Promise<Location[]> {
|
|
346
315
|
const { getDb, schema } = getSchedulingContext();
|
|
347
316
|
const rows = await getDb()
|
package/src/server/hooks.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Booking lifecycle hooks → workflow / webhook dispatcher.
|
|
3
|
-
*
|
|
4
|
-
* When a booking is created / rescheduled / cancelled / no-shown, we:
|
|
5
|
-
* - Materialize scheduled reminders for each active workflow step
|
|
6
|
-
* - Enqueue outgoing webhook deliveries
|
|
7
|
-
*
|
|
8
|
-
* The actual reminder + webhook firing happens on a recurring job (not here).
|
|
9
|
-
*/
|
|
10
1
|
import { eq, and, inArray } from "drizzle-orm";
|
|
11
2
|
import { nanoid } from "nanoid";
|
|
12
3
|
|
|
@@ -31,7 +22,6 @@ export async function onBookingRescheduled(
|
|
|
31
22
|
export async function onBookingCancelled(booking: Booking): Promise<void> {
|
|
32
23
|
await materializeReminders(booking, "cancellation");
|
|
33
24
|
await enqueueWebhooks(booking, "BOOKING_CANCELLED");
|
|
34
|
-
// Cancel any pending before-event reminders
|
|
35
25
|
const { getDb, schema } = getSchedulingContext();
|
|
36
26
|
await getDb()
|
|
37
27
|
.update(schema.scheduledReminders)
|
|
@@ -74,7 +64,6 @@ async function materializeRemindersBefore(booking: Booking): Promise<void> {
|
|
|
74
64
|
const start = new Date(booking.startTime);
|
|
75
65
|
for (const wf of workflows) {
|
|
76
66
|
for (const step of wf.steps) {
|
|
77
|
-
// offsetMinutes is how many minutes BEFORE the event
|
|
78
67
|
const scheduledFor = addMinutes(start, -Math.abs(step.offsetMinutes));
|
|
79
68
|
if (scheduledFor <= new Date()) continue;
|
|
80
69
|
await writeReminder(booking, step, scheduledFor);
|
package/src/server/ics.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal iCalendar (RFC 5545) generator for booking confirmation emails and
|
|
3
|
-
* the `/booking/:uid.ics` download endpoint.
|
|
4
|
-
*
|
|
5
|
-
* Not exhaustive — just enough for Apple Mail / Outlook / Gmail to render
|
|
6
|
-
* the event card correctly and for Add-to-Calendar buttons to work.
|
|
7
|
-
*/
|
|
8
1
|
import type { Booking } from "../shared/index.js";
|
|
9
2
|
|
|
10
3
|
export function buildIcs(booking: Booking, organizerName: string): string {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Built-in video provider (Daily.co) — zero-OAuth video provider driven by a
|
|
3
|
-
* server-to-server API key. Creates a Daily.co room per booking.
|
|
4
|
-
*/
|
|
5
1
|
import type { VideoProvider } from "./types.js";
|
|
6
2
|
|
|
7
3
|
export interface DailyVideoProviderConfig {
|
|
8
4
|
apiKey: string;
|
|
9
|
-
/** Prefix for Daily room names; defaults to "room-" */
|
|
10
5
|
roomPrefix?: string;
|
|
11
6
|
}
|
|
12
7
|
|
|
@@ -15,14 +15,11 @@ import type { CalendarProvider } from "./types.js";
|
|
|
15
15
|
export interface GoogleCalendarProviderConfig {
|
|
16
16
|
clientId: string;
|
|
17
17
|
clientSecret: string;
|
|
18
|
-
/** Resolve a fresh access token for a given credentialId (refresh if needed). */
|
|
19
18
|
getAccessToken: (credentialId: string) => Promise<string>;
|
|
20
|
-
/** Persist updated refresh/access tokens after a refresh. */
|
|
21
19
|
updateTokens?: (
|
|
22
20
|
credentialId: string,
|
|
23
21
|
tokens: { accessToken: string; refreshToken?: string; expiresAt?: Date },
|
|
24
22
|
) => Promise<void>;
|
|
25
|
-
/** Called when the API returns 401/403; the consumer should mark the credential invalid. */
|
|
26
23
|
markInvalid?: (credentialId: string) => Promise<void>;
|
|
27
24
|
}
|
|
28
25
|
|
|
@@ -104,7 +101,6 @@ export function createGoogleCalendarProvider(
|
|
|
104
101
|
expiresAt: new Date(Date.now() + (tokens.expires_in ?? 3600) * 1000),
|
|
105
102
|
});
|
|
106
103
|
|
|
107
|
-
// Discover external email + calendar list
|
|
108
104
|
const calendars = await apiCall<{
|
|
109
105
|
items: { id: string; summary: string; primary?: boolean }[];
|
|
110
106
|
}>(
|
|
@@ -208,7 +204,6 @@ export function createGoogleCalendarProvider(
|
|
|
208
204
|
},
|
|
209
205
|
|
|
210
206
|
async updateEvent({ credentialId, externalId, booking }) {
|
|
211
|
-
// Bump sequence for RFC 5545 compliance
|
|
212
207
|
const newSeq = booking.iCalSequence + 1;
|
|
213
208
|
const body = {
|
|
214
209
|
summary: booking.title,
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google Meet — piggy-backs on Google Calendar credentials. The meeting link
|
|
3
|
-
* is created as part of the calendar event (conferenceData). This provider
|
|
4
|
-
* exists so we can list Google Meet as an installable conferencing option in
|
|
5
|
-
* the UI; the actual meeting creation happens in `google-calendar.createEvent`
|
|
6
|
-
* when `includeConference` is true.
|
|
7
|
-
*/
|
|
8
1
|
import type { VideoProvider } from "./types.js";
|
|
9
2
|
|
|
10
3
|
export const googleMeetProvider: VideoProvider = {
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import type { BusyInterval } from "../../shared/index.js";
|
|
2
|
-
/**
|
|
3
|
-
* Office 365 / Outlook calendar provider via Microsoft Graph.
|
|
4
|
-
*
|
|
5
|
-
* Token flow is identical to Google but against login.microsoftonline.com.
|
|
6
|
-
* Uses Microsoft Graph API for calendars and events.
|
|
7
|
-
*/
|
|
8
2
|
import type { CalendarProvider } from "./types.js";
|
|
9
3
|
|
|
10
4
|
export interface Office365ProviderConfig {
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider registry — consumers register calendar/video/SMS providers at
|
|
3
|
-
* startup. Actions look up providers by kind.
|
|
4
|
-
*/
|
|
5
1
|
import type { CalendarProvider, VideoProvider, SmsProvider } from "./types.js";
|
|
6
2
|
|
|
7
3
|
const calendarProviders = new Map<string, CalendarProvider>();
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Microsoft Teams provider — delegated Microsoft OAuth with Graph-backed
|
|
3
|
-
* standalone online meetings.
|
|
4
|
-
*/
|
|
5
1
|
import type { VideoProvider } from "./types.js";
|
|
6
2
|
|
|
7
3
|
export interface TeamsProviderConfig {
|
|
8
4
|
clientId: string;
|
|
9
5
|
clientSecret: string;
|
|
10
|
-
/** Microsoft tenant id/domain; defaults to work-or-school accounts. */
|
|
11
6
|
tenant?: string;
|
|
12
7
|
getAccessToken: (credentialId: string) => Promise<string>;
|
|
13
8
|
updateTokens?: (
|
|
@@ -19,7 +14,6 @@ export interface TeamsProviderConfig {
|
|
|
19
14
|
rawResponse?: Record<string, unknown>;
|
|
20
15
|
},
|
|
21
16
|
) => Promise<void>;
|
|
22
|
-
/** Called when Graph returns 401/403; mark the credential invalid in UI. */
|
|
23
17
|
markInvalid?: (credentialId: string) => Promise<void>;
|
|
24
18
|
}
|
|
25
19
|
|
|
@@ -106,8 +100,6 @@ export function createTeamsProvider(
|
|
|
106
100
|
rawResponse: tokens,
|
|
107
101
|
});
|
|
108
102
|
|
|
109
|
-
// Use the token from this exchange directly. The consumer's token store
|
|
110
|
-
// may not be observable through getAccessToken until after this callback.
|
|
111
103
|
const identityResponse = await fetch(
|
|
112
104
|
`${GRAPH_BASE_URL}/me?$select=id,mail,userPrincipalName,displayName`,
|
|
113
105
|
{ headers: { authorization: `Bearer ${tokens.access_token}` } },
|
|
@@ -1,29 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pluggable provider interfaces for calendar reads and video-meeting writes.
|
|
3
|
-
*
|
|
4
|
-
* Consumers register providers via the registry. Each provider owns its own
|
|
5
|
-
* OAuth/credential lifecycle; this package is agnostic to how the tokens
|
|
6
|
-
* are stored (typically in core `oauth_tokens`).
|
|
7
|
-
*/
|
|
8
1
|
import type { BusyInterval, Booking } from "../../shared/index.js";
|
|
9
2
|
|
|
10
3
|
export interface CalendarProvider {
|
|
11
|
-
/** Unique provider slug, e.g. "google_calendar" */
|
|
12
4
|
kind: string;
|
|
13
5
|
|
|
14
|
-
/** Human-friendly display name, e.g. "Google Calendar" */
|
|
15
6
|
label: string;
|
|
16
7
|
|
|
17
|
-
/**
|
|
18
|
-
* Start the OAuth flow — return an authorization URL for the user to visit.
|
|
19
|
-
* `redirectUri` is the server's OAuth callback path for this provider.
|
|
20
|
-
*/
|
|
21
8
|
startOAuth(opts: {
|
|
22
9
|
redirectUri: string;
|
|
23
10
|
state: string;
|
|
24
11
|
}): Promise<{ authUrl: string }>;
|
|
25
12
|
|
|
26
|
-
/** Complete the OAuth flow with the received code; persist the credential. */
|
|
27
13
|
completeOAuth(opts: {
|
|
28
14
|
credentialId: string;
|
|
29
15
|
userEmail: string;
|
|
@@ -34,12 +20,10 @@ export interface CalendarProvider {
|
|
|
34
20
|
calendars: { externalId: string; name: string; primary: boolean }[];
|
|
35
21
|
}>;
|
|
36
22
|
|
|
37
|
-
/** List the calendars the user has access to (for Selected Calendars UI). */
|
|
38
23
|
listCalendars(opts: {
|
|
39
24
|
credentialId: string;
|
|
40
25
|
}): Promise<{ externalId: string; name: string; primary: boolean }[]>;
|
|
41
26
|
|
|
42
|
-
/** Read busy intervals across the user's selected calendars. */
|
|
43
27
|
getBusy(opts: {
|
|
44
28
|
credentialId: string;
|
|
45
29
|
calendarExternalIds: string[];
|
|
@@ -47,7 +31,6 @@ export interface CalendarProvider {
|
|
|
47
31
|
end: Date;
|
|
48
32
|
}): Promise<BusyInterval[]>;
|
|
49
33
|
|
|
50
|
-
/** Create a calendar event; return the external id. */
|
|
51
34
|
createEvent(opts: {
|
|
52
35
|
credentialId: string;
|
|
53
36
|
calendarExternalId: string;
|
|
@@ -59,14 +42,12 @@ export interface CalendarProvider {
|
|
|
59
42
|
icalUid?: string;
|
|
60
43
|
}>;
|
|
61
44
|
|
|
62
|
-
/** Update (e.g. after reschedule). Returns the new iCalSequence. */
|
|
63
45
|
updateEvent(opts: {
|
|
64
46
|
credentialId: string;
|
|
65
47
|
externalId: string;
|
|
66
48
|
booking: Booking;
|
|
67
49
|
}): Promise<{ iCalSequence: number }>;
|
|
68
50
|
|
|
69
|
-
/** Delete/cancel an event. */
|
|
70
51
|
deleteEvent(opts: {
|
|
71
52
|
credentialId: string;
|
|
72
53
|
externalId: string;
|
|
@@ -88,12 +69,6 @@ export interface VideoProvider {
|
|
|
88
69
|
state: string;
|
|
89
70
|
}): Promise<{ authUrl: string }>;
|
|
90
71
|
|
|
91
|
-
/**
|
|
92
|
-
* Complete the OAuth flow — optional. Paired with `startOAuth`. Consumers
|
|
93
|
-
* call this from their OAuth callback handler to exchange the `code` for
|
|
94
|
-
* tokens and return identifying info so a `scheduling_credentials` row
|
|
95
|
-
* can be written.
|
|
96
|
-
*/
|
|
97
72
|
completeOAuth?(opts: {
|
|
98
73
|
credentialId: string;
|
|
99
74
|
userEmail: string;
|
|
@@ -105,14 +80,12 @@ export interface VideoProvider {
|
|
|
105
80
|
displayName?: string;
|
|
106
81
|
}>;
|
|
107
82
|
|
|
108
|
-
/** Create a meeting room for a booking. */
|
|
109
83
|
createMeeting(opts: { credentialId?: string; booking: Booking }): Promise<{
|
|
110
84
|
meetingUrl: string;
|
|
111
85
|
meetingId: string;
|
|
112
86
|
meetingPassword?: string;
|
|
113
87
|
}>;
|
|
114
88
|
|
|
115
|
-
/** Delete the meeting when the booking is cancelled. */
|
|
116
89
|
deleteMeeting?(opts: {
|
|
117
90
|
credentialId?: string;
|
|
118
91
|
meetingId: string;
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Zoom provider — OAuth-based; creates a Zoom meeting per booking.
|
|
3
|
-
*
|
|
4
|
-
* Tokens are stored via the consumer's callback (typically core's
|
|
5
|
-
* oauth_tokens), keyed by credentialId. Consumers wire up
|
|
6
|
-
* `getAccessToken` + `updateTokens` against their token store.
|
|
7
|
-
*
|
|
8
|
-
* OAuth:
|
|
9
|
-
* - Auth URL: https://zoom.us/oauth/authorize?response_type=code&...
|
|
10
|
-
* - Token URL: https://zoom.us/oauth/token (basic-auth client_id:secret)
|
|
11
|
-
* - Scopes: meeting:write meeting:read (so we can create + delete)
|
|
12
|
-
* - User info: GET https://api.zoom.us/v2/users/me (returns account_id + email)
|
|
13
|
-
*/
|
|
14
1
|
import type { VideoProvider } from "./types.js";
|
|
15
2
|
|
|
16
3
|
export class ZoomProviderError extends Error {
|
|
@@ -27,11 +14,6 @@ export interface ZoomProviderConfig {
|
|
|
27
14
|
clientId: string;
|
|
28
15
|
clientSecret: string;
|
|
29
16
|
getAccessToken: (credentialId: string) => Promise<string>;
|
|
30
|
-
/**
|
|
31
|
-
* Persist tokens after `completeOAuth` (and any later refresh). Optional —
|
|
32
|
-
* if omitted, the consumer is responsible for doing the write inside their
|
|
33
|
-
* own callback handler.
|
|
34
|
-
*/
|
|
35
17
|
updateTokens?: (
|
|
36
18
|
credentialId: string,
|
|
37
19
|
tokens: {
|
|
@@ -41,11 +23,9 @@ export interface ZoomProviderConfig {
|
|
|
41
23
|
rawResponse?: Record<string, unknown>;
|
|
42
24
|
},
|
|
43
25
|
) => Promise<void>;
|
|
44
|
-
/** Called when the API returns 401/403; mark credential invalid in UI. */
|
|
45
26
|
markInvalid?: (credentialId: string) => Promise<void>;
|
|
46
27
|
}
|
|
47
28
|
|
|
48
|
-
// Minimum scope needed to create + read meetings on the user's behalf.
|
|
49
29
|
const SCOPES = ["meeting:write", "meeting:read", "user:read"];
|
|
50
30
|
|
|
51
31
|
export function createZoomProvider(config: ZoomProviderConfig): VideoProvider {
|
|
@@ -103,7 +83,6 @@ export function createZoomProvider(config: ZoomProviderConfig): VideoProvider {
|
|
|
103
83
|
rawResponse: tokens as unknown as Record<string, unknown>,
|
|
104
84
|
});
|
|
105
85
|
|
|
106
|
-
// Pull user info to label the credential.
|
|
107
86
|
const userRes = await fetch("https://api.zoom.us/v2/users/me", {
|
|
108
87
|
headers: { authorization: `Bearer ${tokens.access_token}` },
|
|
109
88
|
});
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { accessFilter } from "@agent-native/core/sharing";
|
|
2
|
-
/**
|
|
3
|
-
* Data access for schedules — the weekly-hours + date-override definitions
|
|
4
|
-
* that event types reference.
|
|
5
|
-
*/
|
|
6
2
|
import { eq, and, inArray, type SQL } from "drizzle-orm";
|
|
7
3
|
import { nanoid } from "nanoid";
|
|
8
4
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import crypto from "node:crypto";
|
|
19
19
|
|
|
20
20
|
const SEPARATOR = ".";
|
|
21
|
-
const STATE_TTL_MS = 10 * 60 * 1000;
|
|
21
|
+
const STATE_TTL_MS = 10 * 60 * 1000;
|
|
22
22
|
|
|
23
23
|
function getStateSecret(): string {
|
|
24
24
|
const secret =
|
|
@@ -46,16 +46,9 @@ function hmac(message: string, secret: string): string {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
function safeFragment(value: string): string {
|
|
49
|
-
// The encoded payload uses dots as separators, so any literal dot in the
|
|
50
|
-
// user email would corrupt parsing. Replace dots and any non-printable
|
|
51
|
-
// characters before signing.
|
|
52
49
|
return value.replace(/[^A-Za-z0-9_@-]/g, "_");
|
|
53
50
|
}
|
|
54
51
|
|
|
55
|
-
/**
|
|
56
|
-
* Mint a fresh signed state value bound to the current authenticated user
|
|
57
|
-
* and the requested OAuth `kind`.
|
|
58
|
-
*/
|
|
59
52
|
export function signVideoOAuthState(opts: {
|
|
60
53
|
kind: string;
|
|
61
54
|
userEmail: string;
|
|
@@ -85,7 +78,6 @@ export function verifyVideoOAuthState(opts: {
|
|
|
85
78
|
state: string | undefined | null;
|
|
86
79
|
kind: string;
|
|
87
80
|
userEmail: string;
|
|
88
|
-
/** Override default 10-minute TTL (for tests). */
|
|
89
81
|
ttlMs?: number;
|
|
90
82
|
}): boolean {
|
|
91
83
|
if (!opts.state || typeof opts.state !== "string") return false;
|
|
@@ -106,7 +98,6 @@ export function verifyVideoOAuthState(opts: {
|
|
|
106
98
|
if (a.length !== b.length) return false;
|
|
107
99
|
if (!crypto.timingSafeEqual(a, b)) return false;
|
|
108
100
|
|
|
109
|
-
// Freshness check.
|
|
110
101
|
const ttl = opts.ttlMs ?? STATE_TTL_MS;
|
|
111
102
|
const issuedAt = Number.parseInt(timestamp, 36);
|
|
112
103
|
if (!Number.isFinite(issuedAt)) return false;
|
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import { eq } from "drizzle-orm";
|
|
2
|
-
/**
|
|
3
|
-
* Server-side helper for completing video conferencing OAuth callbacks.
|
|
4
|
-
*
|
|
5
|
-
* Templates mount this under `/_agent-native/oauth/<kind>/callback.get.ts`
|
|
6
|
-
* and forward the h3 event. The helper:
|
|
7
|
-
* 1. Looks up the video provider by kind
|
|
8
|
-
* 2. Allocates a `scheduling_credentials` row (so `credentialId` is stable)
|
|
9
|
-
* 3. Calls the provider's `completeOAuth` (tokens get persisted via the
|
|
10
|
-
* provider's `updateTokens` callback, typically against core's
|
|
11
|
-
* `oauth_tokens` table, keyed by `credentialId`)
|
|
12
|
-
* 4. Updates the credential row with display metadata
|
|
13
|
-
*
|
|
14
|
-
* It is intentionally agnostic to the consumer's auth/session plumbing —
|
|
15
|
-
* pass in `userEmail` explicitly.
|
|
16
|
-
*/
|
|
17
2
|
import { nanoid } from "nanoid";
|
|
18
3
|
|
|
19
4
|
import { getSchedulingContext } from "./context.js";
|
|
@@ -27,10 +12,6 @@ export interface CompleteVideoOAuthResult {
|
|
|
27
12
|
displayName?: string;
|
|
28
13
|
}
|
|
29
14
|
|
|
30
|
-
/**
|
|
31
|
-
* Complete a video-provider OAuth callback. Throws on any failure so the
|
|
32
|
-
* caller can decide how to render the error (HTML page, JSON, redirect).
|
|
33
|
-
*/
|
|
34
15
|
export async function completeVideoOAuth(opts: {
|
|
35
16
|
kind: string;
|
|
36
17
|
userEmail: string;
|
|
@@ -50,8 +31,6 @@ export async function completeVideoOAuth(opts: {
|
|
|
50
31
|
const now = new Date().toISOString();
|
|
51
32
|
const credentialId = nanoid();
|
|
52
33
|
|
|
53
|
-
// Insert row up-front so `updateTokens(credentialId, ...)` inside
|
|
54
|
-
// completeOAuth has a stable key to write against.
|
|
55
34
|
await getDb().insert(schema.schedulingCredentials).values({
|
|
56
35
|
id: credentialId,
|
|
57
36
|
type: kind,
|
|
@@ -73,14 +52,12 @@ export async function completeVideoOAuth(opts: {
|
|
|
73
52
|
redirectUri,
|
|
74
53
|
});
|
|
75
54
|
} catch (err) {
|
|
76
|
-
// Roll back the credentials row on failure.
|
|
77
55
|
await getDb()
|
|
78
56
|
.delete(schema.schedulingCredentials)
|
|
79
57
|
.where(eq(schema.schedulingCredentials.id, credentialId));
|
|
80
58
|
throw err;
|
|
81
59
|
}
|
|
82
60
|
|
|
83
|
-
// Update the credential row with external identity metadata.
|
|
84
61
|
await getDb()
|
|
85
62
|
.update(schema.schedulingCredentials)
|
|
86
63
|
.set({
|
package/src/shared/index.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wire-level types shared between server, actions, and React client.
|
|
3
|
-
* These are the primary stable contract of the package.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
export type SchedulingType =
|
|
7
2
|
| "personal"
|
|
8
3
|
| "collective"
|
|
@@ -30,28 +25,19 @@ export type LocationKind =
|
|
|
30
25
|
|
|
31
26
|
export interface Location {
|
|
32
27
|
kind: LocationKind;
|
|
33
|
-
/** Provider credential id, if applicable */
|
|
34
28
|
credentialId?: string;
|
|
35
|
-
/** Meeting link override */
|
|
36
29
|
link?: string;
|
|
37
|
-
/** Street address for in-person */
|
|
38
30
|
address?: string;
|
|
39
|
-
/** Phone number for phone/organizer-phone */
|
|
40
31
|
phone?: string;
|
|
41
|
-
/** Display name shown in booking UI */
|
|
42
32
|
label?: string;
|
|
43
33
|
}
|
|
44
34
|
|
|
45
35
|
export type PeriodType = "unlimited" | "rolling" | "range";
|
|
46
36
|
|
|
47
37
|
export interface BookingLimits {
|
|
48
|
-
/** Max bookings in one day */
|
|
49
38
|
perDay?: number;
|
|
50
|
-
/** Max bookings in one week (starting on user's configured start of week) */
|
|
51
39
|
perWeek?: number;
|
|
52
|
-
/** Max bookings in one month */
|
|
53
40
|
perMonth?: number;
|
|
54
|
-
/** Max bookings in one year */
|
|
55
41
|
perYear?: number;
|
|
56
42
|
}
|
|
57
43
|
|
|
@@ -71,18 +57,13 @@ export interface CustomField {
|
|
|
71
57
|
placeholder?: string;
|
|
72
58
|
required: boolean;
|
|
73
59
|
options?: string[];
|
|
74
|
-
/** Default/preset value for this field */
|
|
75
60
|
defaultValue?: string | number | boolean;
|
|
76
|
-
/** Internal identifier stored on booking responses */
|
|
77
61
|
name: string;
|
|
78
62
|
}
|
|
79
63
|
|
|
80
64
|
export interface RecurringEventRule {
|
|
81
|
-
/** iCal RRULE format, e.g. "FREQ=WEEKLY;COUNT=4" */
|
|
82
65
|
rrule: string;
|
|
83
|
-
/** Max number of occurrences */
|
|
84
66
|
count?: number;
|
|
85
|
-
/** How occurrences are labeled on the booker ("Weekly for 4 weeks") */
|
|
86
67
|
description?: string;
|
|
87
68
|
}
|
|
88
69
|
|
|
@@ -92,15 +73,12 @@ export interface EventType {
|
|
|
92
73
|
slug: string;
|
|
93
74
|
description?: string;
|
|
94
75
|
length: number;
|
|
95
|
-
/** Optional additional duration choices */
|
|
96
76
|
durations?: number[];
|
|
97
77
|
hidden: boolean;
|
|
98
78
|
position: number;
|
|
99
79
|
schedulingType: SchedulingType;
|
|
100
|
-
/** If personal, the owner; if team, null (team event types) */
|
|
101
80
|
ownerEmail?: string;
|
|
102
81
|
teamId?: string;
|
|
103
|
-
/** Default schedule ID if not set at event level */
|
|
104
82
|
scheduleId?: string;
|
|
105
83
|
locations: Location[];
|
|
106
84
|
customFields: CustomField[];
|
|
@@ -128,35 +106,25 @@ export interface EventType {
|
|
|
128
106
|
}
|
|
129
107
|
|
|
130
108
|
export interface Slot {
|
|
131
|
-
/** ISO 8601 start time in UTC */
|
|
132
109
|
start: string;
|
|
133
|
-
/** ISO 8601 end time in UTC */
|
|
134
110
|
end: string;
|
|
135
|
-
/** True if this slot can still be booked (not full for seated events) */
|
|
136
111
|
available: boolean;
|
|
137
|
-
/** Seats remaining, for seated events */
|
|
138
112
|
seatsRemaining?: number;
|
|
139
|
-
/** Assigned host for round-robin events (email) */
|
|
140
113
|
hostEmail?: string;
|
|
141
114
|
}
|
|
142
115
|
|
|
143
116
|
export interface AvailabilityInterval {
|
|
144
|
-
/** "HH:MM" in schedule's timezone */
|
|
145
117
|
startTime: string;
|
|
146
|
-
/** "HH:MM" in schedule's timezone */
|
|
147
118
|
endTime: string;
|
|
148
119
|
}
|
|
149
120
|
|
|
150
121
|
export interface WeeklyAvailability {
|
|
151
|
-
/** 0=Sunday … 6=Saturday, ISO-like */
|
|
152
122
|
day: number;
|
|
153
123
|
intervals: AvailabilityInterval[];
|
|
154
124
|
}
|
|
155
125
|
|
|
156
126
|
export interface DateOverride {
|
|
157
|
-
/** YYYY-MM-DD in schedule's timezone */
|
|
158
127
|
date: string;
|
|
159
|
-
/** Empty array = fully blocked */
|
|
160
128
|
intervals: AvailabilityInterval[];
|
|
161
129
|
}
|
|
162
130
|
|
|
@@ -227,9 +195,7 @@ export interface Host {
|
|
|
227
195
|
}
|
|
228
196
|
|
|
229
197
|
export interface BusyInterval {
|
|
230
|
-
/** ISO 8601 UTC */
|
|
231
198
|
start: string;
|
|
232
|
-
/** ISO 8601 UTC */
|
|
233
199
|
end: string;
|
|
234
200
|
source?: string;
|
|
235
201
|
}
|
|
@@ -279,7 +245,6 @@ export interface WorkflowStep {
|
|
|
279
245
|
id: string;
|
|
280
246
|
order: number;
|
|
281
247
|
action: WorkflowStepAction;
|
|
282
|
-
/** Minutes from trigger; negative = before (for before-event), positive = after */
|
|
283
248
|
offsetMinutes: number;
|
|
284
249
|
sendTo?: string;
|
|
285
250
|
emailSubject?: string;
|
|
@@ -321,7 +286,6 @@ export interface RoutingFormField {
|
|
|
321
286
|
|
|
322
287
|
export interface RoutingFormRule {
|
|
323
288
|
id: string;
|
|
324
|
-
/** Array of `{fieldId, op, value}` expressions ANDed together */
|
|
325
289
|
conditions: {
|
|
326
290
|
fieldId: string;
|
|
327
291
|
op: "equals" | "not-equals" | "contains" | "starts-with" | "in";
|
|
@@ -341,7 +305,6 @@ export interface RoutingForm {
|
|
|
341
305
|
teamId?: string;
|
|
342
306
|
fields: RoutingFormField[];
|
|
343
307
|
rules: RoutingFormRule[];
|
|
344
|
-
/** Action taken when no rules match */
|
|
345
308
|
fallback:
|
|
346
309
|
| { kind: "event-type"; eventTypeId: string }
|
|
347
310
|
| { kind: "external-url"; url: string }
|
|
@@ -359,7 +322,6 @@ export interface HashedLink {
|
|
|
359
322
|
usedAt?: string;
|
|
360
323
|
}
|
|
361
324
|
|
|
362
|
-
/** Round-robin assignment strategy */
|
|
363
325
|
export type RoundRobinStrategy =
|
|
364
326
|
| "lowest-recent-bookings"
|
|
365
327
|
| "weighted"
|