@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.
Files changed (279) hide show
  1. package/dist/actions/_helpers.d.ts +0 -13
  2. package/dist/actions/_helpers.d.ts.map +1 -1
  3. package/dist/actions/_helpers.js +0 -16
  4. package/dist/actions/_helpers.js.map +1 -1
  5. package/dist/actions/create-team.js +0 -1
  6. package/dist/actions/create-team.js.map +1 -1
  7. package/dist/actions/list-bookings.js +0 -4
  8. package/dist/actions/list-bookings.js.map +1 -1
  9. package/dist/actions/refresh-busy-times.js +0 -1
  10. package/dist/actions/refresh-busy-times.js.map +1 -1
  11. package/dist/actions/revoke-private-link.js +0 -2
  12. package/dist/actions/revoke-private-link.js.map +1 -1
  13. package/dist/actions/update-profile.js +0 -5
  14. package/dist/actions/update-profile.js.map +1 -1
  15. package/dist/core/buffers.d.ts +0 -18
  16. package/dist/core/buffers.d.ts.map +1 -1
  17. package/dist/core/buffers.js +0 -6
  18. package/dist/core/buffers.js.map +1 -1
  19. package/dist/core/conflicts.d.ts +0 -4
  20. package/dist/core/conflicts.d.ts.map +1 -1
  21. package/dist/core/conflicts.js +0 -1
  22. package/dist/core/conflicts.js.map +1 -1
  23. package/dist/core/limits.d.ts +0 -8
  24. package/dist/core/limits.d.ts.map +1 -1
  25. package/dist/core/limits.js.map +1 -1
  26. package/dist/core/round-robin.d.ts +0 -17
  27. package/dist/core/round-robin.d.ts.map +1 -1
  28. package/dist/core/round-robin.js.map +1 -1
  29. package/dist/core/rrule.d.ts.map +1 -1
  30. package/dist/core/rrule.js +0 -7
  31. package/dist/core/rrule.js.map +1 -1
  32. package/dist/core/rules.d.ts +0 -17
  33. package/dist/core/rules.d.ts.map +1 -1
  34. package/dist/core/rules.js +0 -8
  35. package/dist/core/rules.js.map +1 -1
  36. package/dist/core/slots.d.ts +0 -31
  37. package/dist/core/slots.d.ts.map +1 -1
  38. package/dist/core/slots.js +0 -9
  39. package/dist/core/slots.js.map +1 -1
  40. package/dist/core/time.d.ts +0 -24
  41. package/dist/core/time.d.ts.map +1 -1
  42. package/dist/core/time.js +0 -37
  43. package/dist/core/time.js.map +1 -1
  44. package/dist/index.d.ts +0 -10
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +0 -10
  47. package/dist/index.js.map +1 -1
  48. package/dist/manifest.d.ts +0 -9
  49. package/dist/manifest.d.ts.map +1 -1
  50. package/dist/manifest.js +0 -18
  51. package/dist/manifest.js.map +1 -1
  52. package/dist/react/components/SlotPicker.d.ts +0 -8
  53. package/dist/react/components/SlotPicker.d.ts.map +1 -1
  54. package/dist/react/components/SlotPicker.js.map +1 -1
  55. package/dist/react/components/TimezoneSelect.d.ts.map +1 -1
  56. package/dist/react/components/TimezoneSelect.js +0 -2
  57. package/dist/react/components/TimezoneSelect.js.map +1 -1
  58. package/dist/react/components/booking-links/AvailabilityEditor.d.ts +0 -4
  59. package/dist/react/components/booking-links/AvailabilityEditor.d.ts.map +1 -1
  60. package/dist/react/components/booking-links/AvailabilityEditor.js +0 -15
  61. package/dist/react/components/booking-links/AvailabilityEditor.js.map +1 -1
  62. package/dist/react/components/booking-links/BookingLinkCreateDialog.d.ts +0 -6
  63. package/dist/react/components/booking-links/BookingLinkCreateDialog.d.ts.map +1 -1
  64. package/dist/react/components/booking-links/BookingLinkCreateDialog.js +0 -16
  65. package/dist/react/components/booking-links/BookingLinkCreateDialog.js.map +1 -1
  66. package/dist/react/components/booking-links/ConferencingSelector.d.ts +0 -2
  67. package/dist/react/components/booking-links/ConferencingSelector.d.ts.map +1 -1
  68. package/dist/react/components/booking-links/ConferencingSelector.js +0 -24
  69. package/dist/react/components/booking-links/ConferencingSelector.js.map +1 -1
  70. package/dist/react/components/booking-links/CustomFieldsEditor.d.ts +0 -1
  71. package/dist/react/components/booking-links/CustomFieldsEditor.d.ts.map +1 -1
  72. package/dist/react/components/booking-links/CustomFieldsEditor.js +0 -14
  73. package/dist/react/components/booking-links/CustomFieldsEditor.js.map +1 -1
  74. package/dist/react/components/booking-links/DurationPicker.d.ts +0 -1
  75. package/dist/react/components/booking-links/DurationPicker.d.ts.map +1 -1
  76. package/dist/react/components/booking-links/DurationPicker.js +1 -11
  77. package/dist/react/components/booking-links/DurationPicker.js.map +1 -1
  78. package/dist/react/components/booking-links/SlugEditor.d.ts +0 -3
  79. package/dist/react/components/booking-links/SlugEditor.d.ts.map +1 -1
  80. package/dist/react/components/booking-links/SlugEditor.js +0 -11
  81. package/dist/react/components/booking-links/SlugEditor.js.map +1 -1
  82. package/dist/react/components/booking-links/index.d.ts +0 -9
  83. package/dist/react/components/booking-links/index.d.ts.map +1 -1
  84. package/dist/react/components/booking-links/index.js +0 -9
  85. package/dist/react/components/booking-links/index.js.map +1 -1
  86. package/dist/react/components/index.d.ts +0 -10
  87. package/dist/react/components/index.d.ts.map +1 -1
  88. package/dist/react/components/index.js +0 -10
  89. package/dist/react/components/index.js.map +1 -1
  90. package/dist/react/hooks/useBookingFlow.d.ts.map +1 -1
  91. package/dist/react/hooks/useBookingFlow.js +0 -10
  92. package/dist/react/hooks/useBookingFlow.js.map +1 -1
  93. package/dist/react/hooks/useEventType.d.ts.map +1 -1
  94. package/dist/react/hooks/useEventType.js +0 -4
  95. package/dist/react/hooks/useEventType.js.map +1 -1
  96. package/dist/react/hooks/useReschedule.d.ts.map +1 -1
  97. package/dist/react/hooks/useReschedule.js +0 -4
  98. package/dist/react/hooks/useReschedule.js.map +1 -1
  99. package/dist/react/hooks/useSlots.d.ts +0 -2
  100. package/dist/react/hooks/useSlots.d.ts.map +1 -1
  101. package/dist/react/hooks/useSlots.js +0 -8
  102. package/dist/react/hooks/useSlots.js.map +1 -1
  103. package/dist/react/hooks/useTimezone.d.ts.map +1 -1
  104. package/dist/react/hooks/useTimezone.js +0 -4
  105. package/dist/react/hooks/useTimezone.js.map +1 -1
  106. package/dist/react/index.d.ts +0 -5
  107. package/dist/react/index.d.ts.map +1 -1
  108. package/dist/react/index.js +0 -5
  109. package/dist/react/index.js.map +1 -1
  110. package/dist/schema/bookings.d.ts +0 -7
  111. package/dist/schema/bookings.d.ts.map +1 -1
  112. package/dist/schema/bookings.js +0 -29
  113. package/dist/schema/bookings.js.map +1 -1
  114. package/dist/schema/calendar-cache.d.ts.map +1 -1
  115. package/dist/schema/calendar-cache.js +0 -11
  116. package/dist/schema/calendar-cache.js.map +1 -1
  117. package/dist/schema/credentials.d.ts +0 -8
  118. package/dist/schema/credentials.d.ts.map +1 -1
  119. package/dist/schema/credentials.js +0 -28
  120. package/dist/schema/credentials.js.map +1 -1
  121. package/dist/schema/event-types.d.ts +0 -10
  122. package/dist/schema/event-types.d.ts.map +1 -1
  123. package/dist/schema/event-types.js +0 -42
  124. package/dist/schema/event-types.js.map +1 -1
  125. package/dist/schema/index.d.ts +0 -11
  126. package/dist/schema/index.d.ts.map +1 -1
  127. package/dist/schema/index.js +0 -11
  128. package/dist/schema/index.js.map +1 -1
  129. package/dist/schema/routing-forms.d.ts.map +1 -1
  130. package/dist/schema/routing-forms.js +0 -17
  131. package/dist/schema/routing-forms.js.map +1 -1
  132. package/dist/schema/schedules.d.ts +0 -12
  133. package/dist/schema/schedules.d.ts.map +1 -1
  134. package/dist/schema/schedules.js +0 -25
  135. package/dist/schema/schedules.js.map +1 -1
  136. package/dist/schema/teams.d.ts.map +1 -1
  137. package/dist/schema/teams.js +0 -7
  138. package/dist/schema/teams.js.map +1 -1
  139. package/dist/schema/workflows.d.ts +0 -7
  140. package/dist/schema/workflows.d.ts.map +1 -1
  141. package/dist/schema/workflows.js +0 -19
  142. package/dist/schema/workflows.js.map +1 -1
  143. package/dist/server/availability-engine.d.ts +0 -12
  144. package/dist/server/availability-engine.d.ts.map +1 -1
  145. package/dist/server/availability-engine.js +0 -20
  146. package/dist/server/availability-engine.js.map +1 -1
  147. package/dist/server/booking-service.d.ts +0 -14
  148. package/dist/server/booking-service.d.ts.map +1 -1
  149. package/dist/server/booking-service.js +0 -8
  150. package/dist/server/booking-service.js.map +1 -1
  151. package/dist/server/bookings-repo.d.ts +0 -7
  152. package/dist/server/bookings-repo.d.ts.map +1 -1
  153. package/dist/server/bookings-repo.js +0 -3
  154. package/dist/server/bookings-repo.js.map +1 -1
  155. package/dist/server/context.d.ts +0 -16
  156. package/dist/server/context.d.ts.map +1 -1
  157. package/dist/server/context.js.map +1 -1
  158. package/dist/server/db-types.d.ts +0 -11
  159. package/dist/server/db-types.d.ts.map +1 -1
  160. package/dist/server/event-types-repo.d.ts +0 -10
  161. package/dist/server/event-types-repo.d.ts.map +1 -1
  162. package/dist/server/event-types-repo.js +0 -21
  163. package/dist/server/event-types-repo.js.map +1 -1
  164. package/dist/server/hooks.d.ts.map +1 -1
  165. package/dist/server/hooks.js +0 -11
  166. package/dist/server/hooks.js.map +1 -1
  167. package/dist/server/ics.d.ts +0 -7
  168. package/dist/server/ics.d.ts.map +1 -1
  169. package/dist/server/ics.js.map +1 -1
  170. package/dist/server/providers/builtin-video.d.ts +0 -5
  171. package/dist/server/providers/builtin-video.d.ts.map +1 -1
  172. package/dist/server/providers/builtin-video.js.map +1 -1
  173. package/dist/server/providers/google-calendar.d.ts +0 -3
  174. package/dist/server/providers/google-calendar.d.ts.map +1 -1
  175. package/dist/server/providers/google-calendar.js +0 -2
  176. package/dist/server/providers/google-calendar.js.map +1 -1
  177. package/dist/server/providers/google-meet.d.ts +0 -7
  178. package/dist/server/providers/google-meet.d.ts.map +1 -1
  179. package/dist/server/providers/google-meet.js.map +1 -1
  180. package/dist/server/providers/office365.d.ts +0 -6
  181. package/dist/server/providers/office365.d.ts.map +1 -1
  182. package/dist/server/providers/office365.js.map +1 -1
  183. package/dist/server/providers/registry.d.ts +0 -4
  184. package/dist/server/providers/registry.d.ts.map +1 -1
  185. package/dist/server/providers/registry.js.map +1 -1
  186. package/dist/server/providers/teams.d.ts +0 -6
  187. package/dist/server/providers/teams.d.ts.map +1 -1
  188. package/dist/server/providers/teams.js +0 -2
  189. package/dist/server/providers/teams.js.map +1 -1
  190. package/dist/server/providers/types.d.ts +0 -27
  191. package/dist/server/providers/types.d.ts.map +1 -1
  192. package/dist/server/providers/zoom.d.ts +0 -19
  193. package/dist/server/providers/zoom.d.ts.map +1 -1
  194. package/dist/server/providers/zoom.js +0 -2
  195. package/dist/server/providers/zoom.js.map +1 -1
  196. package/dist/server/schedules-repo.d.ts.map +1 -1
  197. package/dist/server/schedules-repo.js +0 -4
  198. package/dist/server/schedules-repo.js.map +1 -1
  199. package/dist/server/video-oauth-state.d.ts +0 -5
  200. package/dist/server/video-oauth-state.d.ts.map +1 -1
  201. package/dist/server/video-oauth-state.js +1 -9
  202. package/dist/server/video-oauth-state.js.map +1 -1
  203. package/dist/server/video-oauth.d.ts +0 -4
  204. package/dist/server/video-oauth.d.ts.map +1 -1
  205. package/dist/server/video-oauth.js +0 -23
  206. package/dist/server/video-oauth.js.map +1 -1
  207. package/dist/shared/index.d.ts +0 -37
  208. package/dist/shared/index.d.ts.map +1 -1
  209. package/dist/shared/index.js +0 -4
  210. package/dist/shared/index.js.map +1 -1
  211. package/package.json +4 -4
  212. package/src/actions/_helpers.ts +0 -16
  213. package/src/actions/booking-authz.spec.ts +0 -6
  214. package/src/actions/create-team.ts +0 -1
  215. package/src/actions/event-type-authz.spec.ts +0 -11
  216. package/src/actions/list-bookings.ts +0 -4
  217. package/src/actions/refresh-busy-times.ts +0 -1
  218. package/src/actions/revoke-private-link.ts +0 -2
  219. package/src/actions/update-profile.ts +0 -5
  220. package/src/core/buffers.ts +0 -18
  221. package/src/core/conflicts.ts +0 -4
  222. package/src/core/limits.ts +0 -8
  223. package/src/core/round-robin.test.ts +0 -1
  224. package/src/core/round-robin.ts +0 -17
  225. package/src/core/rrule.ts +0 -7
  226. package/src/core/rules.ts +0 -17
  227. package/src/core/slots.test.ts +1 -11
  228. package/src/core/slots.ts +0 -40
  229. package/src/core/time.ts +0 -37
  230. package/src/index.ts +0 -11
  231. package/src/manifest.ts +0 -19
  232. package/src/react/components/SlotPicker.tsx +0 -8
  233. package/src/react/components/TimezoneSelect.tsx +0 -2
  234. package/src/react/components/_shadcn-shims.d.ts +0 -35
  235. package/src/react/components/booking-links/AvailabilityEditor.tsx +0 -15
  236. package/src/react/components/booking-links/BookingLinkCreateDialog.tsx +0 -22
  237. package/src/react/components/booking-links/ConferencingSelector.tsx +0 -26
  238. package/src/react/components/booking-links/CustomFieldsEditor.tsx +0 -15
  239. package/src/react/components/booking-links/DurationPicker.tsx +1 -12
  240. package/src/react/components/booking-links/SlugEditor.tsx +0 -14
  241. package/src/react/components/booking-links/index.ts +0 -9
  242. package/src/react/components/index.ts +0 -10
  243. package/src/react/hooks/useBookingFlow.ts +0 -10
  244. package/src/react/hooks/useEventType.ts +0 -4
  245. package/src/react/hooks/useReschedule.ts +0 -4
  246. package/src/react/hooks/useSlots.ts +0 -10
  247. package/src/react/hooks/useTimezone.ts +0 -4
  248. package/src/react/index.ts +0 -5
  249. package/src/schema/bookings.ts +0 -29
  250. package/src/schema/calendar-cache.ts +0 -11
  251. package/src/schema/credentials.ts +0 -28
  252. package/src/schema/event-types.ts +0 -42
  253. package/src/schema/index.ts +0 -11
  254. package/src/schema/routing-forms.ts +0 -17
  255. package/src/schema/schedules.ts +0 -25
  256. package/src/schema/teams.ts +0 -7
  257. package/src/schema/workflows.ts +0 -19
  258. package/src/server/availability-engine.test.ts +0 -1
  259. package/src/server/availability-engine.ts +0 -22
  260. package/src/server/booking-service.spec.ts +0 -15
  261. package/src/server/booking-service.ts +0 -22
  262. package/src/server/bookings-repo.ts +0 -10
  263. package/src/server/context.ts +0 -16
  264. package/src/server/db-types.ts +0 -11
  265. package/src/server/event-types-repo.ts +0 -31
  266. package/src/server/hooks.ts +0 -11
  267. package/src/server/ics.ts +0 -7
  268. package/src/server/providers/builtin-video.ts +0 -5
  269. package/src/server/providers/google-calendar.ts +0 -5
  270. package/src/server/providers/google-meet.ts +0 -7
  271. package/src/server/providers/office365.ts +0 -6
  272. package/src/server/providers/registry.ts +0 -4
  273. package/src/server/providers/teams.ts +0 -8
  274. package/src/server/providers/types.ts +0 -27
  275. package/src/server/providers/zoom.ts +0 -21
  276. package/src/server/schedules-repo.ts +0 -4
  277. package/src/server/video-oauth-state.ts +1 -10
  278. package/src/server/video-oauth.ts +0 -23
  279. package/src/shared/index.ts +0 -38
