@cosmoops/connect-sdk 0.38.0 → 0.41.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 (44) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/dist/cjs/client/components/availability-form.js +52 -24
  3. package/dist/cjs/client/components/call-button.js +398 -0
  4. package/dist/cjs/client/components/create-workspace-form.js +66 -0
  5. package/dist/cjs/client/components/event-type-form.js +99 -25
  6. package/dist/cjs/client/components/workspace-switcher.js +42 -9
  7. package/dist/cjs/client/index.js +17 -2
  8. package/dist/cjs/client/portal-links.js +1 -1
  9. package/dist/cjs/client/use-scheduling.js +37 -0
  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 +176 -2
  13. package/dist/cjs/server/resources/calls.js +58 -0
  14. package/dist/cjs/server/resources/scheduling.js +67 -0
  15. package/dist/cjs/server/resources/workspaces.js +30 -11
  16. package/dist/esm/client/components/availability-form.js +53 -25
  17. package/dist/esm/client/components/call-button.js +358 -0
  18. package/dist/esm/client/components/create-workspace-form.js +63 -0
  19. package/dist/esm/client/components/event-type-form.js +100 -26
  20. package/dist/esm/client/components/workspace-switcher.js +42 -9
  21. package/dist/esm/client/index.js +8 -2
  22. package/dist/esm/client/portal-links.js +1 -1
  23. package/dist/esm/client/use-scheduling.js +34 -0
  24. package/dist/esm/client/use-workspaces.js +38 -0
  25. package/dist/esm/server/client.js +1 -1
  26. package/dist/esm/server/handler.js +176 -2
  27. package/dist/esm/server/resources/calls.js +58 -0
  28. package/dist/esm/server/resources/scheduling.js +67 -0
  29. package/dist/esm/server/resources/workspaces.js +30 -11
  30. package/dist/types/client/components/availability-form.d.ts +23 -12
  31. package/dist/types/client/components/call-button.d.ts +132 -0
  32. package/dist/types/client/components/create-workspace-form.d.ts +32 -0
  33. package/dist/types/client/components/event-type-form.d.ts +30 -8
  34. package/dist/types/client/components/workspace-switcher.d.ts +9 -9
  35. package/dist/types/client/index.d.ts +7 -1
  36. package/dist/types/client/portal-links.d.ts +1 -1
  37. package/dist/types/client/use-scheduling.d.ts +46 -2
  38. package/dist/types/client/use-workspaces.d.ts +27 -0
  39. package/dist/types/server/client.d.ts +1 -1
  40. package/dist/types/server/resources/calls.d.ts +32 -1
  41. package/dist/types/server/resources/scheduling.d.ts +66 -2
  42. package/dist/types/server/resources/workspaces.d.ts +28 -0
  43. package/dist/types/types.d.ts +143 -1
  44. package/package.json +4 -1
@@ -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.
@@ -2,21 +2,32 @@ import type { AvailabilitySchedule } from "../../types.js";
2
2
  export interface ConnectAvailabilityFormModalProps {
3
3
  isOpen: boolean;
4
4
  onOpenChange: (isOpen: boolean) => void;
5
- /** Called once the schedule is created, before the modal closes. */
6
- onCreated?: (schedule: AvailabilitySchedule) => 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;
7
13
  }
8
14
  /**
9
- * Gives a workspace its first working hours, from inside a host application
10
- * rather than a link-out to Connect.
15
+ * Creates or edits a workspace's working hours, from inside a host
16
+ * application rather than a link-out to Connect.
11
17
  *
12
18
  * 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.
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.
17
24
  *
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`.
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.
21
32
  */
