@agent-native/scheduling 0.2.0 → 0.2.1-nightly-20260926144920

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.
@@ -2,6 +2,7 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
2
2
  uid: string;
3
3
  reason?: string | undefined;
4
4
  cancelledBy?: "attendee" | "host" | undefined;
5
+ zoomMeetingResolved?: boolean | undefined;
5
6
  token?: string | undefined;
6
7
  }, {
7
8
  booking: import("../index.js").Booking;
@@ -1,19 +1,37 @@
1
- import { defineAction } from "@agent-native/core/action";
1
+ import { defineAction, fail } from "@agent-native/core/action";
2
2
  import { z } from "zod";
3
- import { cancelBooking } from "../server/booking-service.js";
3
+ import { BookingLifecycleError, cancelBooking, } from "../server/booking-service.js";
4
4
  import { getBookingByUid } from "../server/bookings-repo.js";
5
5
  import { currentUserEmailOrNull } from "./_helpers.js";
6
6
  export default defineAction({
7
- description: "Cancel a booking",
7
+ description: "Cancel a booking and its linked video meetings. If a Zoom booking has no recorded meeting, the host must review and resolve it first.",
8
8
  schema: z.object({
9
- uid: z.string(),
10
- reason: z.string().optional(),
11
- cancelledBy: z.enum(["attendee", "host"]).optional(),
12
- token: z.string().optional(),
13
- }),
14
- run: async (args) => ({
15
- booking: await cancelBookingAfterAccessCheck(args),
9
+ uid: z.string().describe("Booking uid"),
10
+ reason: z.string().optional().describe("Reason for canceling the booking"),
11
+ cancelledBy: z
12
+ .enum(["attendee", "host"])
13
+ .optional()
14
+ .describe('Who canceled the booking: "attendee" or "host"'),
15
+ zoomMeetingResolved: z
16
+ .boolean()
17
+ .optional()
18
+ .describe("Host confirms the Zoom meeting was checked and resolved"),
19
+ token: z.string().optional().describe("Booking cancellation token"),
16
20
  }),
21
+ run: async (args) => {
22
+ try {
23
+ return { booking: await cancelBookingAfterAccessCheck(args) };
24
+ }
25
+ catch (error) {
26
+ if (error instanceof BookingLifecycleError) {
27
+ fail(error.message, {
28
+ statusCode: error.statusCode,
29
+ errorCode: error.errorCode,
30
+ });
31
+ }
32
+ throw error;
33
+ }
34
+ },
17
35
  });
18
36
  async function cancelBookingAfterAccessCheck(args) {
19
37
  const booking = await getBookingByUid(args.uid);
@@ -29,6 +47,7 @@ async function cancelBookingAfterAccessCheck(args) {
29
47
  uid: args.uid,
30
48
  reason: args.reason,
31
49
  cancelledBy: args.cancelledBy,
50
+ zoomMeetingResolved: isHost && args.zoomMeetingResolved,
32
51
  });
33
52
  }
34
53
  //# sourceMappingURL=cancel-booking.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cancel-booking.js","sourceRoot":"","sources":["../../src/actions/cancel-booking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,eAAe,YAAY,CAAC;IAC1B,WAAW,EAAE,kBAAkB;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;QACf,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;QACpD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC7B,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACpB,OAAO,EAAE,MAAM,6BAA6B,CAAC,IAAI,CAAC;KACnD,CAAC;CACH,CAAC,CAAC;AAEH,KAAK,UAAU,6BAA6B,CAAC,IAK5C;IACC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,sBAAsB,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC;IAC9D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,WAAW,CAAC;IACpE,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,aAAa,CAAC;QACnB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"cancel-booking.js","sourceRoot":"","sources":["../../src/actions/cancel-booking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,qBAAqB,EACrB,aAAa,GACd,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,uIAAuI;IACzI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QAC1E,WAAW,EAAE,CAAC;aACX,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;aAC1B,QAAQ,EAAE;aACV,QAAQ,CAAC,gDAAgD,CAAC;QAC7D,mBAAmB,EAAE,CAAC;aACnB,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;QACtE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;KACpE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC,IAAI,CAAC,EAAE,CAAC;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;oBAClB,UAAU,EAAE,KAAK,CAAC,UAAU;oBAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;iBAC3B,CAAC,CAAC;YACL,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,KAAK,UAAU,6BAA6B,CAAC,IAM5C;IACC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,sBAAsB,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC;IAC9D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,WAAW,CAAC;IACpE,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,aAAa,CAAC;QACnB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,mBAAmB,EAAE,MAAM,IAAI,IAAI,CAAC,mBAAmB;KACxD,CAAC,CAAC;AACL,CAAC"}
@@ -4,6 +4,7 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
4
4
  newEndTime: string;
5
5
  reason?: string | undefined;
6
6
  rescheduledBy?: "attendee" | "host" | undefined;
7
+ zoomMeetingResolved?: boolean | undefined;
7
8
  token?: string | undefined;
8
9
  }, {
9
10
  booking: import("../index.js").Booking;
@@ -1,21 +1,39 @@
1
- import { defineAction } from "@agent-native/core/action";
1
+ import { defineAction, fail } from "@agent-native/core/action";
2
2
  import { z } from "zod";
3
- import { rescheduleBooking } from "../server/booking-service.js";
3
+ import { BookingLifecycleError, rescheduleBooking, } from "../server/booking-service.js";
4
4
  import { getBookingByUid } from "../server/bookings-repo.js";
5
5
  import { currentUserEmailOrNull } from "./_helpers.js";
6
6
  export default defineAction({
7
- description: "Reschedule a booking to a new start/end time",
7
+ description: "Reschedule a booking, deleting its existing video meeting after the replacement is ready. If a Zoom booking has no recorded meeting, the host must review and resolve it first.",
8
8
  schema: z.object({
9
- uid: z.string(),
10
- newStartTime: z.string(),
11
- newEndTime: z.string(),
12
- reason: z.string().optional(),
13
- rescheduledBy: z.enum(["attendee", "host"]).optional(),
14
- token: z.string().optional(),
15
- }),
16
- run: async (args) => ({
17
- booking: await rescheduleBookingAfterAccessCheck(args),
9
+ uid: z.string().describe("Booking uid"),
10
+ newStartTime: z.string().describe("New start time in ISO 8601 format"),
11
+ newEndTime: z.string().describe("New end time in ISO 8601 format"),
12
+ reason: z.string().optional().describe("Reason for rescheduling"),
13
+ rescheduledBy: z
14
+ .enum(["attendee", "host"])
15
+ .optional()
16
+ .describe('Who requested the reschedule: "attendee" or "host"'),
17
+ zoomMeetingResolved: z
18
+ .boolean()
19
+ .optional()
20
+ .describe("Host confirms the Zoom meeting was checked and resolved"),
21
+ token: z.string().optional().describe("Booking reschedule token"),
18
22
  }),
23
+ run: async (args) => {
24
+ try {
25
+ return { booking: await rescheduleBookingAfterAccessCheck(args) };
26
+ }
27
+ catch (error) {
28
+ if (error instanceof BookingLifecycleError) {
29
+ fail(error.message, {
30
+ statusCode: error.statusCode,
31
+ errorCode: error.errorCode,
32
+ });
33
+ }
34
+ throw error;
35
+ }
36
+ },
19
37
  });
20
38
  async function rescheduleBookingAfterAccessCheck(args) {
21
39
  const booking = await getBookingByUid(args.uid);
@@ -33,6 +51,7 @@ async function rescheduleBookingAfterAccessCheck(args) {
33
51
  newEndTime: args.newEndTime,
34
52
  reason: args.reason,
35
53
  rescheduledBy: args.rescheduledBy,
54
+ zoomMeetingResolved: isHost && args.zoomMeetingResolved,
36
55
  });
37
56
  }
