@cosmoops/connect-sdk 0.37.0 → 0.40.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 (47) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/cjs/client/components/availability-form.js +103 -0
  3. package/dist/cjs/client/components/create-workspace-form.js +66 -0
  4. package/dist/cjs/client/components/event-type-form.js +156 -0
  5. package/dist/cjs/client/components/user-menu.js +3 -24
  6. package/dist/cjs/client/components/workspace-switcher.js +42 -9
  7. package/dist/cjs/client/index.js +31 -3
  8. package/dist/cjs/client/portal-links.js +38 -0
  9. package/dist/cjs/client/use-scheduling.js +104 -8
  10. package/dist/cjs/client/use-workspaces.js +41 -0
  11. package/dist/cjs/server/client.js +1 -1
  12. package/dist/cjs/server/handler.js +181 -2
  13. package/dist/cjs/server/http.js +13 -1
  14. package/dist/cjs/server/resources/ai.js +6 -0
  15. package/dist/cjs/server/resources/scheduling.js +129 -0
  16. package/dist/cjs/server/resources/visitor.js +6 -0
  17. package/dist/cjs/server/resources/workspaces.js +30 -11
  18. package/dist/esm/client/components/availability-form.js +100 -0
  19. package/dist/esm/client/components/create-workspace-form.js +63 -0
  20. package/dist/esm/client/components/event-type-form.js +153 -0
  21. package/dist/esm/client/components/user-menu.js +3 -24
  22. package/dist/esm/client/components/workspace-switcher.js +42 -9
  23. package/dist/esm/client/index.js +17 -1
  24. package/dist/esm/client/portal-links.js +34 -0
  25. package/dist/esm/client/use-scheduling.js +98 -8
  26. package/dist/esm/client/use-workspaces.js +38 -0
  27. package/dist/esm/server/client.js +1 -1
  28. package/dist/esm/server/handler.js +181 -2
  29. package/dist/esm/server/http.js +12 -1
  30. package/dist/esm/server/resources/ai.js +7 -1
  31. package/dist/esm/server/resources/scheduling.js +129 -0
  32. package/dist/esm/server/resources/visitor.js +7 -1
  33. package/dist/esm/server/resources/workspaces.js +30 -11
  34. package/dist/types/client/components/availability-form.d.ts +33 -0
  35. package/dist/types/client/components/create-workspace-form.d.ts +32 -0
  36. package/dist/types/client/components/event-type-form.d.ts +44 -0
  37. package/dist/types/client/components/workspace-switcher.d.ts +9 -9
  38. package/dist/types/client/index.d.ts +10 -1
  39. package/dist/types/client/portal-links.d.ts +22 -0
  40. package/dist/types/client/use-scheduling.d.ts +93 -1
  41. package/dist/types/client/use-workspaces.d.ts +27 -0
  42. package/dist/types/server/client.d.ts +1 -1
  43. package/dist/types/server/http.d.ts +35 -0
  44. package/dist/types/server/resources/scheduling.d.ts +131 -1
  45. package/dist/types/server/resources/workspaces.d.ts +28 -0
  46. package/dist/types/types.d.ts +60 -0
  47. package/package.json +1 -1