22
- export declare function ConnectAvailabilityFormModal({ isOpen, onOpenChange, onCreated, }: Readonly<ConnectAvailabilityFormModalProps>): import("react").JSX.Element;
33
+ export declare function ConnectAvailabilityFormModal({ isOpen, onOpenChange, scheduleId, onSaved, }: Readonly<ConnectAvailabilityFormModalProps>): import("react").JSX.Element;
@@ -0,0 +1,132 @@
1
+ import { type ReactNode } from "react";
2
+ import type { CallingAvailability } from "../../types.js";
3
+ /**
4
+ * Calling from the browser, through the workspace's own number.
5
+ *
6
+ * Three pieces: `<ConnectCallProvider>` once, high in your tree;
7
+ * `<ConnectCallButton phone="+91...">` wherever a person can be rung; and
8
+ * `useConnectCall()` if you want your own button.
9
+ *
10
+ * ## Why a provider, and why high up
11
+ *
12
+ * A call has to outlive the page it was started from - someone who rings a
13
+ * customer and then opens their invoices must not hang up on them by doing so.
14
+ * So the call lives in the provider, which also draws the in-call bar, and a
15
+ * button only asks it to start one. Mount it inside `<ConnectProvider>`,
16
+ * beside your app shell rather than inside a page.
17
+ *
18
+ * ## What happens when someone presses Call
19
+ *
20
+ * 1. The browser signs in to the phone network (`POST /calls/browser-token`
21
+ * on your bridge), once per session - Plivo's SDK keeps its registration.
22
+ * Plivo's SDK is loaded at this moment, not before, so a page that never
23
+ * places a call never downloads it.
24
+ * 2. Connect approves the call (`POST /calls/start`): the workspace must hold
25
+ * a number and the member must have "Make calls". What comes back lets this
26
+ * browser place exactly this call and no other.
27
+ * 3. The browser places it. Connect dials the number from the workspace's own
28
+ * number; nothing is recorded.
29
+ *
30
+ * ## Logging a call
31
+ *
32
+ * `onEnded` hands you the call id - deliberately not an outcome. A browser is
33
+ * not a witness your call log should trust, and the carrier's report reaches
34
+ * Connect a moment after the line drops anyway. Read the outcome on your
35
+ * **server** with `connect.calls.get(callId)` (`calls:read`): `status`,
36
+ * `talkSeconds`, `unansweredReason` and `placedByUserId` are what to log.
37
+ */
38
+ type CallPhase = "connecting" | "ringing" | "in-call" | "ended";
39
+ interface ActiveCall {
40
+ phase: CallPhase;
41
+ label: string;
42
+ number: string;
43
+ callId: string | null;
44
+ connectedAt: number | null;
45
+ endedAfterSeconds: number | null;
46
+ muted: boolean;
47
+ notice: string | null;
48
+ }
49
+ /** The number to ring, and how to name the person on the in-call bar. */
50
+ export interface ConnectCallTarget {
51
+ /** E.164, e.g. `+919876543210`. */
52
+ phone: string;
53
+ /** Shown on the in-call bar. Defaults to the number. */
54
+ name?: string;
55
+ /**
56
+ * Called once the call is over, with Connect's id for it - or `null` when it
57
+ * never got as far as being approved. Read the outcome on your server with
58
+ * `connect.calls.get(callId)`; see the module comment for why not here.
59
+ */
60
+ onEnded?: (result: {
61
+ callId: string | null;
62
+ }) => void;
63
+ }
64
+ export interface ConnectCallContextValue {
65
+ /** A call is in progress - every Call button disables on it. */
66
+ isBusy: boolean;
67
+ startCall(target: ConnectCallTarget): Promise<void>;
68
+ /**
69
+ * Whether this member can call and, if not, why - `null` while it loads.
70
+ * Read once by the provider and shared, so every button and status panel
71
+ * agrees, and refreshed after each call so the minutes shown keep up.
72
+ */
73
+ availability: CallingAvailability | null;
74
+ /** Re-read `availability` - after a top-up in another tab, say. */
75
+ refreshAvailability(): void;
76
+ }
77
+ /** Start a call yourself. Must be inside `<ConnectCallProvider>`. */
78
+ export declare function useConnectCall(): ConnectCallContextValue;
79
+ export interface ConnectCallProviderProps {
80
+ children: ReactNode;
81
+ /**
82
+ * Called for every call that ends, whichever button started it - the place
83
+ * to wire "log this call" once for the whole app. A button's own `onEnded`
84
+ * runs as well.
85
+ */
86
+ onCallEnded?: (result: {
87
+ callId: string | null;
88
+ phone: string;
89
+ }) => void;
90
+ /** Called when a call could not be placed, with the reason to show. Defaults to the in-call bar saying so. */
91
+ onError?: (message: string) => void;
92
+ /** Extra classes for the in-call bar's outer element - merged with `cn`. */
93
+ className?: string;
94
+ }
95
+ /**
96
+ * Holds the call in progress and draws the in-call bar. See the module comment.
97
+ */
98
+ export declare function ConnectCallProvider({ children, onCallEnded, onError, className, }: ConnectCallProviderProps): import("react").JSX.Element;
99
+ export interface ConnectCallButtonProps extends ConnectCallTarget {
100
+ /** `compact` is an icon-only button for a row beside a number. */
101
+ variant?: "default" | "compact";
102
+ /** Button label. Defaults to "Call". */
103
+ children?: ReactNode;
104
+ isDisabled?: boolean;
105
+ /** Merged with `cn`, so an override replaces the default it conflicts with. */
106
+ className?: string;
107
+ }
108
+ /**
109
+ * Rings `phone` from the workspace's number. Needs `<ConnectCallProvider>`
110
+ * above it, and a member with "Make calls" - render it only for them, since a
111
+ * button the server refuses for everyone else helps nobody.
112
+ */
113
+ export declare function ConnectCallButton({ phone, name, onEnded, variant, children, isDisabled, className, }: ConnectCallButtonProps): import("react").JSX.Element | null;
114
+ export interface ConnectCallingStatusProps {
115
+ /** Merged with `cn`. */
116
+ className?: string;
117
+ }
118
+ /**
119
+ * The workspace's calling at a glance - its business number, the minutes
120
+ * left, and the next step - for a settings page. Reads the same availability
121
+ * the Call buttons do, so the two never disagree. Buying minutes and adding a
122
+ * number happen in Connect, and come back here when done.
123
+ */
124
+ export declare function ConnectCallingStatus({ className }: ConnectCallingStatusProps): import("react").JSX.Element;
125
+ /** The floating in-call card. Exported for Storybook only - the provider draws it. */
126
+ export declare function ConnectActiveCallBar({ call, onHangUp, onToggleMute, className, }: {
127
+ call: ActiveCall;
128
+ onHangUp: () => void;
129
+ onToggleMute: () => void;
130
+ className?: string;
131
+ }): import("react").JSX.Element;
132
+ export type { ActiveCall as ConnectActiveCall };
@@ -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;
@@ -1,22 +1,44 @@
1
- import type { BookableEventType } from "../../types.js";
1
+ import type { ManageableEventType } from "../../types.js";
2
2
  export interface ConnectEventTypeFormModalProps {
3
3
  isOpen: boolean;
4
4
  onOpenChange: (isOpen: boolean) => void;
5
- /** Called once the appointment type is created, before the modal closes. */
6
- onCreated?: (eventType: BookableEventType) => 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;
7
14
  }
