@cosmoops/connect-sdk 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/cjs/client/components/availability-form.js +75 -0
  2. package/dist/cjs/client/components/event-type-form.js +82 -0
  3. package/dist/cjs/client/components/user-menu.js +3 -24
  4. package/dist/cjs/client/index.js +21 -3
  5. package/dist/cjs/client/portal-links.js +38 -0
  6. package/dist/cjs/client/use-scheduling.js +67 -8
  7. package/dist/cjs/server/client.js +1 -1
  8. package/dist/cjs/server/handler.js +78 -0
  9. package/dist/cjs/server/http.js +13 -1
  10. package/dist/cjs/server/resources/ai.js +6 -0
  11. package/dist/cjs/server/resources/scheduling.js +62 -0
  12. package/dist/cjs/server/resources/visitor.js +6 -0
  13. package/dist/esm/client/components/availability-form.js +72 -0
  14. package/dist/esm/client/components/event-type-form.js +79 -0
  15. package/dist/esm/client/components/user-menu.js +3 -24
  16. package/dist/esm/client/index.js +12 -1
  17. package/dist/esm/client/portal-links.js +34 -0
  18. package/dist/esm/client/use-scheduling.js +64 -8
  19. package/dist/esm/server/client.js +1 -1
  20. package/dist/esm/server/handler.js +78 -0
  21. package/dist/esm/server/http.js +12 -1
  22. package/dist/esm/server/resources/ai.js +7 -1
  23. package/dist/esm/server/resources/scheduling.js +62 -0
  24. package/dist/esm/server/resources/visitor.js +7 -1
  25. package/dist/types/client/components/availability-form.d.ts +22 -0
  26. package/dist/types/client/components/event-type-form.d.ts +22 -0
  27. package/dist/types/client/index.d.ts +6 -1
  28. package/dist/types/client/portal-links.d.ts +22 -0
  29. package/dist/types/client/use-scheduling.d.ts +49 -1
  30. package/dist/types/server/client.d.ts +1 -1
  31. package/dist/types/server/http.d.ts +35 -0
  32. package/dist/types/server/resources/scheduling.d.ts +67 -1
  33. package/dist/types/types.d.ts +27 -0
  34. package/package.json +1 -1
@@ -31,6 +31,68 @@ export class SchedulingResource {
31
31
  // `undefined` past every status check in between.
32
32
  return result.eventTypes ?? [];
33
33
  }
34
+ /**
35
+ * The working-hours templates an appointment type can point at.
36
+ *
37
+ * Read this before offering to create one - a workspace that already has
38
+ * hours set does not need a second "Working hours" from your integration.
39
+ */
40
+ async listSchedules(workspaceId, options = {}) {
41
+ const result = await request(this.transport, {
42
+ method: "GET",
43
+ path: "/scheduling/schedules",
44
+ query: { workspaceId },
45
+ headers: actingAs(options.asUser),
46
+ });
47
+ return result.schedules ?? [];
48
+ }
49
+ /**
50
+ * Gives a workspace its first working hours.
51
+ *
52
+ * Narrower than what the workspace's own Calendar settings can do - no date
53
+ * overrides, and never owned by one person (`ownerMemberId` stays `null`
54
+ * server-side). Anything beyond that is a Console edit, not a second write
55
+ * path for your integration to maintain.
56
+ */
57
+ createSchedule(input) {
58
+ return request(this.transport, {
59
+ method: "POST",
60
+ path: "/scheduling/schedules",
61
+ json: {
62
+ workspaceId: input.workspaceId,
63
+ name: input.name,
64
+ timezone: input.timezone,
65
+ weeklyHours: input.weeklyHours,
66
+ },
67
+ headers: actingAs(input.asUser),
68
+ });
69
+ }
70
+ /**
71
+ * The first thing a workspace can be booked for.
72
+ *
73
+ * Needs a schedule - create or pick one with `listSchedules`/`createSchedule`
74
+ * first. The slug for a future public booking link is derived from `name`
75
+ * server-side; you cannot choose one.
76
+ */
77
+ createEventType(input) {
78
+ return request(this.transport, {
79
+ method: "POST",
80
+ path: "/scheduling/event-types",
81
+ json: {
82
+ workspaceId: input.workspaceId,
83
+ name: input.name,
84
+ description: input.description ?? null,
85
+ durationMinutes: input.durationMinutes,
86
+ bufferBeforeMinutes: input.bufferBeforeMinutes,
87
+ bufferAfterMinutes: input.bufferAfterMinutes,
88
+ hostMemberId: input.hostMemberId,
89
+ scheduleId: input.scheduleId,
90
+ location: input.location,
91
+ publicBookingEnabled: input.publicBookingEnabled ?? false,
92
+ },
93
+ headers: actingAs(input.asUser),
94
+ });
95
+ }
34
96
  /**
35
97
  * Free times for one appointment type over one window.
36
98
  *
@@ -1,4 +1,4 @@
1
- import { request } from "../http.js";
1
+ import { GENERATION_TIMEOUT_MS, request } from "../http.js";
2
2
  /**
3
3
  * The header a bridge forwards the visitor's own address on.
4
4
  *
@@ -97,6 +97,12 @@ export class VisitorResource {
97
97
  path: "/visitor/chat",
98
98
  json: input,
99
99
  headers: visitorHeaders(options),
100
+ /*
101
+ * Matches the route's own `maxDuration`. This endpoint does not send
102
+ * headers until the model's first token, so the default 20s bound was
103
+ * aborting any turn that opened with a tool call - see `RequestSpec.timeoutMs`.
104
+ */
105
+ timeoutMs: GENERATION_TIMEOUT_MS,
100
106
  raw: true,