@@ -31,6 +31,135 @@ 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
+ * Answers the richer *manageable* shape, not `BookableEventType` - you just
78
+ * created this row and are about to manage it, not book against it.
79
+ */
80
+ createEventType(input) {
81
+ return request(this.transport, {
82
+ method: "POST",
83
+ path: "/scheduling/event-types",
84
+ json: {
85
+ workspaceId: input.workspaceId,
86
+ name: input.name,
87
+ description: input.description ?? null,
88
+ durationMinutes: input.durationMinutes,
89
+ bufferBeforeMinutes: input.bufferBeforeMinutes,
90
+ bufferAfterMinutes: input.bufferAfterMinutes,
91
+ hostMemberId: input.hostMemberId,
92
+ scheduleId: input.scheduleId,
93
+ location: input.location,
94
+ publicBookingEnabled: input.publicBookingEnabled ?? false,
95
+ },
96
+ headers: actingAs(input.asUser),
97
+ });
98
+ }
99
+ /**
100
+ * The richer read `createEventType`/`updateEventType`'s edit mode needs -
101
+ * everything `listEventTypes`'s booking catalogue deliberately withholds,
102
+ * because this is the opposite audience: a member managing their own
103
+ * calendar, not a widget rendering someone else's. Includes inactive rows,
104
+ * since an edit screen is exactly where one gets reactivated.
105
+ */
106
+ async listManageableEventTypes(workspaceId, options = {}) {
107
+ const result = await request(this.transport, {
108
+ method: "GET",
109
+ path: "/scheduling/event-types/manage",
110
+ query: { workspaceId },
111
+ headers: actingAs(options.asUser),
112
+ });
113
+ return result.eventTypes ?? [];
114
+ }
115
+ /**
116
+ * Edits an existing availability schedule.
117
+ *
118
+ * Narrower than what the workspace's own Calendar settings can do, the
119
+ * same way `createSchedule` is: `ownerMemberId` and date overrides stay
120
+ * untouched, since this surface never sets either.
121
+ */
122
+ updateSchedule(input) {
123
+ return request(this.transport, {
124
+ method: "PUT",
125
+ path: `/scheduling/schedules/${encodeURIComponent(input.scheduleId)}`,
126
+ json: {
127
+ workspaceId: input.workspaceId,
128
+ name: input.name,
129
+ timezone: input.timezone,
130
+ weeklyHours: input.weeklyHours,
131
+ },
132
+ headers: actingAs(input.asUser),
133
+ });
134
+ }
135
+ /**
136
+ * Edits an existing appointment type.
137
+ *
138
+ * `hostMemberId` omitted leaves the host untouched, including a *group*
139
+ * host this surface cannot represent - so an edit that says nothing about
140
+ * the host can never accidentally overwrite a team assignment made in
141
+ * Connect.
142
+ */
143
+ updateEventType(input) {
144
+ return request(this.transport, {
145
+ method: "PUT",
146
+ path: `/scheduling/event-types/${encodeURIComponent(input.eventTypeId)}`,
147
+ json: {
148
+ workspaceId: input.workspaceId,
149
+ name: input.name,
150
+ description: input.description,
151
+ durationMinutes: input.durationMinutes,
152
+ bufferBeforeMinutes: input.bufferBeforeMinutes,
153
+ bufferAfterMinutes: input.bufferAfterMinutes,
154
+ hostMemberId: input.hostMemberId,
155
+ scheduleId: input.scheduleId,
156
+ location: input.location,
157
+ publicBookingEnabled: input.publicBookingEnabled,
158
+ active: input.active,
159
+ },
160
+ headers: actingAs(input.asUser),
161
+ });
162
+ }
34
163
  /**
35
164
  * Free times for one appointment type over one window.
36
165
  *
@@ -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
  });
@@ -1,16 +1,5 @@
1
1
  import { actingAs } from "./acting-as.js";
2
2
  import { request } from "../http.js";
3
- /**
4
- * Which workspaces the signed-in user belongs to, moving between them, who
5
- * else is on the team, and inviting or granting access to your application.
6
- *
7
- * **Every call here needs `asUser`** - the signed-in user's opaque
8
- * `sessionToken`. There is no application-wide form of any of these: they take
9
- * no `userId` and no `workspaceId`, and resolve both from the token. That is
10
- * what makes the whole module safe to reach from a browser through
11
- * `createConnectHandler`, and it is why a partner cannot enumerate another
12
- * tenant's team with their own API key.
13
- */
14
3
  export class WorkspacesResource {
15
4
  transport;
16
5
  constructor(transport) {
@@ -31,6 +20,36 @@ export class WorkspacesResource {
31
20
  });
32
21
  return result.workspaces;
33
22
  }