@@ -1,51 +1,27 @@
1
- /**
2
- * Credentials — thin view over framework `oauth_tokens` that records which
3
- * calendar / video integrations a user has connected. The actual OAuth
4
- * tokens live in core's `oauth_tokens` table; this table stores display
5
- * metadata and flags needed by the scheduling UI (display name, invalid
6
- * flag, app icon, default-for-type).
7
- */
8
1
  import { table, text } from "@agent-native/core/db/schema";
9
2
  import { boolean } from "drizzle-orm/pg-core";
10
3
 
11
4
  export const schedulingCredentials = table("scheduling_credentials", {
12
5
  id: text("id").primaryKey(),
13
- /** Provider slug: "google_calendar", "office365_calendar", "zoom_video", "daily_video", … */
14
6
  type: text("type").notNull(),
15
- /** Owner (user) — for team credentials, use teamId too */
16
7
  userEmail: text("user_email"),
17
8
  teamId: text("team_id"),
18
- /** App id from framework app store */
19
9
  appId: text("app_id"),
20
- /** Core `oauth_tokens.id` if applicable */
21
10
  oauthTokenId: text("oauth_token_id"),
22
- /** Human-friendly label shown in UI */
23
11
  displayName: text("display_name"),
24
- /** External account email (e.g. Google account email) */
25
12
  externalEmail: text("external_email"),
26
- /** True after a 401/403 — UI prompts re-connect */
27
13
  invalid: boolean("invalid").notNull().default(false),
28
- /** Whether this is the user's default for its category (e.g. default video) */
29
14
  isDefault: boolean("is_default").notNull().default(false),
30
15
  createdAt: text("created_at").notNull(),
31
16
  updatedAt: text("updated_at").notNull(),
32
17
  });