101
107
  signal: options.signal,
102
108
  });
@@ -0,0 +1,22 @@
1
+ import type { AvailabilitySchedule } from "../../types.js";
2
+ export interface ConnectAvailabilityFormModalProps {
3
+ isOpen: boolean;
4
+ onOpenChange: (isOpen: boolean) => void;
5
+ /** Called once the schedule is created, before the modal closes. */
6
+ onCreated?: (schedule: AvailabilitySchedule) => void;
7
+ }
8
+ /**
9
+ * Gives a workspace its first working hours, from inside a host application
10
+ * rather than a link-out to Connect.
11
+ *
12
+ * Deliberately narrower than Connect's own Calendar settings form: one
13
+ * interval per day (no split shifts), no date overrides, and the timezone
14
+ * defaults to the browser's own rather than asking. This is a first-run
15
+ * setup step, not a second copy of the Console editor - "Manage in Connect"
16
+ * is still where the rest of what a schedule can do lives.
17
+ *
18
+ * **Not optimistic.** `useCreateAvailabilitySchedule` settles the write
19
+ * against the server before this closes, the same posture every write in
20
+ * this package takes - see `ConnectBookingDialog`.
21
+ */
22
+ export declare function ConnectAvailabilityFormModal({ isOpen, onOpenChange, onCreated, }: Readonly<ConnectAvailabilityFormModalProps>): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import type { BookableEventType } from "../../types.js";
2
+ export interface ConnectEventTypeFormModalProps {
3
+ isOpen: boolean;
4
+ onOpenChange: (isOpen: boolean) => void;
5
+ /** Called once the appointment type is created, before the modal closes. */
6
+ onCreated?: (eventType: BookableEventType) => void;
7
+ }
8
+ /**
9
+ * Creates the first thing a workspace can be booked for, from inside a host
10
+ * application rather than a link-out to Connect.
11
+ *
12
+ * **Needs a schedule to exist first** - the picker reads `useAvailabilitySchedules`
13
+ * and renders "Set up availability first" with nothing to submit if none
14
+ * exists yet. Pair this with `ConnectAvailabilityFormModal` in a setup flow
15
+ * rather than assuming one.
16
+ *
17
+ * **Host is a specific member, never a team.** There is no groups read in
18
+ * this bridge, so a round-robin team host stays a Console-only capability -
19
+ * defaults to whoever is signed in, with an optional picker from the
20
+ * workspace's own roster.
21
+ */
22
+ export declare function ConnectEventTypeFormModal({ isOpen, onOpenChange, onCreated, }: Readonly<ConnectEventTypeFormModalProps>): import("react").JSX.Element;
@@ -32,6 +32,7 @@ export type { ConnectUserButtonProps, ConnectProfileModalProps } from "./compone
32
32
  export { ConnectAccountSessions } from "./components/account-sessions.js";
33
33
  export type { ConnectAccountSessionsProps } from "./components/account-sessions.js";
34
34
  export type { ConnectUserMenuProps } from "./components/user-menu.js";
35
+ export { connectPortalUrl, useConnectPortalUrl } from "./portal-links.js";
35
36
  export { AppShell } from "./components/app-shell.js";
36
37
  export type { AppShellProps } from "./components/app-shell.js";
37
38
  export { ConnectSidebar, ConnectSidebarHeader, ConnectSidebarBody, ConnectSidebarFooter, ConnectSidebarRow, } from "./components/sidebar.js";