8
15
  /**
9
- * Creates the first thing a workspace can be booked for, from inside a host
10
- * application rather than a link-out to Connect.
16
+ * Creates or edits an appointment type, from inside a host application
17
+ * rather than a link-out to Connect.
11
18
  *
12
19
  * **Needs a schedule to exist first** - the picker reads `useAvailabilitySchedules`
13
20
  * and renders "Set up availability first" with nothing to submit if none
14
21
  * exists yet. Pair this with `ConnectAvailabilityFormModal` in a setup flow
15
22
  * rather than assuming one.
16
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
+ *
17
33
  * **Host is a specific member, never a team.** There is no groups read in
18
34
  * 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.
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.
21
43
  */
22
- export declare function ConnectEventTypeFormModal({ isOpen, onOpenChange, onCreated, }: Readonly<ConnectEventTypeFormModalProps>): import("react").JSX.Element;
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
@@ -102,6 +102,12 @@ export type { PlanAction, PlanTier, ComparablePlan } from "./components/plan-pri
102
102
  export { ConnectWorkspaceSwitcher } from "./components/workspace-switcher.js";
103
103
  export type { ConnectWorkspaceSwitcherProps } from "./components/workspace-switcher.js";
104
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";
109
+ export { ConnectCallProvider, ConnectCallButton, ConnectCallingStatus, useConnectCall, } from "./components/call-button.js";
110
+ export type { ConnectCallProviderProps, ConnectCallButtonProps, ConnectCallTarget, ConnectCallContextValue, ConnectCallingStatusProps, } from "./components/call-button.js";
105
111
  export { ConnectBookingCalendar } from "./components/booking-calendar.js";
106
112
  export type { ConnectBookingCalendarProps } from "./components/booking-calendar.js";
107
113
  export { ConnectBookingDialog, ConnectBookingDetail } from "./components/booking-dialogs.js";
@@ -109,5 +115,5 @@ export { ConnectAvailabilityFormModal } from "./components/availability-form.js"
109
115
  export type { ConnectAvailabilityFormModalProps } from "./components/availability-form.js";