23
+ /**
24
+ * Opens another workspace under the tenant the signed-in user already
25
+ * owns - a branch office, a second business unit.
26
+ *
27
+ * Every guard `CreateWorkspaceUseCase` enforces still applies: only the
28
+ * tenant's owner may call this, `type: "business"` still needs a non-free
29
+ * email domain, and the tenant's plan still decides whether it may hold
30
+ * another workspace at all - a `PreconditionError` surfaces as a thrown
31
+ * `ConnectError` with a message written to be shown ("Your current plan
32
+ * covers a single workspace...", "You've used all 3 of the workspaces
33
+ * your plans include..."). There is no `tenantId` parameter: the caller
34
+ * names no tenant, same as every other method on this resource names no
35
+ * workspace.
36
+ *
37
+ * `isActive`/`subscribed` on the result are always `false` - this does not
38
+ * switch the session, and the new workspace has no subscription yet. Chain
39
+ * `switch({workspaceId: result.workspaceId})` to move into it, but only
40
+ * when `result.inAudience` - a workspace outside this application's
41
+ * audience is refused by `switch` the same way `selectable()` in
42
+ * `<ConnectWorkspaceSwitcher>` already treats it.
43
+ */
44
+ async create(input, options) {
45
+ const result = await request(this.transport, {
46
+ method: "POST",
47
+ path: "/workspaces",
48
+ headers: actingAs(options.asUser),
49
+ json: input,
50
+ });
51
+ return result.workspace;
52
+ }
34
53
  /**
35
54
  * Moves this session to another workspace, returning a **new session
36
55
  * token**. The one you passed is revoked.
@@ -0,0 +1,33 @@
1
+ import type { AvailabilitySchedule } from "../../types.js";
2
+ export interface ConnectAvailabilityFormModalProps {
3
+ isOpen: boolean;
4
+ onOpenChange: (isOpen: boolean) => void;
5
+ /**
6
+ * `null` (or omitted) creates a new schedule. A row id from
7
+ * `useAvailabilitySchedules` edits that one instead - name and hours
8
+ * prefill from it.
9
+ */
10
+ scheduleId?: string | null;
11
+ /** Called once the schedule is created or saved, before the modal closes. */
12
+ onSaved?: (schedule: AvailabilitySchedule) => void;
13
+ }
14
+ /**
15
+ * Creates or edits a workspace's working hours, from inside a host
16
+ * application rather than a link-out to Connect.
17
+ *
18
+ * Deliberately narrower than Connect's own Calendar settings form: one
19
+ * interval per day (no split shifts), no date overrides, and the timezone is
20
+ * set once at creation (from the browser's own) and shown but not editable
21
+ * here afterwards. This is a first-party setup-and-edit surface, not a
22
+ * second copy of the Console editor - "Manage in Connect" is still where the
23
+ * rest of what a schedule can do lives.
24
+ *
25
+ * **Not optimistic.** The write settles against the server before this
26
+ * closes, the same posture every write in this package takes - see
27
+ * `ConnectBookingDialog`.
28
+ *
29
+ * This outer component only decides whether the row to edit has loaded yet;
30
+ * the form itself is `ScheduleFields` below, mounted with
31
+ * `key={editing?.id}` - see that component's own doc comment for why.
32
+ */
33
+ export declare function ConnectAvailabilityFormModal({ isOpen, onOpenChange, scheduleId, onSaved, }: Readonly<ConnectAvailabilityFormModalProps>): import("react").JSX.Element;
@@ -0,0 +1,32 @@
1
+ import type { UserWorkspace } from "../../types.js";
2
+ export interface ConnectCreateWorkspaceModalProps {
3
+ isOpen: boolean;
4
+ onOpenChange: (isOpen: boolean) => void;
5
+ /** Called once the workspace is created, before the modal closes. */
6
+ onCreated?: (workspace: UserWorkspace) => void;
7
+ }
8
+ /**
9
+ * Opens another workspace under the signed-in user's own tenant - a branch
10
+ * office, a second business unit - from inside a host application rather
11
+ * than a link-out to Connect.
12
+ *
13
+ * **Only the tenant's owner can use this successfully.** `CreateWorkspaceUseCase`
14
+ * refuses anyone who merely belongs to a colleague's tenant, with a message
15
+ * naming that - someone who wants a workspace of their own uses a personal
16
+ * account instead.
17
+ *
18
+ * **The tenant's plan decides how many workspaces it may hold, and this does
19
+ * not pre-check it.** There is no capacity read to show ahead of time - the
20
+ * same posture Connect's own "Create workspace" button takes - so a refusal
21
+ * surfaces here exactly as the server wrote it ("Your current plan covers a
22
+ * single workspace - subscribe to a plan that includes additional workspaces
23
+ * to open another.", or "You've used all 3 of the workspaces your plans
24
+ * include. Upgrade a plan or delete a workspace to open another.").
25
+ *
26
+ * **Does not switch the session to the new workspace.** Creating one never
27
+ * does, on Connect's own screen either - see `useCreateWorkspace`'s doc
28
+ * comment for how to chain a switch once you have the result, and guard that
29
+ * chain on `inAudience` the same way `<ConnectWorkspaceSwitcher>` already
30
+ * does for every other row.
31
+ */
32
+ export declare function ConnectCreateWorkspaceModal({ isOpen, onOpenChange, onCreated, }: Readonly<ConnectCreateWorkspaceModalProps>): import("react").JSX.Element;
@@ -0,0 +1,44 @@
1
+ import type { ManageableEventType } from "../../types.js";
2
+ export interface ConnectEventTypeFormModalProps {
3
+ isOpen: boolean;
4
+ onOpenChange: (isOpen: boolean) => void;
5
+ /**
6
+ * `null` (or omitted) creates a new appointment type. A row id from
7
+ * `useManageableEventTypes` edits that one instead - name, duration,
8
+ * buffers, host, schedule, location and `publicBookingEnabled` all prefill
9
+ * from it.
10
+ */
11
+ eventTypeId?: string | null;
12
+ /** Called once the appointment type is created or saved, before the modal closes. */
13
+ onSaved?: (eventType: ManageableEventType) => void;
14
+ }
15
+ /**
16
+ * Creates or edits an appointment type, from inside a host application
17
+ * rather than a link-out to Connect.
18
+ *
19
+ * **Needs a schedule to exist first** - the picker reads `useAvailabilitySchedules`
20
+ * and renders "Set up availability first" with nothing to submit if none
21
+ * exists yet. Pair this with `ConnectAvailabilityFormModal` in a setup flow
22
+ * rather than assuming one.
23
+ *
24
+ * **That gate waits for the read, and the order matters.** Both bridge reads
25
+ * answer `[]` while they are in flight, so testing `schedules.length === 0`
26
+ * first showed "Set up availability first" to everybody who opened this -
27
+ * including, for a second or two, somebody pressing Edit on an appointment
28
+ * type that provably *has* a schedule. A load state wearing an empty state's
29
+ * words is worse than a spinner: it reads as a verdict, and on a slow
30
+ * connection it is the only thing the modal ever says. A failed read is named
31
+ * as a failure for the same reason - it is not the same fact as "none exist".
32
+ *
33
+ * **Host is a specific member, never a team.** There is no groups read in
34
+ * this bridge, so a round-robin team host stays a Console-only capability -
35
+ * defaults to whoever is signed in on create, with an optional picker from
36
+ * the workspace's own roster. **Editing a group-hosted row is refused
37
+ * inline** - the modal shows a notice instead of a form, because this
38
+ * surface cannot represent (and so cannot safely resend) a team host.
39
+ *
40
+ * This outer component only decides *which* message or form to show; the
41
+ * form itself is `EventTypeFields` below, mounted with `key={editing?.id}` -
42
+ * see that component's own doc comment for why.
43
+ */
44
+ export declare function ConnectEventTypeFormModal({ isOpen, onOpenChange, eventTypeId, onSaved, }: Readonly<ConnectEventTypeFormModalProps>): import("react").JSX.Element;
@@ -21,12 +21,12 @@ export interface ConnectWorkspaceSwitcherProps {
21
21
  * every other host: an account with one workspace sees nothing, because a
22
22
  * switcher offering one option teaches it nothing. Pass `true` on an
23
23
  * application that wants a single-workspace account to be able to
24
- * discover - and start - creating a second one without leaving its own
25
- * chrome. There is deliberately no `workspaces.create()` on the SDK:
26
- * creating a workspace is Connect's job, tied to KYC/KYB and a billing
27
- * profile, not something an API key should be able to trigger - so turning
28
- * this on also adds a "Create workspace" row that opens Connect, rather
29
- * than pretending the switcher can do it itself.
24
+ * discover - and open - a second one without leaving its own chrome. Turning
25
+ * this on adds a "Create workspace" row that opens
26
+ * `<ConnectCreateWorkspaceModal>` inline: name, individual-or-business, and
27
+ * the tenant's own plan decides whether another workspace is allowed at
28
+ * all - the same guards Connect's own "Create workspace" button runs
29
+ * through, surfaced as the server wrote them rather than pre-checked here.
30
30
  */
31
31
  alwaysShow?: boolean;
32
32
  }