38
57
  //# sourceMappingURL=reschedule-booking.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reschedule-booking.js","sourceRoot":"","sources":["../../src/actions/reschedule-booking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,eAAe,YAAY,CAAC;IAC1B,WAAW,EAAE,8CAA8C;IAC3D,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;QACf,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;QACxB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;QACtD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC7B,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACpB,OAAO,EAAE,MAAM,iCAAiC,CAAC,IAAI,CAAC;KACvD,CAAC;CACH,CAAC,CAAC;AAEH,KAAK,UAAU,iCAAiC,CAAC,IAOhD;IACC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,sBAAsB,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC;IAC9D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,eAAe,CAAC;IACxE,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,iBAAiB,CAAC;QACvB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"reschedule-booking.js","sourceRoot":"","sources":["../../src/actions/reschedule-booking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,iLAAiL;IACnL,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACvC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QACtE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QAClE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QACjE,aAAa,EAAE,CAAC;aACb,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;aAC1B,QAAQ,EAAE;aACV,QAAQ,CAAC,oDAAoD,CAAC;QACjE,mBAAmB,EAAE,CAAC;aACnB,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;QACtE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KAClE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC,IAAI,CAAC,EAAE,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;oBAClB,UAAU,EAAE,KAAK,CAAC,UAAU;oBAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;iBAC3B,CAAC,CAAC;YACL,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,KAAK,UAAU,iCAAiC,CAAC,IAQhD;IACC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,sBAAsB,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC;IAC9D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,eAAe,CAAC;IACxE,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,iBAAiB,CAAC;QACvB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,mBAAmB,EAAE,MAAM,IAAI,IAAI,CAAC,mBAAmB;KACxD,CAAC,CAAC;AACL,CAAC"}
@@ -28,6 +28,13 @@ export interface CreateBookingInput {
28
28
  orgId?: string;
29
29
  /** If set, we're rescheduling from this booking uid */
30
30
  fromReschedule?: string;
31
+ /** Keep Zoom reschedules uncommitted until the replacement meeting is usable. */
32
+ requireZoomMeeting?: boolean;
33
+ }
34
+ export declare class BookingLifecycleError extends Error {
35
+ readonly statusCode: 409 | 502;
36
+ readonly errorCode: "zoom_meeting_review_required" | "video_meeting_cleanup_failed" | "video_meeting_creation_failed";
37
+ constructor(message: string, statusCode: 409 | 502, errorCode: "zoom_meeting_review_required" | "video_meeting_cleanup_failed" | "video_meeting_creation_failed");
31
38
  }
32
39
  export declare function createBooking(input: CreateBookingInput): Promise<Booking>;