@@ -104,5 +105,9 @@ export { useConnectWorkspaces, useConnectWorkspaceMembers } from "./provider.js"
104
105
  export { ConnectBookingCalendar } from "./components/booking-calendar.js";
105
106
  export type { ConnectBookingCalendarProps } from "./components/booking-calendar.js";
106
107
  export { ConnectBookingDialog, ConnectBookingDetail } from "./components/booking-dialogs.js";
107
- export { useBookableEventTypes, useAvailableSlots, useBookings, useBookingActions, type SlotQuery, type BookingsQuery, } from "./use-scheduling.js";
108
+ export { ConnectAvailabilityFormModal } from "./components/availability-form.js";
109
+ export type { ConnectAvailabilityFormModalProps } from "./components/availability-form.js";
110
+ export { ConnectEventTypeFormModal } from "./components/event-type-form.js";
111
+ export type { ConnectEventTypeFormModalProps } from "./components/event-type-form.js";
112
+ export { useBookableEventTypes, useAvailabilitySchedules, useCreateAvailabilitySchedule, useCreateEventType, useAvailableSlots, useBookings, useBookingActions, type SlotQuery, type BookingsQuery, } from "./use-scheduling.js";
108
113
  export { layoutBookings, dayColumns, zonedInstant, type GridWindow, type PositionedBooking, } from "./components/booking-grid.js";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Any Connect portal page, with the context it needs to offer a way back