@@ -44,9 +44,9 @@ export interface ConnectWorkspaceSwitcherProps {
44
44
  * a workspace is *created*, so hiding it at one workspace would guarantee
45
45
  * nobody ever reached two. `alwaysShow` is the escape hatch for a partner
46
46
  * application that wants that same discoverability without becoming Connect:
47
- * it keeps the dropdown open below two workspaces and adds a row that sends
48
- * the member to Connect to actually create one, since there is nothing here
49
- * that can.
47
+ * it keeps the dropdown open below two workspaces and adds a row that opens
48
+ * `<ConnectCreateWorkspaceModal>` inline, auto-switching into the result when
49
+ * that is possible - see `handleCreated` below.
50
50
  *
51
51
  * **Authorization is the data, not a prop.** The list comes from the caller's
52
52
  * own session (`GET /workspaces` takes no user id), so a workspace the user
@@ -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";
@@ -101,8 +102,16 @@ export type { PlanAction, PlanTier, ComparablePlan } from "./components/plan-pri
101
102
  export { ConnectWorkspaceSwitcher } from "./components/workspace-switcher.js";
102
103
  export type { ConnectWorkspaceSwitcherProps } from "./components/workspace-switcher.js";
103
104
  export { useConnectWorkspaces, useConnectWorkspaceMembers } from "./provider.js";
105
+ export { ConnectCreateWorkspaceModal } from "./components/create-workspace-form.js";
106
+ export type { ConnectCreateWorkspaceModalProps } from "./components/create-workspace-form.js";
107
+ export { useCreateWorkspace } from "./use-workspaces.js";
108
+ export type { WorkspaceActionsState } from "./use-workspaces.js";
104
109
  export { ConnectBookingCalendar } from "./components/booking-calendar.js";
105
110
  export type { ConnectBookingCalendarProps } from "./components/booking-calendar.js";
106
111
  export { ConnectBookingDialog, ConnectBookingDetail } from "./components/booking-dialogs.js";
107
- export { useBookableEventTypes, useAvailableSlots, useBookings, useBookingActions, type SlotQuery, type BookingsQuery, } from "./use-scheduling.js";
112
+ export { ConnectAvailabilityFormModal } from "./components/availability-form.js";
113
+ export type { ConnectAvailabilityFormModalProps } from "./components/availability-form.js";
114
+ export { ConnectEventTypeFormModal } from "./components/event-type-form.js";
115
+ export type { ConnectEventTypeFormModalProps } from "./components/event-type-form.js";
116
+ export { useBookableEventTypes, useAvailabilitySchedules, useCreateAvailabilitySchedule, useUpdateAvailabilitySchedule, useManageableEventTypes, useCreateEventType, useUpdateEventType, useAvailableSlots, useBookings, useBookingActions, type SlotQuery, type BookingsQuery, } from "./use-scheduling.js";
108
117
  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, ManageableEventType, WeeklyHours } from "../types.js";