110
116
  export { ConnectEventTypeFormModal } from "./components/event-type-form.js";
111
117
  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";
118
+ export { useBookableEventTypes, useAvailabilitySchedules, useCreateAvailabilitySchedule, useUpdateAvailabilitySchedule, useManageableEventTypes, useCreateEventType, useUpdateEventType, useAvailableSlots, useBookings, useBookingActions, type SlotQuery, type BookingsQuery, } from "./use-scheduling.js";
113
119
  export { layoutBookings, dayColumns, zonedInstant, type GridWindow, type PositionedBooking, } from "./components/booking-grid.js";
@@ -4,7 +4,7 @@
4
4
  * `connectPortalUrl(appUrl, clientId, "/calendar/settings")`, and so on.
5
5
  *
6
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
7
+ * these two params only add the `"Back to <your app>"` banner
8
8
  * (`ApplicationReturnBar` on Connect's side). It validates `return_to`
9
9
  * against this `client_id`'s registered redirect origins and silently drops
10
10
  * the banner if they don't match, so a wrong or stale `appUrl`/`clientId`
@@ -1,4 +1,4 @@
1
- import type { AvailabilitySchedule, BookableEventType, Booking, BookingAttendee, WeeklyHours } 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
  *
@@ -25,6 +25,18 @@ export declare function useAvailabilitySchedules(): {
25
25
  isLoading: boolean;
26
26
  error: string | null;
27
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
+ };
28
40
  /**
29
41
  * Gives a workspace its first working hours.
30
42
  *
@@ -39,6 +51,15 @@ export declare function useCreateAvailabilitySchedule(): BookingActionsState & {
39
51
  weeklyHours: WeeklyHours;
40
52
  }): Promise<AvailabilitySchedule | null>;
41
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
+ };
42
63
  /**
43
64
  * Creates the first thing a workspace can be booked for.
44
65
  *
@@ -60,7 +81,30 @@ export declare function useCreateEventType(): BookingActionsState & {
60
81
  value?: string | null;
61
82
  };
62
83
  publicBookingEnabled?: boolean;
63
- }): Promise<BookableEventType | null>;
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>;
64
108
  };
65
109
  export interface SlotQuery {
66
110
  eventTypeId: string;
@@ -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.38.0";
141
+ export declare const SDK_VERSION = "0.41.0";
@@ -1,5 +1,5 @@
1
1
  import { type TransportOptions } from "../http.js";
2
- import type { CallDetail, CallsPage } from "../../types.js";
2
+ import type { BrowserCallingToken, CallingAvailability, CallDetail, CallsPage, StartedBrowserCall } from "../../types.js";
3
3
  export interface ListCallsInput {
4
4
  /** Narrow to one channel. A channel belonging to another application simply matches nothing. */
5
5
  channelId?: string;
@@ -42,4 +42,35 @@ export declare class CallsResource {
42
42
  * exist *or* belongs to another application.
43
43
  */
44
44
  get(callId: string): Promise<CallDetail>;
45
+ /**
46
+ * Whether the member can call, and if not why - what `<ConnectCallButton>`
47
+ * renders from. Throws `ConnectError` 403 for a member without "Make
48
+ * calls"; the bridge turns that into `status: "no_permission"`.
49
+ */
50
+ getCallingAvailability(input: {
51
+ asUser: string;
52
+ }): Promise<CallingAvailability>;
53
+ /** A carrier token the member's browser signs in to the phone network with. */
54
+ getBrowserCallingToken(input: {
55
+ asUser: string;
56
+ }): Promise<BrowserCallingToken>;
57
+ /**
58
+ * Approves one call from the member to `phone` (E.164) and records it.
59
+ *
60
+ * Throws `ConnectError` with status `412` when the workspace has no active
61
+ * number, is not allowed to place calls, or the member is already on one -
62
+ * the message is written to be shown to them.
63
+ */
64
+ startBrowserCall(input: {
65
+ phone: string;
66
+ asUser: string;
67
+ }): Promise<StartedBrowserCall>;
68
+ /**
69
+ * Closes a call the browser never managed to place - recorded as
70
+ * `unanswered`/`cancelled`. A no-op once the carrier has it.
71
+ */
72
+ cancelBrowserCall(input: {
73
+ callId: string;
74
+ asUser: string;
75
+ }): Promise<void>;
45
76
  }
@@ -1,5 +1,5 @@
1
1
  import { type TransportOptions } from "../http.js";
2
- import type { AvailabilitySchedule, BookableEventType, Booking, RescheduledBooking, BookingAttendee, BookingSlots, BookingStatus, ListBookingsPage, WeeklyHours } from "../../types.js";
2
+ import type { AvailabilitySchedule, BookableEventType, Booking, ManageableEventType, RescheduledBooking, BookingAttendee, BookingSlots, BookingStatus, ListBookingsPage, WeeklyHours } from "../../types.js";
3
3
  /**
4
4
  * Present on every method here.
5
5
  *
@@ -98,6 +98,42 @@ export interface CreateEventTypeInput extends ActingAsOption {
98
98
  /** Off by default - most appointment types are booked by your integration or a member, not the public. */
99
99
  publicBookingEnabled?: boolean;
100
100
  }
