@cosmoops/connect-sdk 0.17.0 → 0.18.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.
- package/CHANGELOG.md +82 -0
- package/README.md +19 -1
- package/dist/cjs/client/components/booking-calendar.js +170 -0
- package/dist/cjs/client/components/booking-dialogs.js +124 -0
- package/dist/cjs/client/components/booking-grid.js +206 -0
- package/dist/cjs/client/index.js +15 -1
- package/dist/cjs/client/use-scheduling.js +113 -0
- package/dist/cjs/server/client.js +1 -1
- package/dist/cjs/server/handler.js +136 -0
- package/dist/cjs/server/resources/scheduling.js +32 -1
- package/dist/esm/client/components/booking-calendar.js +167 -0
- package/dist/esm/client/components/booking-dialogs.js +120 -0
- package/dist/esm/client/components/booking-grid.js +199 -0
- package/dist/esm/client/index.js +4 -0
- package/dist/esm/client/use-scheduling.js +107 -0
- package/dist/esm/server/client.js +1 -1
- package/dist/esm/server/handler.js +136 -0
- package/dist/esm/server/resources/scheduling.js +32 -1
- package/dist/types/client/components/booking-calendar.d.ts +38 -0
- package/dist/types/client/components/booking-dialogs.d.ts +33 -0
- package/dist/types/client/components/booking-grid.d.ts +102 -0
- package/dist/types/client/index.d.ts +5 -0
- package/dist/types/client/use-scheduling.d.ts +93 -0
- package/dist/types/server/client.d.ts +1 -1
- package/dist/types/server/index.d.ts +1 -1
- package/dist/types/server/resources/scheduling.d.ts +51 -6
- package/dist/types/types.d.ts +13 -0
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type GridWindow } from "./booking-grid.js";
|
|
2
|
+
export interface ConnectBookingCalendarProps {
|
|
3
|
+
/**
|
|
4
|
+
* The business's IANA timezone. **Every instant on the grid is read against
|
|
5
|
+
* it, never the viewer's** - a workspace's working day must not shift
|
|
6
|
+
* because a member is travelling.
|
|
7
|
+
*
|
|
8
|
+
* Defaults to the host's zone, which is right for the common case where
|
|
9
|
+
* staff and business share one. Pass it explicitly when they might not.
|
|
10
|
+
*/
|
|
11
|
+
timeZone?: string;
|
|
12
|
+
/** Only appointments this member hosts. Omit for the whole workspace's diary. */
|
|
13
|
+
hostMemberId?: string;
|
|
14
|
+
/** Narrow the visible band - see `DEFAULT_WINDOW`. */
|
|
15
|
+
window?: GridWindow;
|
|
16
|
+
/** Hide the "New appointment" action for a read-only view. */
|
|
17
|
+
canBook?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A week of the workspace's calendar, with booking, rescheduling and
|
|
22
|
+
* cancelling.
|
|
23
|
+
*
|
|
24
|
+
* **Two views, and which one you get is a viewport decision, not a
|
|
25
|
+
* preference.** A seven-column time grid needs roughly 640px before a column
|
|
26
|
+
* is wide enough to hold a name; below that it degrades into unreadable
|
|
27
|
+
* slivers. So the grid is `sm:` and up, and the same week renders as a grouped
|
|
28
|
+
* agenda underneath - not a cut-down grid, a different and better shape for a
|
|
29
|
+
* phone. Both read the same data and open the same dialogs.
|
|
30
|
+
*
|
|
31
|
+
* Everything it does goes through the bridge as the signed-in member, so
|
|
32
|
+
* Connect checks *their* `calendar:read` / `calendar:manage` rather than the
|
|
33
|
+
* host application's key. A member who may look but not book gets the grid and
|
|
34
|
+
* a refusal on the write, which is the correct shape - see `useBookingActions`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ConnectBookingCalendar({ timeZone, hostMemberId, window: visibleWindow, canBook, className, }: Readonly<ConnectBookingCalendarProps>): import("react").JSX.Element;
|
|
37
|
+
declare function timeLabel(instant: Date, zone: string): string;
|
|
38
|
+
export { timeLabel as connectBookingTimeLabel };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { BookableEventType, Booking } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Picking a time, and then who it is for.
|
|
4
|
+
*
|
|
5
|
+
* The slot list is read fresh every time this opens and is **never cached
|
|
6
|
+
* across an open**: it is a snapshot of contention, and offering a time
|
|
7
|
+
* somebody took ninety seconds ago is how two people end up in the same slot.
|
|
8
|
+
* The server re-checks inside its transaction regardless, so a stale list
|
|
9
|
+
* costs a refusal rather than a double booking - this only makes the refusal
|
|
10
|
+
* rare enough to be surprising when it happens.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ConnectBookingDialog({ isOpen, onOpenChange, eventTypes, initialStartAt, timeZone, onBooked, }: Readonly<{
|
|
13
|
+
isOpen: boolean;
|
|
14
|
+
onOpenChange(open: boolean): void;
|
|
15
|
+
eventTypes: BookableEventType[];
|
|
16
|
+
initialStartAt: Date;
|
|
17
|
+
timeZone: string;
|
|
18
|
+
onBooked(booking: Booking): void;
|
|
19
|
+
}>): import("react").JSX.Element;
|
|
20
|
+
/**
|
|
21
|
+
* One appointment, and the two things anyone opens it to do.
|
|
22
|
+
*
|
|
23
|
+
* Rescheduling re-reads the slots with `excludeBookingId` set to this booking.
|
|
24
|
+
* Without that the appointment blocks its own replacement, and moving it by
|
|
25
|
+
* half an hour - the only move most people ever make - offers nothing.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ConnectBookingDetail({ booking, eventType, timeZone, onOpenChange, onChanged, }: Readonly<{
|
|
28
|
+
booking: Booking;
|
|
29
|
+
eventType: BookableEventType | null;
|
|
30
|
+
timeZone: string;
|
|
31
|
+
onOpenChange(open: boolean): void;
|
|
32
|
+
onChanged(): void;
|
|
33
|
+
}>): import("react").JSX.Element;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Booking } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The arithmetic behind the week grid, with no React and no fetching - the
|
|
4
|
+
* same split `slot-computation.ts` uses server-side, and for the same reason:
|
|
5
|
+
* every timezone and overlap rule is then testable without rendering
|
|
6
|
+
* anything, and a layout bug is a failing assertion rather than a screenshot
|
|
7
|
+
* somebody has to notice.
|
|
8
|
+
*
|
|
9
|
+
* **Every instant is read against the business's timezone**, never the
|
|
10
|
+
* viewer's. A workspace in Kolkata whose staff are travelling must not see
|
|
11
|
+
* their own working day shift; the grid is a picture of when *the business* is
|
|
12
|
+
* open. That is why every function here takes an explicit `timeZone` rather
|
|
13
|
+
* than falling back to the host's.
|
|
14
|
+
*/
|
|
15
|
+
export interface ZonedInstant {
|
|
16
|
+
/** `YYYY-MM-DD` in `timeZone` - the local calendar day this instant falls on. */
|
|
17
|
+
dateKey: string;
|
|
18
|
+
/** Minutes since local midnight, `0`-`1439`. */
|
|
19
|
+
minutes: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* An instant, as the local day and minute it lands on in `timeZone`.
|
|
23
|
+
*
|
|
24
|
+
* Built from `formatToParts` rather than by adding a fixed offset. An offset
|
|
25
|
+
* is only correct until a DST boundary, and "add 5.5 hours" is wrong the
|
|
26
|
+
* moment the same code is pointed at a zone that observes one - which is
|
|
27
|
+
* exactly the kind of bug that appears twice a year and never in a test.
|
|
28
|
+
*/
|
|
29
|
+
export declare function zonedInstant(instant: Date, timeZone: string): ZonedInstant;
|
|
30
|
+
export interface DayColumn {
|
|
31
|
+
/** `YYYY-MM-DD` in the grid's timezone. */
|
|
32
|
+
dateKey: string;
|
|
33
|
+
/** "Mon 8" - the column heading. */
|
|
34
|
+
label: string;
|
|
35
|
+
/** "Sep" etc, for the first column and any month change. */
|
|
36
|
+
monthLabel: string;
|
|
37
|
+
/** Midnight of this day, as an instant. Used to build slot query windows. */
|
|
38
|
+
startsAt: Date;
|
|
39
|
+
isToday: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `count` consecutive days starting at the local day `anchor` falls on.
|
|
43
|
+
*
|
|
44
|
+
* Days are stepped by adding 24 hours and re-reading the zone rather than by
|
|
45
|
+
* incrementing a date field, so a day that is 23 or 25 hours long still
|
|
46
|
+
* produces the right sequence of `dateKey`s - the midday anchor is what keeps
|
|
47
|
+
* a DST shift from landing the step on the previous or next day.
|
|
48
|
+
*/
|
|
49
|
+
export declare function dayColumns(anchor: Date, timeZone: string, count: number, now: Date): DayColumn[];
|
|
50
|
+
/**
|
|
51
|
+
* Local midnight of `dateKey` in `timeZone`, as an instant.
|
|
52
|
+
*
|
|
53
|
+
* Solved by probing rather than by arithmetic: guess UTC midnight, read what
|
|
54
|
+
* local time that actually is, and subtract the difference. One correction is
|
|
55
|
+
* always enough because a zone's offset cannot change within the few hours the
|
|
56
|
+
* correction spans - and unlike a fixed-offset formula it is right across DST
|
|
57
|
+
* and for the half-hour zones (`Asia/Kolkata`, `Australia/Adelaide`) that a
|
|
58
|
+
* naive implementation quietly breaks on.
|
|
59
|
+
*/
|
|
60
|
+
export declare function dayStartInstant(dateKey: string, timeZone: string): Date;
|
|
61
|
+
export interface PositionedBooking {
|
|
62
|
+
booking: Booking;
|
|
63
|
+
dateKey: string;
|
|
64
|
+
/** Fraction of the visible day, `0`-`1`, from the top of the grid. */
|
|
65
|
+
top: number;
|
|
66
|
+
/** Fraction of the visible day. Never `0` - see `MIN_VISIBLE_FRACTION`. */
|
|
67
|
+
height: number;
|
|
68
|
+
/** Column index within its overlap cluster, and how many columns that cluster has. */
|
|
69
|
+
column: number;
|
|
70
|
+
columns: number;
|
|
71
|
+
/** True when the appointment extends past the grid's visible window. */
|
|
72
|
+
clipped: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface GridWindow {
|
|
75
|
+
/** Minutes since local midnight the grid starts at - `480` is 08:00. */
|
|
76
|
+
startMinute: number;
|
|
77
|
+
endMinute: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Places bookings on the grid, side by side where they collide.
|
|
81
|
+
*
|
|
82
|
+
* Overlap handling is the part worth stating. Two appointments at the same
|
|
83
|
+
* time are not an error - a workspace with two hosts has them constantly - and
|
|
84
|
+
* stacking them would hide one entirely. So overlapping bookings are grouped
|
|
85
|
+
* into *clusters* and each cluster is split into equal columns. The cluster is
|
|
86
|
+
* built transitively: A overlapping B and B overlapping C puts all three in one
|
|
87
|
+
* cluster even when A and C do not touch, because anything else lets two of
|
|
88
|
+
* them land on the same column.
|
|
89
|
+
*/
|
|
90
|
+
export declare function layoutBookings(bookings: Booking[], timeZone: string, window: GridWindow): PositionedBooking[];
|
|
91
|
+
/**
|
|
92
|
+
* The hour labels down the left edge, inclusive of both ends.
|
|
93
|
+
*
|
|
94
|
+
* Takes no timezone, deliberately: these label *wall-clock hours on the grid*,
|
|
95
|
+
* not instants. The grid is already drawn in the business's zone, so "10 am"
|
|
96
|
+
* means the business's ten - running the label through a zone conversion would
|
|
97
|
+
* shift it away from the row it sits on.
|
|
98
|
+
*/
|
|
99
|
+
export declare function hourMarks(window: GridWindow): {
|
|
100
|
+
minute: number;
|
|
101
|
+
label: string;
|
|
102
|
+
}[];
|
|
@@ -87,3 +87,8 @@ export type { PlanAction, PlanTier, ComparablePlan } from "./components/plan-pri
|
|
|
87
87
|
export { ConnectWorkspaceSwitcher } from "./components/workspace-switcher.js";
|
|
88
88
|
export type { ConnectWorkspaceSwitcherProps } from "./components/workspace-switcher.js";
|
|
89
89
|
export { useConnectWorkspaces, useConnectWorkspaceMembers } from "./provider.js";
|
|
90
|
+
export { ConnectBookingCalendar } from "./components/booking-calendar.js";
|
|
91
|
+
export type { ConnectBookingCalendarProps } from "./components/booking-calendar.js";
|
|
92
|
+
export { ConnectBookingDialog, ConnectBookingDetail } from "./components/booking-dialogs.js";
|
|
93
|
+
export { useBookableEventTypes, useAvailableSlots, useBookings, useBookingActions, type SlotQuery, type BookingsQuery, } from "./use-scheduling.js";
|
|
94
|
+
export { layoutBookings, dayColumns, zonedInstant, type GridWindow, type PositionedBooking, } from "./components/booking-grid.js";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { BookableEventType, Booking, BookingAttendee } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The bridge's scheduling surface, as hooks.
|
|
4
|
+
*
|
|
5
|
+
* Every path here is one of the six the bridge exposes, and every one of them
|
|
6
|
+
* is resolved *for the signed-in member* - Connect takes the workspace from
|
|
7
|
+
* their session and checks their own `calendar:read` / `calendar:manage`.
|
|
8
|
+
* Nothing in this file names a workspace, and nothing should: a browser that
|
|
9
|
+
* can name a tenant is a browser that can read someone else's diary.
|
|
10
|
+
*/
|
|
11
|
+
/** What this workspace offers as bookable. Active types only. */
|
|
12
|
+
export declare function useBookableEventTypes(): {
|
|
13
|
+
eventTypes: BookableEventType[];
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
error: string | null;
|
|
16
|
+
};
|
|
17
|
+
export interface SlotQuery {
|
|
18
|
+
eventTypeId: string;
|
|
19
|
+
from: Date;
|
|
20
|
+
to: Date;
|
|
21
|
+
/**
|
|
22
|
+
* Set to the booking being moved. Without it the appointment counts as
|
|
23
|
+
* blocking its own replacement and a reschedule picker comes back empty for
|
|
24
|
+
* the one adjustment people actually make.
|
|
25
|
+
*/
|
|
26
|
+
excludeBookingId?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Free times for one appointment type.
|
|
30
|
+
*
|
|
31
|
+
* **Deliberately re-read rather than cached across a session.** A slot list is
|
|
32
|
+
* a snapshot of contention: anyone else on that calendar - a colleague, a
|
|
33
|
+
* voice agent mid-call, someone on the public booking link - can take one
|
|
34
|
+
* between the read and the click. Showing a stale one is how two people are
|
|
35
|
+
* offered the same minute. The booking call re-checks inside a transaction
|
|
36
|
+
* anyway, so a stale list costs a refusal rather than a double booking; this
|
|
37
|
+
* just means the refusal is rare.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useAvailableSlots(query: SlotQuery | null): {
|
|
40
|
+
slots: import("./index.js").BookingSlot[];
|
|
41
|
+
timezone: string | null;
|
|
42
|
+
durationMinutes: number | null;
|
|
43
|
+
isLoading: boolean;
|
|
44
|
+
error: string | null;
|
|
45
|
+
refetch: () => void;
|
|
46
|
+
};
|
|
47
|
+
export interface BookingsQuery {
|
|
48
|
+
from: Date;
|
|
49
|
+
to: Date;
|
|
50
|
+
/** Only appointments this member is hosting. Omit for the whole workspace. */
|
|
51
|
+
hostMemberId?: string;
|
|
52
|
+
limit?: number;
|
|
53
|
+
}
|
|
54
|
+
/** One page of the diary, ascending - a forward view, not a history. */
|
|
55
|
+
export declare function useBookings(query: BookingsQuery): {
|
|
56
|
+
bookings: Booking[];
|
|
57
|
+
hasMore: boolean;
|
|
58
|
+
isLoading: boolean;
|
|
59
|
+
error: string | null;
|
|
60
|
+
path: string;
|
|
61
|
+
refetch: () => void;
|
|
62
|
+
};
|
|
63
|
+
export interface BookingActionsState {
|
|
64
|
+
isPending: boolean;
|
|
65
|
+
/** The last refusal, written to be shown to the person who clicked. */
|
|
66
|
+
error: string | null;
|
|
67
|
+
clearError(): void;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Book, move and cancel.
|
|
71
|
+
*
|
|
72
|
+
* **None of these is optimistic**, and that is not an oversight. Whether a
|
|
73
|
+
* slot is still free is a question only the server can answer, inside the
|
|
74
|
+
* transaction that decides it - two people can be holding the same minute
|
|
75
|
+
* right now. Painting a booking as made and withdrawing it is exactly the lie
|
|
76
|
+
* the two-phase hold exists to prevent.
|
|
77
|
+
*/
|
|
78
|
+
export declare function useBookingActions(): BookingActionsState & {
|
|
79
|
+
createBooking(input: {
|
|
80
|
+
eventTypeId: string;
|
|
81
|
+
startAt: string;
|
|
82
|
+
attendee: BookingAttendee;
|
|
83
|
+
notes?: string | null;
|
|
84
|
+
}): Promise<Booking | null>;
|
|
85
|
+
rescheduleBooking(input: {
|
|
86
|
+
bookingId: string;
|
|
87
|
+
startAt: string;
|
|
88
|
+
}): Promise<Booking | null>;
|
|
89
|
+
cancelBooking(input: {
|
|
90
|
+
bookingId: string;
|
|
91
|
+
reason?: string | null;
|
|
92
|
+
}): Promise<Booking | null>;
|
|
93
|
+
};
|
|
@@ -27,7 +27,7 @@ export type { AnalyticsResource } from "./resources/analytics.js";
|
|
|
27
27
|
export type { SessionsResource } from "./resources/sessions.js";
|
|
28
28
|
export type { ExecuteIntegrationActionInput, IntegrationsResource } from "./resources/integrations.js";
|
|
29
29
|
export type { PlatformResource } from "./resources/platform.js";
|
|
30
|
-
export type { SchedulingResource, FindSlotsInput, ListBookingsInput, CreateBookingInput, } from "./resources/scheduling.js";
|
|
30
|
+
export type { SchedulingResource, FindSlotsInput, ListBookingsInput, CreateBookingInput, RescheduleBookingInput, } from "./resources/scheduling.js";
|
|
31
31
|
/**
|
|
32
32
|
* Webhook verification and a ready-made POST route. Server-only for the
|
|
33
33
|
* obvious reason: the signing secret must never reach a browser bundle.
|
|
@@ -1,13 +1,45 @@
|
|
|
1
1
|
import { type TransportOptions } from "../http.js";
|
|
2
|
-
import type { BookableEventType, Booking, BookingAttendee, BookingSlots, BookingStatus, ListBookingsPage } from "../../types.js";
|
|
3
|
-
|
|
2
|
+
import type { BookableEventType, Booking, RescheduledBooking, BookingAttendee, BookingSlots, BookingStatus, ListBookingsPage } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Present on every method here.
|
|
5
|
+
*
|
|
6
|
+
* With `asUser`, Connect derives the workspace from **that member's session**
|
|
7
|
+
* and ignores `workspaceId`, then checks their own `calendar:read` /
|
|
8
|
+
* `calendar:manage`. Without it the call is your server acting for a workspace
|
|
9
|
+
* you name, gated only on your application being installed there. The bridge
|
|
10
|
+
* always sends it - a browser must never be trusted to name a tenant, and an
|
|
11
|
+
* end user of your app is not automatically allowed to book on their
|
|
12
|
+
* employer's calendar.
|
|
13
|
+
*/
|
|
14
|
+
export interface ActingAsOption {
|
|
15
|
+
/** The signed-in member's opaque Connect session token. */
|
|
16
|
+
asUser?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface FindSlotsInput extends ActingAsOption {
|
|
4
19
|
workspaceId: string;
|
|
5
20
|
eventTypeId: string;
|
|
6
21
|
/** ISO-8601 instant, or a `Date`. */
|
|
7
22
|
from: string | Date;
|
|
8
23
|
to: string | Date;
|
|
24
|
+
/**
|
|
25
|
+
* A booking to treat as if it were not there - **set this when offering
|
|
26
|
+
* times to move an existing appointment to.**
|
|
27
|
+
*
|
|
28
|
+
* Without it the appointment counts as blocking its own replacement, so the
|
|
29
|
+
* adjustment people actually make - same day, half an hour later - comes
|
|
30
|
+
* back with nothing available.
|
|
31
|
+
*/
|
|
32
|
+
excludeBookingId?: string;
|
|
9
33
|
}
|
|
10
|
-
export interface
|
|
34
|
+
export interface RescheduleBookingInput extends ActingAsOption {
|
|
35
|
+
workspaceId: string;
|
|
36
|
+
bookingId: string;
|
|
37
|
+
/** The new time, from a `findSlots` result, passed back unchanged. */
|
|
38
|
+
startAt: string | Date;
|
|
39
|
+
/** Replaces the original note when given; it carries over otherwise. */
|
|
40
|
+
notes?: string | null;
|
|
41
|
+
}
|
|
42
|
+
export interface ListBookingsInput extends ActingAsOption {
|
|
11
43
|
workspaceId: string;
|
|
12
44
|
status?: BookingStatus;
|
|
13
45
|
/** A Connect workspace member id - only bookings that committed them. */
|
|
@@ -19,7 +51,7 @@ export interface ListBookingsInput {
|
|
|
19
51
|
cursor?: string;
|
|
20
52
|
limit?: number;
|
|
21
53
|
}
|
|
22
|
-
export interface CreateBookingInput {
|
|
54
|
+
export interface CreateBookingInput extends ActingAsOption {
|
|
23
55
|
workspaceId: string;
|
|
24
56
|
eventTypeId: string;
|
|
25
57
|
/**
|
|
@@ -50,7 +82,7 @@ export declare class SchedulingResource {
|
|
|
50
82
|
private readonly transport;
|
|
51
83
|
constructor(transport: TransportOptions);
|
|
52
84
|
/** What this workspace offers as bookable. Active appointment types only. */
|
|
53
|
-
listEventTypes(workspaceId: string): Promise<BookableEventType[]>;
|
|
85
|
+
listEventTypes(workspaceId: string, options?: ActingAsOption): Promise<BookableEventType[]>;
|
|
54
86
|
/**
|
|
55
87
|
* Free times for one appointment type over one window.
|
|
56
88
|
*
|
|
@@ -76,6 +108,19 @@ export declare class SchedulingResource {
|
|
|
76
108
|
* a `ConnectError` with `code: "conflict"` rather than double-booking.
|
|
77
109
|
*/
|
|
78
110
|
createBooking(input: CreateBookingInput): Promise<Booking>;
|
|
111
|
+
/**
|
|
112
|
+
* Moves an appointment to a different time.
|
|
113
|
+
*
|
|
114
|
+
* **The original is retired, not edited.** It stays on the diary as
|
|
115
|
+
* `rescheduled` with `rescheduledToId` pointing at the replacement, and both
|
|
116
|
+
* come back here - so a booking id you cached still resolves, and still says
|
|
117
|
+
* where the appointment went.
|
|
118
|
+
*
|
|
119
|
+
* A refused move changes nothing: the new slot is claimed before the old one
|
|
120
|
+
* is released, so a `conflict` leaves the customer with the appointment they
|
|
121
|
+
* already had. Re-read the slots (with `excludeBookingId`) and offer another.
|
|
122
|
+
*/
|
|
123
|
+
rescheduleBooking(input: RescheduleBookingInput): Promise<RescheduledBooking>;
|
|
79
124
|
/**
|
|
80
125
|
* Frees the slot and records why.
|
|
81
126
|
*
|
|
@@ -83,7 +128,7 @@ export declare class SchedulingResource {
|
|
|
83
128
|
* reason, which is what makes a late cancellation something anyone can look
|
|
84
129
|
* up afterwards.
|
|
85
130
|
*/
|
|
86
|
-
cancelBooking(input: {
|
|
131
|
+
cancelBooking(input: ActingAsOption & {
|
|
87
132
|
workspaceId: string;
|
|
88
133
|
bookingId: string;
|
|
89
134
|
reason?: string | null;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1202,8 +1202,21 @@ export interface Booking {
|
|
|
1202
1202
|
notes: string | null;
|
|
1203
1203
|
source: BookingSource;
|
|
1204
1204
|
cancelledReason: string | null;
|
|
1205
|
+
/**
|
|
1206
|
+
* Set when `status` is `rescheduled` - the booking that replaced this one.
|
|
1207
|
+
*
|
|
1208
|
+
* Rescheduling retires a booking rather than moving its `startAt`, so an id
|
|
1209
|
+
* you cached still resolves and still tells you where the appointment went.
|
|
1210
|
+
*/
|
|
1211
|
+
rescheduledToId: string | null;
|
|
1205
1212
|
createdAt: string;
|
|
1206
1213
|
}
|
|
1214
|
+
export interface RescheduledBooking {
|
|
1215
|
+
/** The new appointment. This is the live one. */
|
|
1216
|
+
booking: Booking;
|
|
1217
|
+
/** The retired original, now `rescheduled` and pointing at `booking`. */
|
|
1218
|
+
previous: Booking;
|
|
1219
|
+
}
|
|
1207
1220
|
export interface ListBookingsPage {
|
|
1208
1221
|
bookings: Booking[];
|
|
1209
1222
|
/** Pass back as `cursor`. A cursor belongs to one set of filters. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmoops/connect-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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",
|