2
2
  /**
3
3
  * The bridge's scheduling surface, as hooks.
4
4
  *
@@ -14,6 +14,98 @@ 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
+ * The richer read `ConnectEventTypeFormModal`'s edit mode needs - everything
30
+ * `useBookableEventTypes`'s booking catalogue deliberately withholds. See
31
+ * the bridge route's own doc comment for why this is a separate read rather
32
+ * than a wider response on that one. Includes inactive rows.
33
+ */
34
+ export declare function useManageableEventTypes(): {
35
+ eventTypes: ManageableEventType[];
36
+ isLoading: boolean;
37
+ error: string | null;
38
+ refetch: () => void;
39
+ };
40
+ /**
41
+ * Gives a workspace its first working hours.
42
+ *
43
+ * **Not optimistic** - same posture as `useBookingActions`: this is one of
44
+ * the two writes a host's first-run setup makes, and a modal that closes on
45
+ * a failed create is worse than one that stays open with the reason shown.
46
+ */
47
+ export declare function useCreateAvailabilitySchedule(): BookingActionsState & {
48
+ createSchedule(input: {
49
+ name: string;
50
+ timezone: string;
51
+ weeklyHours: WeeklyHours;
52
+ }): Promise<AvailabilitySchedule | null>;
53
+ };
54
+ /** Edits an existing availability schedule. Every field optional - send only what changed. */
55
+ export declare function useUpdateAvailabilitySchedule(): BookingActionsState & {
56
+ updateSchedule(input: {
57
+ scheduleId: string;
58
+ name?: string;
59
+ timezone?: string;
60
+ weeklyHours?: WeeklyHours;
61
+ }): Promise<AvailabilitySchedule | null>;
62
+ };
63
+ /**
64
+ * Creates the first thing a workspace can be booked for.
65
+ *
66
+ * Host is a specific member, never a team - there is no groups read in this
67
+ * bridge, so a round-robin team host stays a Console-only capability
68
+ * reachable by following "Manage in Connect".
69
+ */
70
+ export declare function useCreateEventType(): BookingActionsState & {
71
+ createEventType(input: {
72
+ name: string;
73
+ description?: string | null;
74
+ durationMinutes: number;
75
+ bufferBeforeMinutes?: number;
76
+ bufferAfterMinutes?: number;
77
+ hostMemberId: string;
78
+ scheduleId: string;
79
+ location: {
80
+ kind: "phone" | "address" | "link";
81
+ value?: string | null;
82
+ };
83
+ publicBookingEnabled?: boolean;
84
+ }): Promise<ManageableEventType | null>;
85
+ };
86
+ /**
87
+ * Edits an existing appointment type. Every field optional - send only what
88
+ * changed. `hostMemberId` omitted leaves the host untouched, including a
89
+ * *group* host this surface cannot represent.
90
+ */
91
+ export declare function useUpdateEventType(): BookingActionsState & {
92
+ updateEventType(input: {
93
+ eventTypeId: string;
94
+ name?: string;
95
+ description?: string | null;
96
+ durationMinutes?: number;
97
+ bufferBeforeMinutes?: number;
98
+ bufferAfterMinutes?: number;
99
+ hostMemberId?: string;
100
+ scheduleId?: string;
101
+ location?: {
102
+ kind: "phone" | "address" | "link";
103
+ value?: string | null;
104
+ };
105
+ publicBookingEnabled?: boolean;
106
+ active?: boolean;
107
+ }): Promise<ManageableEventType | null>;
108
+ };
17
109
  export interface SlotQuery {
18
110
  eventTypeId: string;
19
111
  from: Date;
@@ -0,0 +1,27 @@
1
+ import type { UserWorkspace } from "../types.js";
2
+ export interface WorkspaceActionsState {
3
+ isPending: boolean;
4
+ /** The last refusal, written to be shown to the person who clicked - see `CreateWorkspaceUseCase`. */
5
+ error: string | null;
6
+ clearError(): void;
7
+ }
8
+ /**
9
+ * Opens another workspace under the tenant the signed-in user already owns.
10
+ *
11
+ * **Not optimistic**, same posture as every write in `use-scheduling.ts`:
12
+ * whether the tenant's plan still has room for another workspace is a
13
+ * question only the server can answer, and a modal that closes before that
14
+ * answer comes back is the lie a two-phase write exists to avoid.
15
+ *
16
+ * The result is a `UserWorkspace` row with `isActive`/`subscribed` both
17
+ * `false` - creating does not switch the session to it, and the workspace has
18
+ * no subscription yet. Pair with `<ConnectWorkspaceSwitcher>`'s own
19
+ * `mutateResource("/workspaces/switch", ...)` call to move into it, guarded
20
+ * on `inAudience` the same way that component's `selectable()` already is.
21
+ */
22
+ export declare function useCreateWorkspace(): WorkspaceActionsState & {
23
+ createWorkspace(input: {
24
+ name: string;
25
+ type: "individual" | "business";
26
+ }): Promise<UserWorkspace | null>;
27
+ };
@@ -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.40.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`.