33
40
  export declare function rescheduleBooking(input: {
@@ -36,11 +43,13 @@ export declare function rescheduleBooking(input: {
36
43
  newEndTime: string;
37
44
  reason?: string;
38
45
  rescheduledBy?: "attendee" | "host";
46
+ zoomMeetingResolved?: boolean;
39
47
  }): Promise<Booking>;
40
48
  export declare function cancelBooking(input: {
41
49
  uid: string;
42
50
  reason?: string;
43
51
  cancelledBy?: "attendee" | "host";
52
+ zoomMeetingResolved?: boolean;
44
53
  }): Promise<Booking>;
45
54
  export declare function markNoShow(uid: string, attendeeEmail: string): Promise<void>;
46
55
  //# sourceMappingURL=booking-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"booking-service.d.ts","sourceRoot":"","sources":["../../src/server/booking-service.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,SAAS,EACV,MAAM,oBAAoB,CAAC;AAkB5B,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,OAAO,CAAC,CAqElB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CACrC,GAAG,OAAO,CAAC,OAAO,CAAC,CAmDnB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CACnC,GAAG,OAAO,CAAC,OAAO,CAAC,CA8BnB;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"booking-service.d.ts","sourceRoot":"","sources":["../../src/server/booking-service.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,SAAS,EACV,MAAM,oBAAoB,CAAC;AAkB5B,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,UAAU,EAAE,GAAG,GAAG,GAAG;IAC9B,QAAQ,CAAC,SAAS,EACd,8BAA8B,GAC9B,8BAA8B,GAC9B,+BAA+B;IANrC,YACE,OAAO,EAAE,MAAM,EACN,UAAU,EAAE,GAAG,GAAG,GAAG,EACrB,SAAS,EACd,8BAA8B,GAC9B,8BAA8B,GAC9B,+BAA+B,EAGpC;CACF;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,OAAO,CAAC,CAwFlB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,GAAG,OAAO,CAAC,OAAO,CAAC,CAwEnB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAClC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBnB;AAsDD,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -5,6 +5,15 @@ import { getSchedulingContext } from "./context.js";
5
5
  import { getEventTypeById } from "./event-types-repo.js";
6
6
  import { onBookingCreated, onBookingCancelled, onBookingRescheduled, } from "./hooks.js";
7
7
  import { getCalendarProvider, getVideoProvider } from "./providers/registry.js";
8
+ export class BookingLifecycleError extends Error {
9
+ statusCode;
10
+ errorCode;
11
+ constructor(message, statusCode, errorCode) {
12
+ super(message);
13
+ this.statusCode = statusCode;
14
+ this.errorCode = errorCode;
15
+ }
16
+ }
8
17
  export async function createBooking(input) {
9
18
  const eventType = input.eventType;
10
19
  const title = input.title ??
@@ -37,6 +46,7 @@ export async function createBooking(input) {
37
46
  ownerEmail: input.hostEmail,
38
47
  orgId: input.orgId,
39
48
  });
49
+ let usableZoomMeeting = false;
40
50
  // Create video meeting if location is a video kind
41
51
  if (booking.location && isVideoKind(booking.location.kind)) {
42
52
  const provider = getVideoProvider(videoProviderKindFor(booking.location.kind));
@@ -46,7 +56,7 @@ export async function createBooking(input) {
46
56
  credentialId: booking.location.credentialId,
47
57
  booking,
48
58
  });
49
- if (meeting.meetingUrl) {
59
+ if (meeting.meetingId && booking.location.credentialId) {
50
60
  await addBookingReference(booking.id, {
51
61
  type: provider.kind,
52
62
  externalId: meeting.meetingId,
@@ -54,13 +64,21 @@ export async function createBooking(input) {
54
64
  meetingPassword: meeting.meetingPassword,
55
65
  credentialId: booking.location.credentialId,
56
66
  });
67
+ usableZoomMeeting =
68
+ provider.kind === "zoom_video" && Boolean(meeting.meetingUrl);
57
69
  }
58
70
  }
59
71
  catch {
72
+ if (input.requireZoomMeeting) {
73
+ throw new BookingLifecycleError("Replacement Zoom meeting could not be confirmed. The original booking remains active, and the replacement reservation needs host review.", 502, "video_meeting_creation_failed");
74
+ }
60
75
  // Continue without the video link; the host can fix on the booking detail page
61
76
  }
62
77
  }
63
78
  }
79
+ if (input.requireZoomMeeting && !usableZoomMeeting) {
80
+ throw new BookingLifecycleError("Replacement Zoom meeting could not be confirmed. The original booking remains active, and the replacement reservation needs host review.", 502, "video_meeting_creation_failed");
81
+ }
64
82
  // Write to destination calendar
65
83
  await writeToDestinationCalendars(booking);
66
84
  // Fire workflow hooks
@@ -77,6 +95,7 @@ export async function rescheduleBooking(input) {
77
95
  const eventType = await getEventTypeById(original.eventTypeId);
78
96
  if (!eventType)
79
97
  throw new Error("Event type missing");
98
+ requireZoomMeetingResolution(original, input.zoomMeetingResolved);
80
99
  // Create the new booking (validated against availability, ignoring the
81
100
  // original's own slot) before touching the original, so a slot conflict
82
101
  // never leaves the original marked "rescheduled" with no successor.
@@ -97,7 +116,23 @@ export async function rescheduleBooking(input) {
97
116
  iCalUid: original.iCalUid,
98
117
  iCalSequence: original.iCalSequence + 1,
99
118
  fromReschedule: input.uid,
119
+ requireZoomMeeting: original.location?.kind === "zoom",
100
120
  });
121
+ try {
122
+ await deleteVideoMeetings(original);
123
+ }
124
+ catch (error) {
125
+ try {
126
+ await cancelBooking({ uid: newBooking.uid });
127
+ }
128
+ catch (rollbackError) {
129
+ const cleanupMessage = rollbackError instanceof Error
130
+ ? rollbackError.message
131
+ : "unknown error";
132
+ throw new BookingLifecycleError(`The existing meeting could not be canceled, and the replacement booking could not be fully rolled back: ${cleanupMessage}`, 502, "video_meeting_cleanup_failed");
133
+ }
134
+ throw error;
135
+ }
101
136
  // Mark old as rescheduled now that the replacement exists.
102
137
  await updateBookingStatus(input.uid, "rescheduled", {
103
138
  reschedulingReason: input.reason,
@@ -125,6 +160,8 @@ export async function cancelBooking(input) {
125
160
  const booking = await getBookingByUid(input.uid);
126
161
  if (!booking)
127
162
  throw new Error(`Booking ${input.uid} not found`);
163
+ requireZoomMeetingResolution(booking, input.zoomMeetingResolved);
164
+ await deleteVideoMeetings(booking);
128
165
  await updateBookingStatus(input.uid, "cancelled", {
129
166
  cancellationReason: input.reason,
130
167
  });
@@ -139,20 +176,40 @@ export async function cancelBooking(input) {
139
176
  }
140
177
  catch { }
141
178
  }
142
- const videoProvider = getVideoProvider(ref.type);
143
- if (videoProvider?.deleteMeeting) {
144
- try {
145
- await videoProvider.deleteMeeting({
146
- credentialId: ref.credentialId,
147
- meetingId: ref.externalId,
148
- });
149
- }
150
- catch { }
151
- }
152
179
  }
153
180
  await onBookingCancelled(booking);
154
181
  return (await getBookingByUid(input.uid));
155
182
  }
183
+ function requireZoomMeetingResolution(booking, zoomMeetingResolved) {
184
+ if (booking.location?.kind === "zoom" &&
185
+ !booking.references.some((ref) => ref.type === "zoom_video") &&
186
+ zoomMeetingResolved !== true) {
187
+ throw new BookingLifecycleError("Zoom meeting needs host review; cancel it in Zoom, then confirm it was resolved", 409, "zoom_meeting_review_required");
188
+ }
189
+ }
190
+ async function deleteVideoMeetings(booking) {
191
+ for (const ref of booking.references) {
192
+ const provider = getVideoProvider(ref.type);
193
+ if (!provider) {
194
+ if (ref.type.endsWith("_video") || ref.type === "google_meet") {
195
+ throw new BookingLifecycleError(`${ref.type} provider is unavailable to cancel this meeting`, 502, "video_meeting_cleanup_failed");
196
+ }
197
+ continue;
198
+ }
199
+ if (!provider.deleteMeeting) {
200
+ throw new BookingLifecycleError(`${provider.label} does not support meeting cancellation`, 502, "video_meeting_cleanup_failed");
201
+ }
202
+ try {
203
+ await provider.deleteMeeting({
204
+ credentialId: ref.credentialId,
205
+ meetingId: ref.externalId,
206
+ });
207
+ }
208
+ catch (error) {
209
+ throw new BookingLifecycleError(`${provider.label} meeting could not be canceled${error instanceof Error ? `: ${error.message}` : ""}`, 502, "video_meeting_cleanup_failed");
210
+ }
211
+ }
212
+ }
156
213
  export async function markNoShow(uid, attendeeEmail) {
157
214
  const booking = await getBookingByUid(uid);
158
215
  if (!booking)
@@ -1 +1 @@
1
- {"version":3,"file":"booking-service.js","sourceRoot":"","sources":["../../src/server/booking-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"booking-service.js","sourceRoot":"","sources":["../../src/server/booking-service.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../../../src/server/providers/teams.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,YAAY,CAAC,EAAE,CACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,KACE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAKD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,mBAAmB,GAC1B,aAAa,CAuJf"}
1
+ {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["../../../src/server/providers/teams.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,YAAY,CAAC,EAAE,CACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,KACE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAKD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,mBAAmB,GAC1B,aAAa,CAyJf"}
@@ -97,8 +97,9 @@ export function createTeamsProvider(config) {
97
97
  return { meetingId: meeting.id, meetingUrl: meeting.joinWebUrl };
98
98
  },
99
99
  async deleteMeeting({ credentialId, meetingId }) {
100
- if (!credentialId)
101
- return;
100
+ if (!credentialId) {
101
+ throw new Error("Microsoft Teams requires credentialId");
102
+ }
102
103
  const response = await graphRequest(credentialId, `/me/onlineMeetings/${encodeURIComponent(meetingId)}`, { method: "DELETE" });
103
104
  if (response.status === 204 || response.status === 404)
104
105
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"teams.js","sourceRoot":"","sources":["../../../src/server/providers/teams.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"teams.js","sourceRoot":"","sources":["../../../src/server/providers/teams.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,GAAG,CAAC,gBAAgB,EAAE,0BAA0B,EAAE,WAAW,CAAC,CAAC;AAC3E,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAE1D,MAAM,UAAU,mBAAmB,CACjC,MAA2B;IAE3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,eAAe,CAAC;IAChD,MAAM,YAAY,GAAG,qCAAqC,kBAAkB,CAAC,MAAM,CAAC,cAAc,CAAC;IAEnG,KAAK,UAAU,YAAY,CACzB,YAAoB,EACpB,IAAY,EACZ,IAAkB;QAElB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,cAAc,GAAG,IAAI,EAAE,EAAE;YACvD,GAAG,IAAI;YACP,OAAO;SACR,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvD,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC,YAAY,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,iBAAiB;QAExB,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE;YACrC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;gBACjC,SAAS,EAAE,MAAM,CAAC,QAAQ;gBAC1B,YAAY,EAAE,WAAW;gBACzB,aAAa,EAAE,MAAM;gBACrB,aAAa,EAAE,OAAO;gBACtB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;gBACvB,MAAM,EAAE,SAAS;gBACjB,KAAK;aACN,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,cAAc,MAAM,EAAE,EAAE,CAAC;QAC5D,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE;YAChE,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC;gBACtC,SAAS,EAAE,MAAM,CAAC,QAAQ;gBAC1B,aAAa,EAAE,MAAM,CAAC,YAAY;gBAClC,IAAI;gBACJ,YAAY,EAAE,WAAW;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;aACxB,CAAC,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,QAAQ,EAAE;gBACzD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;gBAChE,IAAI,EAAE,WAAW;aAClB,CAAC,CAAC;YACH,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CACb,0CAA0C,aAAa,CAAC,MAAM,GAAG,CAClE,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAKzC,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACb,yDAAyD,CAC1D,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC,YAAY,EAAE;gBACxC,WAAW,EAAE,MAAM,CAAC,YAAY;gBAChC,YAAY,EAAE,MAAM,CAAC,aAAa;gBAClC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;gBACpE,WAAW,EAAE,MAAM;aACpB,CAAC,CAAC;YAEH,wEAAwE;YACxE,0EAA0E;YAC1E,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAClC,GAAG,cAAc,mDAAmD,EACpE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE,EAAE,EAAE,CAChE,CAAC;YACF,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACb,2CAA2C,gBAAgB,CAAC,MAAM,GAAG,CACtE,CAAC;YACJ,CAAC;YACD,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,CAK9C,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,wDAAwD,CACzD,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,iBAAiB,EAAE,QAAQ,CAAC,EAAE;gBAC9B,aAAa,EAAE,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,iBAAiB,IAAI,SAAS;gBACvE,WAAW,EAAE,QAAQ,CAAC,WAAW;aAClC,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE;YAC3C,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,YAAY,EAAE,oBAAoB,EAAE;gBACtE,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,OAAO,EAAE,OAAO,CAAC,KAAK;oBACtB,aAAa,EAAE,OAAO,CAAC,SAAS;oBAChC,WAAW,EAAE,OAAO,CAAC,OAAO;iBAC7B,CAAC;aACH,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,4CAA4C,QAAQ,CAAC,MAAM,GAAG,CAC/D,CAAC;YACJ,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGrC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvC,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;QACnE,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE;YAC7C,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,YAAY,CACjC,YAAY,EACZ,sBAAsB,kBAAkB,CAAC,SAAS,CAAC,EAAE,EACrD,EAAE,MAAM,EAAE,QAAQ,EAAE,CACrB,CAAC;YACF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO;YAC/D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,4CAA4C,QAAQ,CAAC,MAAM,GAAG,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../../src/server/providers/zoom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,UAAU,EAAE,MAAM;IAD7B,YACW,UAAU,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EAIrB;CACF;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D;;;;OAIG;IACH,YAAY,CAAC,EAAE,CACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,KACE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAKD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,aAAa,CAsI5E"}
1
+ {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../../src/server/providers/zoom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,UAAU,EAAE,MAAM;IAD7B,YACW,UAAU,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EAIrB;CACF;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D;;;;OAIG;IACH,YAAY,CAAC,EAAE,CACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,KACE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAKD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,aAAa,CAyI5E"}
@@ -108,12 +108,15 @@ export function createZoomProvider(config) {
108
108
  },
109
109
  async deleteMeeting({ credentialId, meetingId }) {
110
110
  if (!credentialId)
111
- return;
111
+ throw new Error("Zoom requires credentialId");
112
112
  const token = await config.getAccessToken(credentialId);
113
- await fetch(`https://api.zoom.us/v2/meetings/${encodeURIComponent(meetingId)}`, {
113
+ const res = await fetch(`https://api.zoom.us/v2/meetings/${encodeURIComponent(meetingId)}`, {
114
114
  method: "DELETE",
115
115
  headers: { authorization: `Bearer ${token}` },
116
116
  });
117
+ if (!res.ok && res.status !== 404) {
118
+ throw new Error(`Zoom meeting deletion failed: ${res.status}`);
119
+ }
117
120
  },
118
121
  };
119
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"zoom.js","sourceRoot":"","sources":["../../../src/server/providers/zoom.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zoom.js","sourceRoot":"","sources":["../../../src/server/providers/zoom.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/scheduling",
3
- "version": "0.2.0",
3
+ "version": "0.2.1-nightly-20260926144920",
4
4
  "description": "Scheduling primitives for agent-native apps — event types, availability, bookings, team scheduling, workflows, and routing forms.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -66,10 +66,10 @@
66
66
  "react": "^19.2.5",
67
67
  "typescript-7": "npm:typescript@^7.0.2",
68
68
  "vitest": "^4.1.5",
69
- "@agent-native/core": "0.192.0"
69
+ "@agent-native/core": "0.192.1-nightly-20260926144920"
70
70
  },
71
71
  "peerDependencies": {
72
- "@agent-native/core": ">=0.8.0",
72
+ "@agent-native/core": "0.192.1-nightly-20260926144920",
73
73
  "@tabler/icons-react": "^3.41.1",
74
74
  "drizzle-orm": ">=0.45",
75
75
  "react": ">=18",
@@ -15,6 +15,7 @@ import * as schema from "../schema/index.js";
15
15
  import { setSchedulingContext } from "../server/context.js";
16
16
  import addBookingAttendee from "./add-booking-attendee.js";
17
17
  import addBookingNote from "./add-booking-note.js";
18
+ import cancelBooking from "./cancel-booking.js";
18
19
  import confirmBooking from "./confirm-booking.js";
19
20
  import markNoShow from "./mark-no-show.js";
20
21
  import removeBookingAttendee from "./remove-booking-attendee.js";
@@ -183,6 +184,33 @@ async function noteCount(): Promise<number> {
183
184
  return rows.length;
184
185
  }
185
186
 
187
+ async function setZoomLocation(): Promise<void> {
188
+ await execute({
189
+ sql: "UPDATE bookings SET location = ? WHERE uid = ?",
190
+ args: [JSON.stringify({ kind: "zoom" }), BOOKING_UID],
191
+ });
192
+ }
193
+
194
+ describe("cancel-booking Zoom review authorization", () => {
195
+ it("does not let a public cancellation token assert that Zoom was resolved", async () => {
196
+ currentUserEmail = undefined;
197
+ await setZoomLocation();
198
+
199
+ await expect(
200
+ cancelBooking.run({
201
+ uid: BOOKING_UID,
202
+ token: "cancel-token-1",
203
+ zoomMeetingResolved: true,
204
+ }),
205
+ ).rejects.toMatchObject({
206
+ message: expect.stringMatching(/Zoom meeting needs host review/i),
207
+ statusCode: 409,
208
+ errorCode: "zoom_meeting_review_required",
209
+ });
210
+ expect(await bookingStatus()).toBe("pending");
211
+ });
212
+ });
213
+
186
214
  describe("confirm-booking authorization", () => {
187
215
  it("rejects a non-host caller and leaves the booking unchanged", async () => {
188
216
  currentUserEmail = OUTSIDER_EMAIL;
@@ -1,27 +1,49 @@
1
- import { defineAction } from "@agent-native/core/action";
1
+ import { defineAction, fail } from "@agent-native/core/action";
2
2
  import { z } from "zod";
3
3
 
4
- import { cancelBooking } from "../server/booking-service.js";
4
+ import {
5
+ BookingLifecycleError,
6
+ cancelBooking,
7
+ } from "../server/booking-service.js";
5
8
  import { getBookingByUid } from "../server/bookings-repo.js";
6
9
  import { currentUserEmailOrNull } from "./_helpers.js";
7
10
 
8
11
  export default defineAction({
9
- description: "Cancel a booking",
12
+ description:
13
+ "Cancel a booking and its linked video meetings. If a Zoom booking has no recorded meeting, the host must review and resolve it first.",
10
14
  schema: z.object({
11
- uid: z.string(),
12
- reason: z.string().optional(),
13
- cancelledBy: z.enum(["attendee", "host"]).optional(),
14
- token: z.string().optional(),
15
- }),
16
- run: async (args) => ({
17
- booking: await cancelBookingAfterAccessCheck(args),
15
+ uid: z.string().describe("Booking uid"),
16
+ reason: z.string().optional().describe("Reason for canceling the booking"),
17
+ cancelledBy: z
18
+ .enum(["attendee", "host"])
19
+ .optional()
20
+ .describe('Who canceled the booking: "attendee" or "host"'),
21
+ zoomMeetingResolved: z
22
+ .boolean()
23
+ .optional()
24
+ .describe("Host confirms the Zoom meeting was checked and resolved"),
25
+ token: z.string().optional().describe("Booking cancellation token"),
18
26
  }),
27
+ run: async (args) => {
28
+ try {
29
+ return { booking: await cancelBookingAfterAccessCheck(args) };
30
+ } catch (error) {
31
+ if (error instanceof BookingLifecycleError) {
32
+ fail(error.message, {
33
+ statusCode: error.statusCode,
34
+ errorCode: error.errorCode,
35
+ });
36
+ }
37
+ throw error;
38
+ }
39
+ },
19
40
  });
20
41
 
21
42
  async function cancelBookingAfterAccessCheck(args: {
22
43
  uid: string;
23
44
  reason?: string;
24
45
  cancelledBy?: "attendee" | "host";
46
+ zoomMeetingResolved?: boolean;
25
47
  token?: string;
26
48
  }) {
27
49
  const booking = await getBookingByUid(args.uid);
@@ -36,5 +58,6 @@ async function cancelBookingAfterAccessCheck(args: {
36
58
  uid: args.uid,
37
59
  reason: args.reason,
38
60
  cancelledBy: args.cancelledBy,
61
+ zoomMeetingResolved: isHost && args.zoomMeetingResolved,
39
62
  });
40
63
  }
@@ -1,23 +1,44 @@
1
- import { defineAction } from "@agent-native/core/action";
1
+ import { defineAction, fail } from "@agent-native/core/action";
2
2
  import { z } from "zod";
3
3
 
4
- import { rescheduleBooking } from "../server/booking-service.js";
4
+ import {
5
+ BookingLifecycleError,
6
+ rescheduleBooking,
7
+ } from "../server/booking-service.js";
5
8
  import { getBookingByUid } from "../server/bookings-repo.js";
6
9
  import { currentUserEmailOrNull } from "./_helpers.js";
7
10
 
8
11
  export default defineAction({
9
- description: "Reschedule a booking to a new start/end time",
12
+ description:
13
+ "Reschedule a booking, deleting its existing video meeting after the replacement is ready. If a Zoom booking has no recorded meeting, the host must review and resolve it first.",
10
14
  schema: z.object({
11
- uid: z.string(),
12
- newStartTime: z.string(),
13
- newEndTime: z.string(),
14
- reason: z.string().optional(),
15
- rescheduledBy: z.enum(["attendee", "host"]).optional(),
16
- token: z.string().optional(),
17
- }),
18
- run: async (args) => ({
19
- booking: await rescheduleBookingAfterAccessCheck(args),
15
+ uid: z.string().describe("Booking uid"),
16
+ newStartTime: z.string().describe("New start time in ISO 8601 format"),
17
+ newEndTime: z.string().describe("New end time in ISO 8601 format"),
18
+ reason: z.string().optional().describe("Reason for rescheduling"),
19
+ rescheduledBy: z
20
+ .enum(["attendee", "host"])
21
+ .optional()
22
+ .describe('Who requested the reschedule: "attendee" or "host"'),
23
+ zoomMeetingResolved: z
24
+ .boolean()
25
+ .optional()
26
+ .describe("Host confirms the Zoom meeting was checked and resolved"),
27
+ token: z.string().optional().describe("Booking reschedule token"),
20
28
  }),
29
+ run: async (args) => {
30
+ try {
31
+ return { booking: await rescheduleBookingAfterAccessCheck(args) };
32
+ } catch (error) {
33
+ if (error instanceof BookingLifecycleError) {
34
+ fail(error.message, {
35
+ statusCode: error.statusCode,
36
+ errorCode: error.errorCode,
37
+ });
38
+ }
39
+ throw error;
40
+ }
41
+ },
21
42
  });
22
43
 
23
44
  async function rescheduleBookingAfterAccessCheck(args: {
@@ -26,6 +47,7 @@ async function rescheduleBookingAfterAccessCheck(args: {
26
47
  newEndTime: string;
27
48
  reason?: string;
28
49
  rescheduledBy?: "attendee" | "host";
50
+ zoomMeetingResolved?: boolean;
29
51
  token?: string;
30
52
  }) {
31
53
  const booking = await getBookingByUid(args.uid);
@@ -42,5 +64,6 @@ async function rescheduleBookingAfterAccessCheck(args: {
42
64
  newEndTime: args.newEndTime,
43
65
  reason: args.reason,
44
66
  rescheduledBy: args.rescheduledBy,
67
+ zoomMeetingResolved: isHost && args.zoomMeetingResolved,
45
68
  });
46
69
  }
@@ -3,16 +3,23 @@ import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
 
5
5
  import { closeDbExec, createGetDb, getDbExec } from "@agent-native/core/db";
6
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
7
 
8
8
  import * as schema from "../schema/index.js";
9
9
  import type { EventType } from "../shared/index.js";
10
10
  import { SlotConflictError } from "./availability-engine.js";
11
- import { createBooking, rescheduleBooking } from "./booking-service.js";
11
+ import {
12
+ cancelBooking,
13
+ createBooking,
14
+ rescheduleBooking,
15
+ } from "./booking-service.js";
12
16
  import { getBookingByUid, insertBooking } from "./bookings-repo.js";
13
17
  import { setSchedulingContext } from "./context.js";
14
- import { registerCalendarProvider } from "./providers/registry.js";
15
- import type { CalendarProvider } from "./providers/types.js";
18
+ import {
19
+ registerCalendarProvider,
20
+ registerVideoProvider,
21
+ } from "./providers/registry.js";
22
+ import type { CalendarProvider, VideoProvider } from "./providers/types.js";
16
23
 
17
24
  const HOST_EMAIL = "host@example.com";
18
25
  const ATTENDEE_EMAIL = "attendee@example.com";
@@ -33,6 +40,9 @@ async function execute(statement: SqlStatement) {
33
40
  });
34
41
  }
35
42
  const GUEST_EMAIL = "guest@example.com";
43
+ const createZoomMeetingMock = vi.fn<VideoProvider["createMeeting"]>();
44
+ const deleteZoomMeetingMock =
45
+ vi.fn<NonNullable<VideoProvider["deleteMeeting"]>>();
36
46
 
37
47
  let dbDir: string;
38
48
 
@@ -85,6 +95,17 @@ function makeCalendarProvider(
85
95
  }
86
96
 
87
97
  beforeEach(async () => {
98
+ createZoomMeetingMock.mockReset().mockResolvedValue({
99
+ meetingUrl: "https://zoom.us/j/123456789",
100
+ meetingId: "zoom-meeting-1",
101
+ });
102
+ deleteZoomMeetingMock.mockReset().mockResolvedValue();
103
+ registerVideoProvider({
104
+ kind: "zoom_video",
105
+ label: "Test Zoom",
106
+ createMeeting: createZoomMeetingMock,
107
+ deleteMeeting: deleteZoomMeetingMock,
108
+ });
88
109
  dbDir = mkdtempSync(join(tmpdir(), "scheduling-booking-test-"));
89
110
  process.env.DATABASE_URL = `pglite:${dbDir}`;
90
111
  await execute(`
@@ -214,6 +235,21 @@ beforeEach(async () => {
214
235
  visibility TEXT NOT NULL DEFAULT 'private'
215
236
  );
216
237
  `);
238
+ await execute(`
239
+ CREATE TABLE scheduled_reminders (
240
+ id TEXT PRIMARY KEY,
241
+ booking_id TEXT NOT NULL,
242
+ workflow_step_id TEXT NOT NULL,
243
+ method TEXT NOT NULL,
244
+ scheduled_for TEXT NOT NULL,
245
+ sent BOOLEAN NOT NULL DEFAULT false,
246
+ sent_at TEXT,
247
+ failed BOOLEAN NOT NULL DEFAULT false,
248
+ failure_reason TEXT,
249
+ attempts INTEGER NOT NULL DEFAULT 0,
250
+ created_at TEXT NOT NULL
251
+ );
252
+ `);
217
253
  await execute(`
218
254
  CREATE TABLE event_types (
219
255
  id TEXT PRIMARY KEY,
@@ -567,4 +603,177 @@ describe("rescheduleBooking", () => {
567
603
  const stillOriginal = await getBookingByUid(original.uid);
568
604
  expect(stillOriginal?.status).toBe("confirmed");
569
605
  });
606
+
607
+ it("deletes the old Zoom meeting before releasing the original slot", async () => {
608
+ const eventType = makeEventType();
609
+ await seedEventType(eventType);
610
+ const original = await createBooking({
611
+ eventType,
612
+ hostEmail: HOST_EMAIL,
613
+ startTime: "2026-08-10T10:00:00.000Z",
614
+ endTime: "2026-08-10T10:30:00.000Z",
615
+ timezone: "UTC",
616
+ location: { kind: "zoom", credentialId: "zoom-account" },
617
+ attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
618
+ });
619
+
620
+ await rescheduleBooking({
621
+ uid: original.uid,
622
+ newStartTime: "2026-08-10T11:00:00.000Z",
623
+ newEndTime: "2026-08-10T11:30:00.000Z",
624
+ });
625
+
626
+ expect(deleteZoomMeetingMock).toHaveBeenCalledWith({
627
+ credentialId: "zoom-account",
628
+ meetingId: "zoom-meeting-1",
629
+ });
630
+ expect((await getBookingByUid(original.uid))?.status).toBe("rescheduled");
631
+ });
632
+
633
+ it("keeps the original active when the replacement Zoom meeting is missing", async () => {
634
+ const eventType = makeEventType();
635
+ await seedEventType(eventType);
636
+ const original = await createBooking({
637
+ eventType,
638
+ hostEmail: HOST_EMAIL,
639
+ startTime: "2026-08-10T10:00:00.000Z",
640
+ endTime: "2026-08-10T10:30:00.000Z",
641
+ timezone: "UTC",
642
+ location: { kind: "zoom", credentialId: "zoom-account" },
643
+ attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
644
+ });
645
+ createZoomMeetingMock.mockRejectedValueOnce(
646
+ new Error("Zoom creation failed"),
647
+ );
648
+ deleteZoomMeetingMock.mockRejectedValueOnce(
649
+ new Error("old meeting must not be touched"),
650
+ );
651
+
652
+ await expect(
653
+ rescheduleBooking({
654
+ uid: original.uid,
655
+ newStartTime: "2026-08-10T11:00:00.000Z",
656
+ newEndTime: "2026-08-10T11:30:00.000Z",
657
+ }),
658
+ ).rejects.toMatchObject({
659
+ statusCode: 502,
660
+ errorCode: "video_meeting_creation_failed",
661
+ });
662
+
663
+ expect(deleteZoomMeetingMock).not.toHaveBeenCalled();
664
+ expect((await getBookingByUid(original.uid))?.status).toBe("confirmed");
665
+ const { rows } = await execute({
666
+ sql: "SELECT uid, status FROM bookings WHERE from_reschedule = ?",
667
+ args: [original.uid],
668
+ });
669
+ expect(rows).toHaveLength(1);
670
+ const replacement = await getBookingByUid(String(rows[0]!.uid));
671
+ expect(replacement).toMatchObject({ status: "confirmed", references: [] });
672
+ await expect(cancelBooking({ uid: replacement!.uid })).rejects.toThrow(
673
+ /Zoom meeting needs host review/i,
674
+ );
675
+ });
676
+
677
+ it("keeps the original slot confirmed when old Zoom cleanup fails", async () => {
678
+ const eventType = makeEventType();
679
+ await seedEventType(eventType);
680
+ const original = await createBooking({
681
+ eventType,
682
+ hostEmail: HOST_EMAIL,
683
+ startTime: "2026-08-11T10:00:00.000Z",
684
+ endTime: "2026-08-11T10:30:00.000Z",
685
+ timezone: "UTC",
686
+ location: { kind: "zoom", credentialId: "zoom-account" },
687
+ attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
688
+ });
689
+ deleteZoomMeetingMock.mockRejectedValueOnce(
690
+ new Error("Zoom is unavailable"),
691
+ );
692
+
693
+ await expect(
694
+ rescheduleBooking({
695
+ uid: original.uid,
696
+ newStartTime: "2026-08-11T11:00:00.000Z",
697
+ newEndTime: "2026-08-11T11:30:00.000Z",
698
+ }),
699
+ ).rejects.toThrow("Zoom is unavailable");
700
+ expect((await getBookingByUid(original.uid))?.status).toBe("confirmed");
701
+ const { rows } = await execute("SELECT status FROM bookings");
702
+ expect(rows.map((row: any) => row.status).sort()).toEqual([
703
+ "cancelled",
704
+ "confirmed",
705
+ ]);
706
+ expect(deleteZoomMeetingMock).toHaveBeenCalledTimes(2);
707
+ });
708
+
709
+ it("requires host resolution before rescheduling an unrecorded Zoom meeting", async () => {
710
+ const eventType = makeEventType();
711
+ await seedEventType(eventType);
712
+ createZoomMeetingMock.mockRejectedValueOnce(
713
+ new Error("ambiguous Zoom failure"),
714
+ );
715
+ const original = await createBooking({
716
+ eventType,
717
+ hostEmail: HOST_EMAIL,
718
+ startTime: "2026-08-12T10:00:00.000Z",
719
+ endTime: "2026-08-12T10:30:00.000Z",
720
+ timezone: "UTC",
721
+ location: { kind: "zoom", credentialId: "zoom-account" },
722
+ attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
723
+ });
724
+
725
+ await expect(
726
+ rescheduleBooking({
727
+ uid: original.uid,
728
+ newStartTime: "2026-08-12T11:00:00.000Z",
729
+ newEndTime: "2026-08-12T11:30:00.000Z",
730
+ }),
731
+ ).rejects.toThrow(/Zoom meeting needs host review/i);
732
+ expect((await getBookingByUid(original.uid))?.status).toBe("confirmed");
733
+ });
734
+ });
735
+
736
+ describe("cancelBooking", () => {
737
+ it("keeps the slot confirmed when Zoom deletion fails", async () => {
738
+ const booking = await createBooking({
739
+ eventType: makeEventType(),
740
+ hostEmail: HOST_EMAIL,
741
+ startTime: "2026-08-13T10:00:00.000Z",
742
+ endTime: "2026-08-13T10:30:00.000Z",
743
+ timezone: "UTC",
744
+ location: { kind: "zoom", credentialId: "zoom-account" },
745
+ attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
746
+ });
747
+ deleteZoomMeetingMock.mockRejectedValueOnce(
748
+ new Error("Zoom is unavailable"),
749
+ );
750
+
751
+ await expect(cancelBooking({ uid: booking.uid })).rejects.toThrow(
752
+ "Zoom is unavailable",
753
+ );
754
+ expect((await getBookingByUid(booking.uid))?.status).toBe("confirmed");
755
+ });
756
+
757
+ it("requires host resolution before canceling an unrecorded Zoom meeting", async () => {
758
+ createZoomMeetingMock.mockRejectedValueOnce(
759
+ new Error("ambiguous Zoom failure"),
760
+ );
761
+ const booking = await createBooking({
762
+ eventType: makeEventType(),
763
+ hostEmail: HOST_EMAIL,
764
+ startTime: "2026-08-14T10:00:00.000Z",
765
+ endTime: "2026-08-14T10:30:00.000Z",
766
+ timezone: "UTC",
767
+ location: { kind: "zoom", credentialId: "zoom-account" },
768
+ attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
769
+ });
770
+
771
+ await expect(cancelBooking({ uid: booking.uid })).rejects.toThrow(
772
+ /Zoom meeting needs host review/i,
773
+ );
774
+ expect((await getBookingByUid(booking.uid))?.status).toBe("confirmed");
775
+
776
+ await cancelBooking({ uid: booking.uid, zoomMeetingResolved: true });
777
+ expect((await getBookingByUid(booking.uid))?.status).toBe("cancelled");
778
+ });
570
779
  });
@@ -52,6 +52,21 @@ export interface CreateBookingInput {
52
52
  orgId?: string;
53
53
  /** If set, we're rescheduling from this booking uid */
54
54
  fromReschedule?: string;
55
+ /** Keep Zoom reschedules uncommitted until the replacement meeting is usable. */
56
+ requireZoomMeeting?: boolean;
57
+ }
58
+
59
+ export class BookingLifecycleError extends Error {
60
+ constructor(
61
+ message: string,
62
+ readonly statusCode: 409 | 502,
63
+ readonly errorCode:
64
+ | "zoom_meeting_review_required"
65
+ | "video_meeting_cleanup_failed"
66
+ | "video_meeting_creation_failed",
67
+ ) {
68
+ super(message);
69
+ }
55
70
  }
56
71
 
57
72
  export async function createBooking(
@@ -90,6 +105,8 @@ export async function createBooking(
90
105
  orgId: input.orgId,
91
106
  });
92
107
 
108
+ let usableZoomMeeting = false;
109
+
93
110
  // Create video meeting if location is a video kind
94
111
  if (booking.location && isVideoKind(booking.location.kind)) {
95
112
  const provider = getVideoProvider(
@@ -101,7 +118,7 @@ export async function createBooking(
101
118
  credentialId: booking.location.credentialId,
102
119
  booking,
103
120
  });
104
- if (meeting.meetingUrl) {
121
+ if (meeting.meetingId && booking.location.credentialId) {
105
122
  await addBookingReference(booking.id, {
106
123
  type: provider.kind,
107
124
  externalId: meeting.meetingId,
@@ -109,13 +126,30 @@ export async function createBooking(
109
126
  meetingPassword: meeting.meetingPassword,
110
127
  credentialId: booking.location.credentialId,
111
128
  });
129
+ usableZoomMeeting =
130
+ provider.kind === "zoom_video" && Boolean(meeting.meetingUrl);
112
131
  }
113
132
  } catch {
133
+ if (input.requireZoomMeeting) {
134
+ throw new BookingLifecycleError(
135
+ "Replacement Zoom meeting could not be confirmed. The original booking remains active, and the replacement reservation needs host review.",
136
+ 502,
137
+ "video_meeting_creation_failed",
138
+ );
139
+ }
114
140
  // Continue without the video link; the host can fix on the booking detail page
115
141
  }
116
142
  }
117
143
  }
118
144
 
145
+ if (input.requireZoomMeeting && !usableZoomMeeting) {
146
+ throw new BookingLifecycleError(
147
+ "Replacement Zoom meeting could not be confirmed. The original booking remains active, and the replacement reservation needs host review.",
148
+ 502,
149
+ "video_meeting_creation_failed",
150
+ );
151
+ }
152
+
119
153
  // Write to destination calendar
120
154
  await writeToDestinationCalendars(booking);
121
155
 
@@ -133,11 +167,13 @@ export async function rescheduleBooking(input: {
133
167
  newEndTime: string;
134
168
  reason?: string;
135
169
  rescheduledBy?: "attendee" | "host";
170
+ zoomMeetingResolved?: boolean;
136
171
  }): Promise<Booking> {
137
172
  const original = await getBookingByUid(input.uid);
138
173
  if (!original) throw new Error(`Booking ${input.uid} not found`);
139
174
  const eventType = await getEventTypeById(original.eventTypeId);
140
175
  if (!eventType) throw new Error("Event type missing");
176
+ requireZoomMeetingResolution(original, input.zoomMeetingResolved);
141
177
 
142
178
  // Create the new booking (validated against availability, ignoring the
143
179
  // original's own slot) before touching the original, so a slot conflict
@@ -159,8 +195,28 @@ export async function rescheduleBooking(input: {
159
195
  iCalUid: original.iCalUid,
160
196
  iCalSequence: original.iCalSequence + 1,
161
197
  fromReschedule: input.uid,
198
+ requireZoomMeeting: original.location?.kind === "zoom",
162
199
  });
163
200
 
201
+ try {
202
+ await deleteVideoMeetings(original);
203
+ } catch (error) {
204
+ try {
205
+ await cancelBooking({ uid: newBooking.uid });
206
+ } catch (rollbackError) {
207
+ const cleanupMessage =
208
+ rollbackError instanceof Error
209
+ ? rollbackError.message
210
+ : "unknown error";
211
+ throw new BookingLifecycleError(
212
+ `The existing meeting could not be canceled, and the replacement booking could not be fully rolled back: ${cleanupMessage}`,
213
+ 502,
214
+ "video_meeting_cleanup_failed",
215
+ );
216
+ }
217
+ throw error;
218
+ }
219
+
164
220
  // Mark old as rescheduled now that the replacement exists.
165
221
  await updateBookingStatus(input.uid, "rescheduled", {
166
222
  reschedulingReason: input.reason,
@@ -190,9 +246,13 @@ export async function cancelBooking(input: {
190
246
  uid: string;
191
247
  reason?: string;
192
248
  cancelledBy?: "attendee" | "host";
249
+ zoomMeetingResolved?: boolean;
193
250
  }): Promise<Booking> {
194
251
  const booking = await getBookingByUid(input.uid);
195
252
  if (!booking) throw new Error(`Booking ${input.uid} not found`);
253
+ requireZoomMeetingResolution(booking, input.zoomMeetingResolved);
254
+ await deleteVideoMeetings(booking);
255
+
196
256
  await updateBookingStatus(input.uid, "cancelled", {
197
257
  cancellationReason: input.reason,
198
258
  });
@@ -207,21 +267,64 @@ export async function cancelBooking(input: {
207
267
  });
208
268
  } catch {}
209
269
  }
210
- const videoProvider = getVideoProvider(ref.type);
211
- if (videoProvider?.deleteMeeting) {
212
- try {
213
- await videoProvider.deleteMeeting({
214
- credentialId: ref.credentialId,
215
- meetingId: ref.externalId,
216
- });
217
- } catch {}
218
- }
219
270
  }
220
271
 
221
272
  await onBookingCancelled(booking);
222
273
  return (await getBookingByUid(input.uid))!;
223
274
  }
224
275
 
276
+ function requireZoomMeetingResolution(
277
+ booking: Booking,
278
+ zoomMeetingResolved?: boolean,
279
+ ): void {
280
+ if (
281
+ booking.location?.kind === "zoom" &&
282
+ !booking.references.some((ref) => ref.type === "zoom_video") &&
283
+ zoomMeetingResolved !== true
284
+ ) {
285
+ throw new BookingLifecycleError(
286
+ "Zoom meeting needs host review; cancel it in Zoom, then confirm it was resolved",
287
+ 409,
288
+ "zoom_meeting_review_required",
289
+ );
290
+ }
291
+ }
292
+
293
+ async function deleteVideoMeetings(booking: Booking): Promise<void> {
294
+ for (const ref of booking.references) {
295
+ const provider = getVideoProvider(ref.type);
296
+ if (!provider) {
297
+ if (ref.type.endsWith("_video") || ref.type === "google_meet") {
298
+ throw new BookingLifecycleError(
299
+ `${ref.type} provider is unavailable to cancel this meeting`,
300
+ 502,
301
+ "video_meeting_cleanup_failed",
302
+ );
303
+ }
304
+ continue;
305
+ }
306
+ if (!provider.deleteMeeting) {
307
+ throw new BookingLifecycleError(
308
+ `${provider.label} does not support meeting cancellation`,
309
+ 502,
310
+ "video_meeting_cleanup_failed",
311
+ );
312
+ }
313
+ try {
314
+ await provider.deleteMeeting({
315
+ credentialId: ref.credentialId,
316
+ meetingId: ref.externalId,
317
+ });
318
+ } catch (error) {
319
+ throw new BookingLifecycleError(
320
+ `${provider.label} meeting could not be canceled${error instanceof Error ? `: ${error.message}` : ""}`,
321
+ 502,
322
+ "video_meeting_cleanup_failed",
323
+ );
324
+ }
325
+ }
326
+ }
327
+
225
328
  export async function markNoShow(
226
329
  uid: string,
227
330
  attendeeEmail: string,
@@ -232,6 +232,13 @@ describe("createTeamsProvider", () => {
232
232
  ).resolves.toBeUndefined();
233
233
  });
234
234
 
235
+ it("requires a credential before deleting a meeting", async () => {
236
+ await expect(
237
+ provider().deleteMeeting!({ meetingId: "meeting-example" }),
238
+ ).rejects.toThrow("Microsoft Teams requires credentialId");
239
+ expect(fetchMock).not.toHaveBeenCalled();
240
+ });
241
+
235
242
  it.each([401, 403])(
236
243
  "marks a credential invalid on delete HTTP %s",
237
244
  async (status) => {
@@ -165,7 +165,9 @@ export function createTeamsProvider(
165
165
  },
166
166
 
167
167
  async deleteMeeting({ credentialId, meetingId }) {
168
- if (!credentialId) return;
168
+ if (!credentialId) {
169
+ throw new Error("Microsoft Teams requires credentialId");
170
+ }
169
171
  const response = await graphRequest(
170
172
  credentialId,
171
173
  `/me/onlineMeetings/${encodeURIComponent(meetingId)}`,
@@ -0,0 +1,72 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ import { createZoomProvider } from "./zoom.js";
4
+
5
+ describe("createZoomProvider.deleteMeeting", () => {
6
+ const fetchMock = vi.fn<typeof fetch>();
7
+ const getAccessToken = vi.fn(async () => "access-token-example");
8
+
9
+ beforeEach(() => {
10
+ vi.stubGlobal("fetch", fetchMock);
11
+ });
12
+
13
+ afterEach(() => {
14
+ vi.unstubAllGlobals();
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ function provider() {
19
+ return createZoomProvider({
20
+ clientId: "client-id-example",
21
+ clientSecret: "client-secret-example",
22
+ getAccessToken,
23
+ });
24
+ }
25
+
26
+ it("deletes a known meeting", async () => {
27
+ fetchMock.mockResolvedValueOnce(new Response(null, { status: 204 }));
28
+
29
+ await provider().deleteMeeting!({
30
+ credentialId: "zoom-account-example",
31
+ meetingId: "meeting-id-example",
32
+ });
33
+
34
+ expect(fetchMock).toHaveBeenCalledWith(
35
+ "https://api.zoom.us/v2/meetings/meeting-id-example",
36
+ {
37
+ method: "DELETE",
38
+ headers: { authorization: "Bearer access-token-example" },
39
+ },
40
+ );
41
+ });
42
+
43
+ it("treats an already-missing meeting as deleted", async () => {
44
+ fetchMock.mockResolvedValueOnce(new Response(null, { status: 404 }));
45
+
46
+ await expect(
47
+ provider().deleteMeeting!({
48
+ credentialId: "zoom-account-example",
49
+ meetingId: "missing-meeting-example",
50
+ }),
51
+ ).resolves.toBeUndefined();
52
+ });
53
+
54
+ it("preserves a booking when Zoom rejects meeting deletion", async () => {
55
+ fetchMock.mockResolvedValueOnce(new Response(null, { status: 503 }));
56
+
57
+ await expect(
58
+ provider().deleteMeeting!({
59
+ credentialId: "zoom-account-example",
60
+ meetingId: "meeting-id-example",
61
+ }),
62
+ ).rejects.toThrow("Zoom meeting deletion failed: 503");
63
+ });
64
+
65
+ it("requires a credential before deleting a meeting", async () => {
66
+ await expect(
67
+ provider().deleteMeeting!({ meetingId: "meeting-id-example" }),
68
+ ).rejects.toThrow("Zoom requires credentialId");
69
+ expect(getAccessToken).not.toHaveBeenCalled();
70
+ expect(fetchMock).not.toHaveBeenCalled();
71
+ });
72
+ });
@@ -171,15 +171,18 @@ export function createZoomProvider(config: ZoomProviderConfig): VideoProvider {
171
171
  },
172
172
 
173
173
  async deleteMeeting({ credentialId, meetingId }) {
174
- if (!credentialId) return;
174
+ if (!credentialId) throw new Error("Zoom requires credentialId");
175
175
  const token = await config.getAccessToken(credentialId);
176
- await fetch(
176
+ const res = await fetch(
177
177
  `https://api.zoom.us/v2/meetings/${encodeURIComponent(meetingId)}`,
178
178
  {
179
179
  method: "DELETE",
180
180
  headers: { authorization: `Bearer ${token}` },
181
181
  },
182
182
  );
183
+ if (!res.ok && res.status !== 404) {
184
+ throw new Error(`Zoom meeting deletion failed: ${res.status}`);
185
+ }
183
186
  },
184
187
  };
185
188
  }