3
+ * here - `connectPortalUrl(appUrl, clientId, "/profile")`,
4
+ * `connectPortalUrl(appUrl, clientId, "/calendar/settings")`, and so on.
5
+ *
6
+ * Connect answers any of these paths for a signed-in user on the bare URL -
7
+ * these two params only add the "Back to <your app>" banner
8
+ * (`ApplicationReturnBar` on Connect's side). It validates `return_to`
9
+ * against this `client_id`'s registered redirect origins and silently drops
10
+ * the banner if they don't match, so a wrong or stale `appUrl`/`clientId`
11
+ * pairing degrades to what linking there did before rather than erroring.
12
+ *
13
+ * `window.location.href` rather than a configured home URL: the point is to
14
+ * come back to the page they left, and only the browser knows which one that
15
+ * is.
16
+ */
17
+ export declare function connectPortalUrl(appUrl: string, clientId: string, path: string): string;
18
+ /**
19
+ * `connectPortalUrl`, with `appUrl`/`clientId` read from the provider instead
20
+ * of threaded through by every caller.
21
+ */
22
+ export declare function useConnectPortalUrl(path: string): string;
@@ -1,4 +1,4 @@
1
- import type { BookableEventType, Booking, BookingAttendee } from "../types.js";
1
+ import type { AvailabilitySchedule, BookableEventType, Booking, BookingAttendee, WeeklyHours } from "../types.js";
2
2
  /**
3
3
  * The bridge's scheduling surface, as hooks.
4
4
  *
@@ -14,6 +14,54 @@ export declare function useBookableEventTypes(): {
14
14
  isLoading: boolean;
15
15
  error: string | null;
16
16
  };
17
+ /**
18
+ * The working-hours templates an appointment type can point at.
19
+ *
20
+ * Read this before offering a "set up availability" step - a workspace that
21
+ * already has one does not need a second "Working hours" from your UI.
22
+ */
23
+ export declare function useAvailabilitySchedules(): {
24
+ schedules: AvailabilitySchedule[];
25
+ isLoading: boolean;
26
+ error: string | null;
27
+ };
28
+ /**
29
+ * Gives a workspace its first working hours.
30
+ *
31
+ * **Not optimistic** - same posture as `useBookingActions`: this is one of
32
+ * the two writes a host's first-run setup makes, and a modal that closes on
33
+ * a failed create is worse than one that stays open with the reason shown.
34
+ */
35
+ export declare function useCreateAvailabilitySchedule(): BookingActionsState & {
36
+ createSchedule(input: {
37
+ name: string;
38
+ timezone: string;
39
+ weeklyHours: WeeklyHours;
40
+ }): Promise<AvailabilitySchedule | null>;
41
+ };
42
+ /**
43
+ * Creates the first thing a workspace can be booked for.
44
+ *
45
+ * Host is a specific member, never a team - there is no groups read in this
46
+ * bridge, so a round-robin team host stays a Console-only capability
47
+ * reachable by following "Manage in Connect".
48
+ */
49
+ export declare function useCreateEventType(): BookingActionsState & {
50
+ createEventType(input: {
51
+ name: string;
52
+ description?: string | null;
53
+ durationMinutes: number;
54
+ bufferBeforeMinutes?: number;
55
+ bufferAfterMinutes?: number;
56
+ hostMemberId: string;
57
+ scheduleId: string;
58
+ location: {
59
+ kind: "phone" | "address" | "link";
60
+ value?: string | null;
61
+ };
62
+ publicBookingEnabled?: boolean;
63
+ }): Promise<BookableEventType | null>;
64
+ };
17
65
  export interface SlotQuery {
18
66
  eventTypeId: string;
19
67
  from: Date;
@@ -138,4 +138,4 @@ export declare class ConnectClient {
138
138
  constructor(options: ConnectClientOptions);
139
139
  }
140
140
  /** Kept in step with `package.json` by `sdk.test.ts`. */
141
- export declare const SDK_VERSION = "0.37.0";
141
+ export declare const SDK_VERSION = "0.38.0";
@@ -1,4 +1,15 @@
1
1
  export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
2
+ /**
3
+ * How long a *generating* endpoint may take to send its headers.
4
+ *
5
+ * One number, named once, and it is not a guess: it is what
6
+ * `POST /visitor/chat` and `POST /ai/chat` declare as their `maxDuration` on
7
+ * the far side. A client bound shorter than the route's own ceiling cannot be
8
+ * right - it can only abort work Connect is still allowed to be doing - and
9
+ * the two numbers drifting apart is exactly how a 20s client came to be
10
+ * fronting a 60s route.
11
+ */
12
+ export declare const GENERATION_TIMEOUT_MS = 60000;
2
13
  export interface RequestSpec {
3
14
  /**
4
15
  * `PUT` and `DELETE` were added for the store resources. Both are idempotent
@@ -24,6 +35,30 @@ export interface RequestSpec {
24
35
  * Also stops `timeoutMs` from applying to the *body*: see `request`.
25
36
  */
26
37
  raw?: boolean;
38
+ /**
39
+ * Override the client's `timeoutMs` for this one call.
40
+ *
41
+ * The transport-wide default bounds how long a request may take to *reach*
42
+ * Connect, and 20 seconds is generous for every endpoint that answers from a
43
+ * read. It is the wrong bound for a **generating** endpoint, because of how
44
+ * those are built on the far side: `POST /visitor/chat` holds its response
45
+ * open until the first delta arrives, deliberately, so that a refusal is
46
+ * still an ordinary `{error}` envelope with a status rather than an event
47
+ * inside a stream nobody can change the status of. So "time to headers"
48
+ * there is time to the model's first token - after up to four tool-calling
49
+ * steps - and that route declares `maxDuration = 60` precisely because it
50
+ * can take that long.
51
+ *
52
+ * With one 20s number for everything, the client aborted at 20s, the abort
53
+ * read as `network_error`, and the bridge returned **502 after exactly
54
+ * 20.0s** on any conversation whose first token took longer - which is every
55
+ * conversation that starts with a tool call. It is the only route on the
56
+ * platform that exceeds the default; every other one declares 15 or 20.
57
+ *
58
+ * Set it where the endpoint's own `maxDuration` is larger, and nowhere else.
59
+ * It does not bound the stream once it has started - see the timer below.
60
+ */
61
+ timeoutMs?: number;
27
62
  signal?: AbortSignal;
28
63
  /**
29
64
  * Force this request into the retry path even though it is a `POST`.
@@ -1,5 +1,5 @@
1
1
  import { type TransportOptions } from "../http.js";
2
- import type { BookableEventType, Booking, RescheduledBooking, BookingAttendee, BookingSlots, BookingStatus, ListBookingsPage } from "../../types.js";
2
+ import type { AvailabilitySchedule, BookableEventType, Booking, RescheduledBooking, BookingAttendee, BookingSlots, BookingStatus, ListBookingsPage, WeeklyHours } from "../../types.js";
3
3
  /**
4
4
  * Present on every method here.
5
5
  *
@@ -56,6 +56,48 @@ export interface ListBookingsInput extends ActingAsOption {
56
56
  cursor?: string;
57
57
  limit?: number;
58
58
  }
59
+ export interface ListSchedulesInput extends ActingAsOption {
60
+ workspaceId: string;
61
+ }
62
+ /**
63
+ * What `createSchedule` takes - deliberately narrower than Connect's own
64
+ * Calendar settings form: no date overrides, and never owned by one person.
65
+ * Anything beyond this is a Console edit, not a second write path to
66
+ * maintain.
67
+ */
68
+ export interface CreateScheduleInput extends ActingAsOption {
69
+ workspaceId: string;
70
+ name: string;
71
+ /** Validated against the IANA database server-side, e.g. `"Asia/Kolkata"`. */
72
+ timezone: string;
73
+ weeklyHours: WeeklyHours;
74
+ }
75
+ /**
76
+ * What `createEventType` takes.
77
+ *
78
+ * Host is a specific member, never a team - there is no groups read in this
79
+ * API, so a round-robin team host stays a Console-only capability, reachable
80
+ * by following "Manage in Connect".
81
+ */
82
+ export interface CreateEventTypeInput extends ActingAsOption {
83
+ workspaceId: string;
84
+ name: string;
85
+ description?: string | null;
86
+ /** 5 to 480 minutes. */
87
+ durationMinutes: number;
88
+ /** Dead time reserved either side of the meeting. Both default to 5. */
89
+ bufferBeforeMinutes?: number;
90
+ bufferAfterMinutes?: number;
91
+ /** A `ConnectWorkspaceMember.memberId` - see `Booking.hostMemberIds`. */
92
+ hostMemberId: string;
93
+ scheduleId: string;
94
+ location: {
95
+ kind: "phone" | "address" | "link";
96
+ value?: string | null;
97
+ };
98
+ /** Off by default - most appointment types are booked by your integration or a member, not the public. */
99
+ publicBookingEnabled?: boolean;
100
+ }
59
101
  export interface CreateBookingInput extends ActingAsOption {
60
102
  workspaceId: string;
61
103
  eventTypeId: string;
@@ -88,6 +130,30 @@ export declare class SchedulingResource {
88
130
  constructor(transport: TransportOptions);
89
131
  /** What this workspace offers as bookable. Active appointment types only. */
90
132
  listEventTypes(workspaceId: string, options?: ActingAsOption): Promise<BookableEventType[]>;
133
+ /**
134
+ * The working-hours templates an appointment type can point at.
135
+ *
136
+ * Read this before offering to create one - a workspace that already has
137
+ * hours set does not need a second "Working hours" from your integration.
138
+ */
139
+ listSchedules(workspaceId: string, options?: ActingAsOption): Promise<AvailabilitySchedule[]>;
140
+ /**
141
+ * Gives a workspace its first working hours.
142
+ *
143
+ * Narrower than what the workspace's own Calendar settings can do - no date
144
+ * overrides, and never owned by one person (`ownerMemberId` stays `null`
145
+ * server-side). Anything beyond that is a Console edit, not a second write
146
+ * path for your integration to maintain.
147
+ */
148
+ createSchedule(input: CreateScheduleInput): Promise<AvailabilitySchedule>;
149
+ /**
150
+ * The first thing a workspace can be booked for.
151
+ *
152
+ * Needs a schedule - create or pick one with `listSchedules`/`createSchedule`
153
+ * first. The slug for a future public booking link is derived from `name`
154
+ * server-side; you cannot choose one.
155
+ */
156
+ createEventType(input: CreateEventTypeInput): Promise<BookableEventType>;
91
157
  /**
92
158
  * Free times for one appointment type over one window.
93
159
  *
@@ -2003,6 +2003,33 @@ export interface ListBookingsPage {
2003
2003
  hasMore: boolean;
2004
2004
  totalCount: number;
2005
2005
  }
2006
+ /**
2007
+ * One interval within a day, in minutes since midnight - `540` is 9am.
2008
+ */
2009
+ export interface WeeklyInterval {
2010
+ startMinute: number;
2011
+ endMinute: number;
2012
+ }
2013
+ /**
2014
+ * A week of working hours, one entry per weekday - `0` is Sunday. An empty
2015
+ * array means closed that day; every key is required, so "closed on Sunday"
2016
+ * is an array the caller had to mean rather than a key they forgot.
2017
+ */
2018
+ export interface WeeklyHours {
2019
+ 0: WeeklyInterval[];
2020
+ 1: WeeklyInterval[];
2021
+ 2: WeeklyInterval[];
2022
+ 3: WeeklyInterval[];
2023
+ 4: WeeklyInterval[];
2024
+ 5: WeeklyInterval[];
2025
+ 6: WeeklyInterval[];
2026
+ }
2027
+ /** A working-hours template an appointment type points at. */
2028
+ export interface AvailabilitySchedule {
2029
+ id: string;
2030
+ name: string;
2031
+ timezone: string;
2032
+ }
2006
2033
  /**
2007
2034
  * A phone or email on a contact.
2008
2035
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmoops/connect-sdk",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "Official server-side SDK for the CosmoOps Connect platform API - Login with Connect, entitlements, billing and metering.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "commonjs",