33
18
 
34
- /**
35
- * Which external calendars a credential reads "busy" times from.
36
- * A single credential (e.g. a Google account) may expose multiple calendars
37
- * (primary, vacation, shared). Users pick a subset to check for conflicts,
38
- * plus exactly one as the destination for new events.
39
- */
40
19
  export const selectedCalendars = table("selected_calendars", {
41
20
  id: text("id").primaryKey(),
42
21
  credentialId: text("credential_id").notNull(),
43
22
  userEmail: text("user_email").notNull(),
44
- /** External calendar id from the provider */
45
23
  externalId: text("external_id").notNull(),
46
- /** Provider name for this entry */
47
24
  integration: text("integration").notNull(),
48
- /** Optional event-type-level override (only check this calendar for that event) */
49
25
  eventTypeId: text("event_type_id"),
50
26
  createdAt: text("created_at").notNull(),
51
27
  });
@@ -54,16 +30,13 @@ export const destinationCalendars = table("destination_calendars", {
54
30
  id: text("id").primaryKey(),
55
31
  credentialId: text("credential_id").notNull(),
56
32
  userEmail: text("user_email").notNull(),
57
- /** Provider name */
58
33
  integration: text("integration").notNull(),
59
34
  externalId: text("external_id").notNull(),
60
35
  primaryEmail: text("primary_email"),
61
- /** Optional event-type-level override */
62
36
  eventTypeId: text("event_type_id"),
63
37
  createdAt: text("created_at").notNull(),
64
38
  });