101
+ /**
102
+ * What `updateSchedule` takes. Every field optional - send only what changed.
103
+ * `ownerMemberId` and date overrides are not settable from this surface at
104
+ * all, so an edit can never touch them.
105
+ */
106
+ export interface UpdateScheduleInput extends ActingAsOption {
107
+ workspaceId: string;
108
+ scheduleId: string;
109
+ name?: string;
110
+ timezone?: string;
111
+ weeklyHours?: WeeklyHours;
112
+ }
113
+ /**
114
+ * What `updateEventType` takes. Every field optional - send only what
115
+ * changed. `hostMemberId` omitted leaves the host untouched, including a
116
+ * *group* host this surface cannot represent; sending one always rewrites to
117
+ * a member host, by design.
118
+ */
119
+ export interface UpdateEventTypeInput extends ActingAsOption {
120
+ workspaceId: string;
121
+ eventTypeId: string;
122
+ name?: string;
123
+ description?: string | null;
124
+ durationMinutes?: number;
125
+ bufferBeforeMinutes?: number;
126
+ bufferAfterMinutes?: number;
127
+ hostMemberId?: string;
128
+ scheduleId?: string;
129
+ location?: {
130
+ kind: "phone" | "address" | "link";
131
+ value?: string | null;
132
+ };
133
+ publicBookingEnabled?: boolean;
134
+ /** Take an appointment type out of (or back into) service. */
135
+ active?: boolean;
136
+ }
101
137
  export interface CreateBookingInput extends ActingAsOption {
102
138
  workspaceId: string;
103
139
  eventTypeId: string;
@@ -152,8 +188,36 @@ export declare class SchedulingResource {
152
188
  * Needs a schedule - create or pick one with `listSchedules`/`createSchedule`
153
189
  * first. The slug for a future public booking link is derived from `name`
154
190
  * server-side; you cannot choose one.
191
+ *
192
+ * Answers the richer *manageable* shape, not `BookableEventType` - you just
193
+ * created this row and are about to manage it, not book against it.
194
+ */
195
+ createEventType(input: CreateEventTypeInput): Promise<ManageableEventType>;
196
+ /**
197
+ * The richer read `createEventType`/`updateEventType`'s edit mode needs -
198
+ * everything `listEventTypes`'s booking catalogue deliberately withholds,
199
+ * because this is the opposite audience: a member managing their own
200
+ * calendar, not a widget rendering someone else's. Includes inactive rows,
201
+ * since an edit screen is exactly where one gets reactivated.
202
+ */
203
+ listManageableEventTypes(workspaceId: string, options?: ActingAsOption): Promise<ManageableEventType[]>;
204
+ /**
205
+ * Edits an existing availability schedule.
206
+ *
207
+ * Narrower than what the workspace's own Calendar settings can do, the
208
+ * same way `createSchedule` is: `ownerMemberId` and date overrides stay
209
+ * untouched, since this surface never sets either.
210
+ */
211
+ updateSchedule(input: UpdateScheduleInput): Promise<AvailabilitySchedule>;
212
+ /**
213
+ * Edits an existing appointment type.
214
+ *
215
+ * `hostMemberId` omitted leaves the host untouched, including a *group*
216
+ * host this surface cannot represent - so an edit that says nothing about
217
+ * the host can never accidentally overwrite a team assignment made in
218
+ * Connect.
155
219
  */
156
- createEventType(input: CreateEventTypeInput): Promise<BookableEventType>;
220
+ updateEventType(input: UpdateEventTypeInput): Promise<ManageableEventType>;
157
221
  /**
158
222
  * Free times for one appointment type over one window.
159
223
  *