65
39
 
66
- /** Verified sender emails for workflows sending from a custom address. */
67
40
  export const verifiedEmails = table("verified_emails", {
68
41
  id: text("id").primaryKey(),
69
42
  email: text("email").notNull(),
@@ -72,7 +45,6 @@ export const verifiedEmails = table("verified_emails", {
72
45
  verifiedAt: text("verified_at").notNull(),
73
46
  });
74
47
 
75
- /** Verified phone numbers for workflows sending SMS. */
76
48
  export const verifiedNumbers = table("verified_numbers", {
77
49
  id: text("id").primaryKey(),
78
50
  phoneNumber: text("phone_number").notNull(),
@@ -1,14 +1,3 @@
1
- /**
2
- * Event types — the top-level bookable definition.
3
- *
4
- * An EventType represents "a 30-minute intro call", "a team round-robin sales
5
- * demo", or "a managed internal 1:1". It is the primary resource users create,
6
- * edit, and share booking links for.
7
- *
8
- * Ownership: personal event types are owned by a user (ownerEmail);
9
- * team event types are owned by a team (teamId). Sharing is via the framework
10
- * sharing system (`event_type_shares`).
11
- */
12
1
  import {
13
2
  table,
14
3
  text,
@@ -21,44 +10,33 @@ import { boolean } from "drizzle-orm/pg-core";
21
10
  export const eventTypes = table("event_types", {
22
11
  id: text("id").primaryKey(),
23
12
 
24
- // Identity
25
13
  title: text("title").notNull(),
26
14
  slug: text("slug").notNull(),
27
15
  description: text("description"),
28
- /** Default duration in minutes */
29
16
  length: integer("length").notNull().default(30),
30
- /** JSON array of additional duration choices, e.g. [15, 30, 60] */
31
17
  durations: text("durations"),
32
18
  position: integer("position").notNull().default(0),
33
19
  hidden: boolean("hidden").notNull().default(false),
34
20
  color: text("color"),
35
21
 
36
- // Scheduling model
37
22
  schedulingType: text("scheduling_type", {
38
23
  enum: ["personal", "collective", "round-robin", "managed"],
39
24
  })
40
25
  .notNull()
41
26
  .default("personal"),
42
- /** Team id if this is a team event type; null for personal */
43
27
  teamId: text("team_id"),
44
28
 
45
- // Locations (JSON array of Location objects)
46
29
  locations: text("locations"),
47
30
 
48
- // Custom fields (JSON array of CustomField objects)
49
31
  customFields: text("custom_fields"),
50
32
 
51
- // Default schedule reference
52
33
  scheduleId: text("schedule_id"),
53
34
 
54
- // Buffers & notice
55
35
  minimumBookingNotice: integer("minimum_booking_notice").notNull().default(0),
56
36
  beforeEventBuffer: integer("before_event_buffer").notNull().default(0),
57
37
  afterEventBuffer: integer("after_event_buffer").notNull().default(0),
58
- /** Slot granularity in minutes; null = use duration */
59
38
  slotInterval: integer("slot_interval"),
60
39
 
61
- // Booking window
62
40
  periodType: text("period_type", {
63
41
  enum: ["unlimited", "rolling", "range"],
64
42
  })
@@ -68,7 +46,6 @@ export const eventTypes = table("event_types", {
68
46
  periodStartDate: text("period_start_date"),
69
47
  periodEndDate: text("period_end_date"),
70
48
 
71
- // Capacity & policies
72
49
  seatsPerTimeSlot: integer("seats_per_time_slot"),
73
50
  requiresConfirmation: boolean("requires_confirmation")
74
51
  .notNull()
@@ -77,16 +54,12 @@ export const eventTypes = table("event_types", {
77
54
  hideCalendarNotes: boolean("hide_calendar_notes").notNull().default(false),
78
55
  successRedirectUrl: text("success_redirect_url"),
79
56
  bookingLimits: text("booking_limits"),
80
- /** Lock timezone on Booker (for in-person or local-only events) */
81
57
  lockTimeZoneToggle: boolean("lock_time_zone_toggle").notNull().default(false),
82
58
 
83
- // Recurring (JSON RecurringEventRule) — Tier 2
84
59
  recurringEvent: text("recurring_event"),
85
60
 
86
- // Templated event name: "{name} + {host}"
87
61
  eventName: text("event_name"),
88
62
 
89
- // Misc
90
63
  metadata: text("metadata"),
91
64
  createdAt: text("created_at").notNull(),
92
65
  updatedAt: text("updated_at").notNull(),
@@ -94,26 +67,17 @@ export const eventTypes = table("event_types", {
94
67
  ...ownableColumns(),
95
68
  });
96
69
 
97
- /**
98
- * Host assignments for team / round-robin / collective event types.
99
- * Composite key (userEmail, eventTypeId).
100
- */
101
70
  export const eventTypeHosts = table("event_type_hosts", {
102
71
  eventTypeId: text("event_type_id").notNull(),
103
72
  userEmail: text("user_email").notNull(),
104
- /** Fixed hosts always attend; non-fixed hosts rotate in round-robin */
105
73
  isFixed: boolean("is_fixed").notNull().default(false),
106
- /** Relative weight for weighted round-robin (default 1) */
107
74
  weight: integer("weight").notNull().default(1),
108
- /** Lower number = higher priority in round-robin tiebreak */
109
75
  priority: integer("priority").notNull().default(2),
110
- /** Host-specific schedule override; null = use host's default */
111
76
  scheduleId: text("schedule_id"),
112
77
  groupId: text("group_id"),
113
78
  createdAt: text("created_at").notNull(),
114
79
  });
115
80
 
116
- /** Host groups — collective assignment within a round-robin group. */
117
81
  export const eventTypeHostGroups = table("event_type_host_groups", {
118
82
  id: text("id").primaryKey(),
119
83
  eventTypeId: text("event_type_id").notNull(),
@@ -121,19 +85,13 @@ export const eventTypeHostGroups = table("event_type_host_groups", {
121
85
  createdAt: text("created_at").notNull(),
122
86
  });
123
87
 
124
- /**
125
- * Rename history — e.g. `/me/old-slug` → `/me/new-slug`.
126
- * Public booker redirects the old slug to the new one.
127
- */
128
88
  export const eventTypeSlugRedirects = table("event_type_slug_redirects", {
129
- /** Composite: "ownerEmail:slug" or "team:teamId:slug" — unique across ownership scope */
130
89
  oldKey: text("old_key").primaryKey(),
131
90
  newKey: text("new_key").notNull(),
132
91
  eventTypeId: text("event_type_id"),
133
92
  createdAt: text("created_at").notNull(),
134
93
  });
135
94
 
136
- /** Hashed private links (`/d/:hash/:slug`) — shareable tokens that don't expose the owner's username. */
137
95
  export const hashedLinks = table("hashed_links", {
138
96
  id: text("id").primaryKey(),
139
97
  hash: text("hash").notNull().unique(),
@@ -1,14 +1,3 @@
1
- /**
2
- * Barrel export for all scheduling schema tables.
3
- *
4
- * Consumer apps compose this with their own schema:
5
- *
6
- * // server/db/schema.ts
7
- * export * from "@agent-native/scheduling/schema";
8
- * export * from "./local-tables.js";
9
- *
10
- * Drizzle's schema scanner picks up all tables from the combined namespace.
11
- */
12
1
  export * from "./event-types.js";
13
2
  export * from "./schedules.js";
14
3
  export * from "./bookings.js";
@@ -1,12 +1,3 @@
1
- /**
2
- * Routing forms — ChiliPiper-style pre-booking forms that route prospects to
3
- * the right event type based on their answers.
4
- *
5
- * A form has fields (text/select/multi), rules (match conditions → action),
6
- * and a fallback. Public form URL is `/forms/:formId`; on submit we evaluate
7
- * rules in order and either redirect to an event-type booker, open an
8
- * external URL, or show a custom message.
9
- */
10
1
  import {
11
2
  table,
12
3
  text,
@@ -21,11 +12,8 @@ export const routingForms = table("routing_forms", {
21
12
  description: text("description"),
22
13
  teamId: text("team_id"),
23
14
  disabled: boolean("disabled").notNull().default(false),
24
- /** JSON array of RoutingFormField */
25
15
  fields: text("fields").notNull().default("[]"),
26
- /** JSON array of RoutingFormRule */
27
16
  rules: text("rules").notNull().default("[]"),
28
- /** JSON RoutingFormRule action object for when no rules match */
29
17
  fallback: text("fallback"),
30
18
  createdAt: text("created_at").notNull(),
31
19
  updatedAt: text("updated_at").notNull(),
@@ -35,15 +23,10 @@ export const routingForms = table("routing_forms", {
35
23
  export const routingFormResponses = table("routing_form_responses", {
36
24
  id: text("id").primaryKey(),
37
25
  formId: text("form_id").notNull(),
38
- /** JSON object of fieldId → value */
39
26
  response: text("response").notNull(),
40
- /** Booking id if the response resulted in a booking */
41
27
  bookingId: text("booking_id"),
42
- /** Which rule matched (null if fallback) */
43
28
  matchedRuleId: text("matched_rule_id"),
44
- /** Resulting action description for quick filtering */
45
29
  routedTo: text("routed_to"),
46
- /** Submitter context */
47
30
  submitterEmail: text("submitter_email"),
48
31
  submitterIp: text("submitter_ip"),
49
32
  createdAt: text("created_at").notNull(),
@@ -1,12 +1,3 @@
1
- /**
2
- * Schedules — named availability presets ("Working Hours", "Evenings").
3
- *
4
- * A Schedule has weekly rules (e.g. Mon-Fri 9am-5pm) stored as rows in
5
- * `schedule_availability`, plus one-off overrides stored in `date_overrides`.
6
- *
7
- * Each user has one default schedule; event types can pick any of the user's
8
- * schedules, or a host-specific override for team events.
9
- */
10
1
  import {
11
2
  table,
12
3
  text,
@@ -26,38 +17,23 @@ export const schedules = table("schedules", {
26
17
  ...ownableColumns(),
27
18
  });
28
19
 
29
- /**
30
- * Weekly availability rules.
31
- * Each row is one interval on one day-of-week for one schedule.
32
- * Example: scheduleId=X, day=1 (Mon), startTime="09:00", endTime="12:00".
33
- */
34
20
  export const scheduleAvailability = table("schedule_availability", {
35
21
  id: text("id").primaryKey(),
36
22
  scheduleId: text("schedule_id").notNull(),
37
- /** 0=Sunday … 6=Saturday */
38
23
  day: integer("day").notNull(),
39
- /** "HH:MM" in schedule's timezone */
40
24
  startTime: text("start_time").notNull(),
41
25
  endTime: text("end_time").notNull(),
42
26
  createdAt: text("created_at").notNull(),
43
27
  });
44
28
 
45
- /**
46
- * Date-specific overrides.
47
- * Example: scheduleId=X, date="2026-04-25", intervals=[] (fully blocked).
48
- * Or intervals=[{"09:00"-"11:00"}] (only 9-11 on that day).
49
- */
50
29
  export const dateOverrides = table("date_overrides", {
51
30
  id: text("id").primaryKey(),
52
31
  scheduleId: text("schedule_id").notNull(),
53
- /** YYYY-MM-DD in schedule's timezone */
54
32
  date: text("date").notNull(),
55
- /** JSON array of {startTime,endTime}. Empty = fully blocked. */
56
33
  intervals: text("intervals").notNull().default("[]"),
57
34
  createdAt: text("created_at").notNull(),
58
35
  });
59
36
 
60
- /** Time-zoned travel windows that override the user's default timezone. */
61
37
  export const travelSchedules = table("travel_schedules", {
62
38
  id: text("id").primaryKey(),
63
39
  userEmail: text("user_email").notNull(),
@@ -67,7 +43,6 @@ export const travelSchedules = table("travel_schedules", {
67
43
  createdAt: text("created_at").notNull(),
68
44
  });
69
45
 
70
- /** Out of office — blocks bookings and optionally redirects to a coworker. */
71
46
  export const outOfOfficeEntries = table("out_of_office_entries", {
72
47
  id: text("id").primaryKey(),
73
48
  userEmail: text("user_email").notNull(),
@@ -1,10 +1,3 @@
1
- /**
2
- * Teams — groupings of users who share event types, round-robin across hosts,
3
- * and present a team booking page at `/team/:slug`.
4
- *
5
- * Framework `org` provides heavier identity (for full multi-tenant orgs);
6
- * teams here are lighter-weight and may be scoped to a single org.
7
- */
8
1
  import {
9
2
  table,
10
3
  text,
@@ -1,10 +1,3 @@
1
- /**
2
- * Workflows — trigger-based automations ("email attendee 1h before event").
3
- *
4
- * Each workflow has a trigger + ordered steps. Steps run on a schedule via
5
- * the framework's recurring-jobs mechanism: when a booking fires a trigger,
6
- * we materialize scheduled reminders; a job processes them when due.
7
- */
8
1
  import {
9
2
  table,
10
3
  text,
@@ -29,7 +22,6 @@ export const workflows = table("workflows", {
29
22
  }).notNull(),
30
23
  teamId: text("team_id"),
31
24
  disabled: boolean("disabled").notNull().default(false),
32
- /** JSON array of eventTypeIds this workflow runs on. Empty = none. */
33
25
  activeOnEventTypeIds: text("active_on_event_type_ids")
34
26
  .notNull()
35
27
  .default("[]"),
@@ -53,24 +45,16 @@ export const workflowSteps = table("workflow_steps", {
53
45
  "webhook",
54
46
  ],
55
47
  }).notNull(),
56
- /** Offset in minutes from the trigger. Negative = before (for before-event). */
57
48
  offsetMinutes: integer("offset_minutes").notNull().default(0),
58
- /** Target email / phone / url depending on action */
59
49
  sendTo: text("send_to"),
60
50
  emailSubject: text("email_subject"),
61
51
  emailBody: text("email_body"),
62
52
  smsBody: text("sms_body"),
63
53
  webhookUrl: text("webhook_url"),
64
- /** Named template key (e.g. "default-reminder") */
65
54
  template: text("template"),
66
55
  createdAt: text("created_at").notNull(),
67
56
  });
68
57
 
69
- /**
70
- * Materialized reminders waiting to fire.
71
- * Written by the booking-service hook when a trigger occurs.
72
- * Drained by a recurring job that processes due rows.
73
- */
74
58
  export const scheduledReminders = table("scheduled_reminders", {
75
59
  id: text("id").primaryKey(),
76
60
  bookingId: text("booking_id").notNull(),
@@ -87,14 +71,12 @@ export const scheduledReminders = table("scheduled_reminders", {
87
71
  createdAt: text("created_at").notNull(),
88
72
  });
89
73
 
90
- /** Outgoing webhook subscriptions. */
91
74
  export const webhooks = table("webhooks", {
92
75
  id: text("id").primaryKey(),
93
76
  name: text("name"),
94
77
  subscriberUrl: text("subscriber_url").notNull(),
95
78
  secret: text("secret"),
96
79
  active: boolean("active").notNull().default(true),
97
- /** JSON array of trigger keys */
98
80
  eventTriggers: text("event_triggers").notNull().default("[]"),
99
81
  teamId: text("team_id"),
100
82
  eventTypeId: text("event_type_id"),
@@ -114,7 +96,6 @@ export const webhookDeliveries = table("webhook_deliveries", {
114
96
  attempts: integer("attempts").notNull().default(0),
115
97
  });
116
98
 
117
- /** API keys for programmatic access. */
118
99
  export const apiKeys = table("api_keys", {
119
100
  id: text("id").primaryKey(),
120
101
  hashedKey: text("hashed_key").notNull().unique(),
@@ -29,7 +29,6 @@ interface FakeDbInput {
29
29
  }>;
30
30
  credentials?: CredentialRow[];
31
31
  selected?: SelectedCalendarRow[];
32
- /** Supports the pre-batching implementation during characterization. */
33
32
  legacySelectedBatches?: SelectedCalendarRow[][];
34
33
  }
35
34
 
@@ -1,11 +1,3 @@
1
- /**
2
- * Availability engine — combines an event type, schedule, and calendar busy
3
- * intervals into the slot list shown to the Booker.
4
- *
5
- * This is where the pure `computeAvailableSlots` gets plugged into the real
6
- * world: it fetches the schedule, merges busy times from the selected
7
- * calendars + existing bookings, and applies booking limits.
8
- */
9
1
  import { eq, gte, lt, and, inArray } from "drizzle-orm";
10
2
 
11
3
  import { expandSlotForConflictCheck } from "../core/buffers.js";
@@ -39,16 +31,9 @@ export interface AssertSlotAvailableInput {
39
31
  endTime: string;
40
32
  beforeEventBuffer?: number;
41
33
  afterEventBuffer?: number;
42
- /** Booking uid to ignore when checking conflicts (e.g. the one being rescheduled). */
43
34
  excludeBookingUid?: string;
44
35
  }
45
36
 
46
- /**
47
- * Re-validate a single requested interval right before it's written —
48
- * cheap by design: aggregates busy only over the buffer-expanded window
49
- * instead of scanning a full day like `getAvailableSlots`. Throws
50
- * `SlotConflictError` if the window collides with existing busy time.
51
- */
52
37
  export async function assertSlotAvailable(
53
38
  input: AssertSlotAvailableInput,
54
39
  ): Promise<void> {
@@ -73,7 +58,6 @@ export async function assertSlotAvailable(
73
58
 
74
59
  export interface GetSlotsInput {
75
60
  eventType: EventType;
76
- /** The user we're finding availability for — their schedule + calendars. */
77
61
  forUserEmail: string;
78
62
  rangeStart: Date;
79
63
  rangeEnd: Date;
@@ -141,10 +125,6 @@ async function resolveDefaultSchedule(
141
125
  return getScheduleById(rows[0].id);
142
126
  }
143
127
 
144
- /**
145
- * Merge busy intervals from: (a) existing bookings for the user, (b) selected
146
- * external calendars (via providers), (c) the calendar cache.
147
- */
148
128
  export async function aggregateBusy(input: {
149
129
  userEmail: string;
150
130
  rangeStart: Date;
@@ -154,7 +134,6 @@ export async function aggregateBusy(input: {
154
134
  const db = getDb();
155
135
  const busy: BusyInterval[] = [];
156
136
 
157
- // Existing bookings where this user is the host
158
137
  const bookings = await db
159
138
  .select()
160
139
  .from(schema.bookings)
@@ -174,7 +153,6 @@ export async function aggregateBusy(input: {
174
153
  });
175
154
  }
176
155
 
177
- // External calendars via registered providers
178
156
  const creds = await db
179
157
  .select()
180
158
  .from(schema.schedulingCredentials)
@@ -305,7 +305,6 @@ afterEach(async () => {
305
305
  rmSync(dbDir, { recursive: true, force: true });
306
306
  });
307
307
 
308
- /** `rescheduleBooking` re-loads the event type by id, so it must exist. */
309
308
  async function seedEventType(eventType: EventType): Promise<void> {
310
309
  await execute({
311
310
  sql: `INSERT INTO event_types (
@@ -405,9 +404,6 @@ describe("insertBooking", () => {
405
404
  timezone: "UTC",
406
405
  attendees: [
407
406
  { email: ATTENDEE_EMAIL, name: "Attendee One" },
408
- // A null email violates the NOT NULL constraint after the first
409
- // attendee (and the booking row) have already been written —
410
- // proving the whole write is one atomic unit.
411
407
  { email: null as unknown as string, name: "Bad Attendee" },
412
408
  ],
413
409
  ownerEmail: HOST_EMAIL,
@@ -499,8 +495,6 @@ describe("createBooking", () => {
499
495
  attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
500
496
  });
501
497
 
502
- // Starts exactly when the first booking ends, so the raw windows don't
503
- // overlap — only the buffered event type's 15-minute lead-in collides.
504
498
  const bufferedEventType = makeEventType({
505
499
  id: "event-type-buffered",
506
500
  beforeEventBuffer: 15,
@@ -518,9 +512,6 @@ describe("createBooking", () => {
518
512
  });
519
513
 
520
514
  it("allows an out-of-availability free slot once the conflicting booking is cancelled", async () => {
521
- // Sanity check that the conflict guard is scoped to the requested
522
- // window, not a blanket rejection — a later, non-overlapping slot for
523
- // the same host must still succeed.
524
515
  const eventType = makeEventType();
525
516
  await createBooking({
526
517
  eventType,
@@ -556,9 +547,6 @@ describe("rescheduleBooking", () => {
556
547
  attendee: { email: ATTENDEE_EMAIL, name: "Attendee One" },
557
548
  });
558
549
 
559
- // Reschedule to an overlapping-but-shifted slot; if the original
560
- // booking's own busy interval weren't excluded, this would always
561
- // conflict with itself.
562
550
  const rescheduled = await rescheduleBooking({
563
551
  uid: original.uid,
564
552
  newStartTime: "2026-08-08T10:15:00.000Z",
@@ -597,9 +585,6 @@ describe("rescheduleBooking", () => {
597
585
  }),
598
586
  ).rejects.toBeInstanceOf(SlotConflictError);
599
587
 
600
- // The original booking must stay intact after a failed reschedule
601
- // attempt — it should never be left marked "rescheduled" with no
602
- // successor.
603
588
  const stillOriginal = await getBookingByUid(original.uid);
604
589
  expect(stillOriginal?.status).toBe("confirmed");
605
590
  });
@@ -1,17 +1,5 @@
1
1
  import { eq } from "drizzle-orm";
2
2
 
3
- /**
4
- * Booking lifecycle — create, reschedule, cancel — wired to providers and
5
- * workflow hooks.
6
- *
7
- * The booking flow:
8
- * 1. Load event type and resolve host (1:1, round-robin).
9
- * 2. Validate requested slot against availability engine.
10
- * 3. Insert the booking row + attendees.
11
- * 4. For each video/calendar provider, create external events and attach
12
- * references to the booking.
13
- * 5. Emit lifecycle event → workflows materialize scheduled reminders.
14
- */
15
3
  import type {
16
4
  Booking,
17
5
  Attendee,
@@ -50,9 +38,7 @@ export interface CreateBookingInput {
50
38
  iCalUid?: string;
51
39
  iCalSequence?: number;
52
40
  orgId?: string;
53
- /** If set, we're rescheduling from this booking uid */
54
41
  fromReschedule?: string;
55
- /** Keep Zoom reschedules uncommitted until the replacement meeting is usable. */
56
42
  requireZoomMeeting?: boolean;
57
43
  }
58
44
 
@@ -107,7 +93,6 @@ export async function createBooking(
107
93
 
108
94
  let usableZoomMeeting = false;
109
95
 
110
- // Create video meeting if location is a video kind
111
96
  if (booking.location && isVideoKind(booking.location.kind)) {
112
97
  const provider = getVideoProvider(
113
98
  videoProviderKindFor(booking.location.kind),
@@ -150,10 +135,8 @@ export async function createBooking(
150
135
  );
151
136
  }
152
137
 
153
- // Write to destination calendar
154
138
  await writeToDestinationCalendars(booking);
155
139
 
156
- // Fire workflow hooks
157
140
  await onBookingCreated(booking);
158
141
 
159
142
  const final = await getBookingByUid(booking.uid);
@@ -175,9 +158,6 @@ export async function rescheduleBooking(input: {
175
158
  if (!eventType) throw new Error("Event type missing");
176
159
  requireZoomMeetingResolution(original, input.zoomMeetingResolved);
177
160
 
178
- // Create the new booking (validated against availability, ignoring the
179
- // original's own slot) before touching the original, so a slot conflict
180
- // never leaves the original marked "rescheduled" with no successor.
181
161
  const attendee = original.attendees[0];
182
162
  const guests = original.attendees.slice(1);
183
163
  const newBooking = await createBooking({
@@ -217,12 +197,10 @@ export async function rescheduleBooking(input: {
217
197
  throw error;
218
198
  }
219
199
 
220
- // Mark old as rescheduled now that the replacement exists.
221
200
  await updateBookingStatus(input.uid, "rescheduled", {
222
201
  reschedulingReason: input.reason,
223
202
  });
224
203
 
225
- // Update external calendar events (PATCH, not delete+create)
226
204
  for (const ref of original.references) {
227
205
  const provider = getCalendarProvider(ref.type);
228
206
  if (provider?.updateEvent && ref.credentialId) {
@@ -1,7 +1,4 @@
1
1
  import { accessFilter } from "@agent-native/core/sharing";
2
- /**
3
- * Data access for bookings + their attendees, references, and notes.
4
- */
5
2
  import { eq, and, gte, lt, or, desc, asc, isNotNull } from "drizzle-orm";
6
3
  import { nanoid } from "nanoid";
7
4
 
@@ -98,16 +95,9 @@ export interface ListBookingsFilter {
98
95
  eventTypeId?: string;
99
96
  status?: BookingStatus | "upcoming" | "past" | "unconfirmed" | "recurring";
100
97
  attendeeEmail?: string;
101
- /** Inclusive start (ISO) */
102
98
  from?: string;
103
- /** Exclusive end (ISO) */
104
99
  to?: string;
105
100
  limit?: number;
106
- /**
107
- * If true, admit any booking the current user owns, has been shared on, or
108
- * matches via org-visibility — in addition to the explicit `hostEmail`
109
- * filter (which still narrows further when set).
110
- */
111
101
  useAccessFilter?: boolean;
112
102
  }
113
103
 
@@ -1,32 +1,16 @@
1
- /**
2
- * Server-side context — the package's view of the world.
3
- *
4
- * Actions and server logic call `getSchedulingContext()` to get handles to
5
- * the DB, provider registry, current user, and configuration. The consumer
6
- * wires this up at app startup via `setSchedulingContext()`.
7
- *
8
- * The context is pinned on `globalThis` under a symbol key so Vite SSR +
9
- * Nitro can safely end up with two module instances (e.g. source via
10
- * workspace linking vs. dist/) and still share state. Same pattern core uses
11
- * for the secrets registry.
12
- */
13
1
  import type { GetDbFn, SchedulingSchema } from "./db-types.js";
14
2
 
15
3
  export interface SchedulingContext {
16
4
  getDb: GetDbFn;
17
5
  schema: SchedulingSchema;
18
- /** How the consumer resolves the current user's email (typically from request ctx). */
19
6
  getCurrentUserEmail: () => string | undefined;
20
- /** How the consumer resolves the current user's org id (if multi-tenant). */
21
7
  getCurrentOrgId?: () => string | undefined;
22
- /** Default brand/timezone/week-start for a user (from settings). */
23
8
  getUserPreferences?: (email: string) => Promise<{
24
9
  timezone?: string;
25
10
  weekStartsOn?: 0 | 1;
26
11
  brandColor?: string;
27
12
  darkBrandColor?: string;
28
13
  }>;
29
- /** Base public URL, e.g. "https://sched.example.com" — used in emails + ICS. */
30
14
  publicBaseUrl?: string;
31
15
  }
32
16
 
@@ -1,16 +1,5 @@
1
- /**
2
- * DB shape contracts.
3
- *
4
- * The package doesn't own a live DB connection — it takes `getDb()` from the
5
- * consumer, which returns a Drizzle client wired to the consumer's schema.
6
- * This file declares the minimum shape the package needs.
7
- */
8
1
  import type * as schemaAll from "../schema/index.js";
9
2
 
10
3
  export type SchedulingSchema = typeof schemaAll;
11
4
 
12
- /**
13
- * GetDb accessor — consumer-provided. Typically returns the Drizzle client
14
- * used everywhere in the template.
15
- */
16
5
  export type GetDbFn = () => any;