@cosmoops/connect-sdk 0.27.0 → 0.28.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 CHANGED
@@ -3,12 +3,61 @@
3
3
  `@cosmoops/connect-sdk` follows semver, with the 0.x convention that **minor
4
4
  versions may carry breaking changes** and patch versions never do.
5
5
 
6
+ ## 0.28.0
7
+
8
+ Connect's webhook bus carried four events, all of them about billing and
9
+ deletion. It now carries the seven a system of record is actually built on —
10
+ calls, appointments and contacts — so the work your customers do inside
11
+ Connect can reach the product they do the rest of their work in.
12
+
13
+ ### Added
14
+
15
+ - Seven webhook event types, with their payloads fully typed on
16
+ `ConnectWebhookEventMap`: `call.completed`, `call.missed`,
17
+ `booking.confirmed`, `booking.cancelled`, `booking.rescheduled`,
18
+ `contact.created` and `contact.updated`. Register handlers for them on
19
+ `createConnectWebhookHandler` exactly as you do the existing four.
20
+ - `ConnectCallDirection` and `ConnectContactSource`, the two unions those
21
+ payloads carry.
22
+
23
+ These are **activity** events rather than lifecycle ones, and the difference
24
+ decides who receives them: they are delivered only to applications the
25
+ workspace is actually subscribed to, so a lapsed customer stops emitting on
26
+ the same boundary that stops their access.
27
+
28
+ Three conventions are worth reading before you write a handler, each
29
+ documented on the types themselves. Phone numbers are E.164. A call event
30
+ identifies its party by `contactPhone` and deliberately carries no
31
+ `contactId` — Connect resolves a caller *by* the number and at the moment a
32
+ call ends it often has not, so the field would be `null` on most deliveries.
33
+ And `booking.rescheduled` carries `previousBookingId` as well as `bookingId`,
34
+ because Connect retires the old booking and writes a new one: reconcile on
35
+ the previous id or you will end up holding two appointments.
36
+
37
+ ### Fixed
38
+
39
+ - `Booking` fixtures in the bundled tests compile again — the type gained a
40
+ required `hostMemberIds` in 0.27.0 and one fixture was missed. No runtime
41
+ change.
42
+
43
+ ### A note on exhaustiveness
44
+
45
+ `ConnectWebhookEventType` is a union that grows, and this release grows it.
46
+ `createConnectWebhookHandler` is unaffected — its `on` map is partial and it
47
+ answers 200 to anything you have not registered. A hand-written `switch` with
48
+ an exhaustive `never` check on that union will now fail to compile until you
49
+ add the new members; that is the documented contract of this union rather than
50
+ a break, and it is the reason the handler exists.
51
+
6
52
  ## 0.27.0
7
53
 
8
54
  A minor rather than a patch because `Booking` gains a required field, so a
9
55
  hand-written object satisfying the old interface no longer type-checks. Nothing
10
56
  you *read* from the API breaks.
11
57
 
58
+ 0.26.1 was never published; its note below ships as part of this release, so the
59
+ registry goes 0.26.0 → 0.27.0.
60
+
12
61
  ### Added
13
62
 
14
63
  - **`connect.scheduling.getBooking()`** - one appointment, by the id you
@@ -161,4 +161,4 @@ class ConnectClient {
161
161
  }
162
162
  exports.ConnectClient = ConnectClient;
163
163
  /** Kept in step with `package.json` by `sdk.test.ts`. */
164
- exports.SDK_VERSION = "0.27.0";
164
+ exports.SDK_VERSION = "0.28.0";
@@ -157,4 +157,4 @@ export class ConnectClient {
157
157
  }
158
158
  }
159
159
  /** Kept in step with `package.json` by `sdk.test.ts`. */
160
- export const SDK_VERSION = "0.27.0";
160
+ export const SDK_VERSION = "0.28.0";
@@ -123,4 +123,4 @@ export declare class ConnectClient {
123
123
  constructor(options: ConnectClientOptions);
124
124
  }
125
125
  /** Kept in step with `package.json` by `sdk.test.ts`. */
126
- export declare const SDK_VERSION = "0.27.0";
126
+ export declare const SDK_VERSION = "0.28.0";
@@ -775,7 +775,7 @@ export interface EmitEventsResponse {
775
775
  * `createConnectWebhookHandler` simply ignores anything you have not
776
776
  * registered a handler for.
777
777
  */
778
- export type ConnectWebhookEventType = "workspace.deletion_scheduled" | "workspace.deletion_cancelled" | "workspace.deleted" | "subscription.cancelled";
778
+ export type ConnectWebhookEventType = "workspace.deletion_scheduled" | "workspace.deletion_cancelled" | "workspace.deleted" | "subscription.cancelled" | "call.completed" | "call.missed" | "booking.confirmed" | "booking.cancelled" | "booking.rescheduled" | "contact.created" | "contact.updated";
779
779
  /**
780
780
  * A workspace's deletion has been confirmed and the grace window is running.
781
781
  *
@@ -815,12 +815,197 @@ export interface SubscriptionCancelledEvent {
815
815
  subscriptionId: string;
816
816
  applicationId: string;
817
817
  }
818
+ /** Which way a call went. */
819
+ export type ConnectCallDirection = "inbound" | "outbound";
820
+ /**
821
+ * A call ended.
822
+ *
823
+ * The event an external system of record is built on: it is what turns a
824
+ * conversation that happened in Connect's telephony into a row in your own
825
+ * timeline with nobody retyping it. Fires for every completed call, whether an
826
+ * agent answered it or a person did.
827
+ */
828
+ export interface CallCompletedEvent {
829
+ workspaceId: string;
830
+ callId: string;
831
+ channelId: string | null;
832
+ /**
833
+ * E.164, and the only identity a call event carries.
834
+ *
835
+ * There is deliberately no `contactId`: Connect resolves a caller to a
836
+ * contact by number, and at the moment a call ends it may not have done so
837
+ * at all - the field would be `null` on most deliveries, which is a field
838
+ * that silently does nothing. Match on this instead. It is the same
839
+ * canonical form `contacts.lookupByPhone` takes, so resolving it is one call
840
+ * if you want the contact.
841
+ */
842
+ contactPhone: string | null;
843
+ direction: ConnectCallDirection;
844
+ /** How it ended, as Connect's telephony reported it - `"completed"`, `"transferred"`, … */
845
+ outcome: string;
846
+ durationSeconds: number;
847
+ /**
848
+ * What the agent's skills captured during the conversation, keyed by the
849
+ * capture fields the agent declares.
850
+ *
851
+ * Shapeless on purpose - the keys and the value types are whatever that
852
+ * agent's `extractionSchema` declares, which Connect does not constrain.
853
+ * `{}` on most calls, since an unanswered or human-answered call extracts
854
+ * nothing, so treat every key as optional rather than checking the object
855
+ * for presence.
856
+ */
857
+ extraction: Record<string, unknown>;
858
+ /** ISO-8601. */
859
+ occurredAt: string;
860
+ }
861
+ /**
862
+ * A call reached a channel and nothing answered it.
863
+ *
864
+ * Its own event rather than an `outcome` on the one above, because the action
865
+ * differs in kind: a completed call is something to file, a missed one is
866
+ * somebody to ring back. Treating this as a lead is the right thing to do
867
+ * with it.
868
+ */
869
+ export interface CallMissedEvent {
870
+ workspaceId: string;
871
+ callId: string;
872
+ channelId: string | null;
873
+ /** E.164, and the only identity this carries - see `CallCompletedEvent.contactPhone`. */
874
+ contactPhone: string | null;
875
+ direction: ConnectCallDirection;
876
+ /** ISO-8601. */
877
+ occurredAt: string;
878
+ }
879
+ /**
880
+ * An appointment was booked and is holding its slot.
881
+ *
882
+ * Raised however it was booked - the customer's portal, the public booking
883
+ * page, a voice agent mid-call, or your own API call - so you get one shape
884
+ * for all four and never have to reconcile "did we create this, or did they?".
885
+ * Dedupe on `bookingId`, not on the envelope alone.
886
+ */
887
+ export interface BookingConfirmedEvent {
888
+ workspaceId: string;
889
+ bookingId: string;
890
+ eventTypeId: string;
891
+ eventTypeName: string;
892
+ /** ISO-8601, UTC. Render it in `timezone`, which is the workspace's, not the viewer's. */
893
+ startAt: string;
894
+ endAt: string;
895
+ /** IANA zone the appointment was booked in. */
896
+ timezone: string;
897
+ attendeeName: string;
898
+ attendeeEmail: string | null;
899
+ /** E.164. */
900
+ attendeePhone: string | null;
901
+ contactId: string | null;
902
+ /** Connect user ids of the hosts. */
903
+ hostMemberIds: string[];
904
+ /** ISO-8601. */
905
+ occurredAt: string;
906
+ }
907
+ /** An appointment was cancelled. The slot is free and any prep against it is void. */
908
+ export interface BookingCancelledEvent {
909
+ workspaceId: string;
910
+ bookingId: string;
911
+ eventTypeId: string;
912
+ eventTypeName: string;
913
+ /** ISO-8601. The time it *was* going to happen. */
914
+ startAt: string;
915
+ attendeeName: string;
916
+ contactId: string | null;
917
+ /** ISO-8601. */
918
+ occurredAt: string;
919
+ }
920
+ /**
921
+ * An appointment moved.
922
+ *
923
+ * Connect retires the old booking and writes a new one rather than mutating
924
+ * it, so this carries **both ids**: `bookingId` is the row that now exists and
925
+ * `previousBookingId` is the one you are already holding. Reconcile on the
926
+ * previous id or you will end up with two appointments.
927
+ */
928
+ export interface BookingRescheduledEvent {
929
+ workspaceId: string;
930
+ bookingId: string;
931
+ eventTypeId: string;
932
+ eventTypeName: string;
933
+ /** ISO-8601, the new time. */
934
+ startAt: string;
935
+ endAt: string;
936
+ previousBookingId: string;
937
+ /** ISO-8601, the time it was before. */
938
+ previousStartAt: string;
939
+ timezone: string;
940
+ attendeeName: string;
941
+ contactId: string | null;
942
+ /** ISO-8601. */
943
+ occurredAt: string;
944
+ }
945
+ /**
946
+ * How Connect came to know a contact.
947
+ *
948
+ * `extraction` is the interesting one: an agent's skill captured them from
949
+ * what was said, with nobody typing anything. `call` means the number was seen
950
+ * on a call. `manual` and `import` are the two a human stands behind, and
951
+ * Connect lets only those overwrite a field that already has a value.
952
+ */
953
+ export type ConnectContactSource = "call" | "manual" | "import" | "api" | "extraction";
954
+ /**
955
+ * Connect learned about a person.
956
+ *
957
+ * The event with no equivalent anywhere else in this API: most often an agent
958
+ * captured them mid-call through the `contact-capture` skill, so the contact
959
+ * exists in Connect and your product has never heard of them. Without this the
960
+ * capture is invisible where the customer actually works.
961
+ */
962
+ export interface ContactCreatedEvent {
963
+ workspaceId: string;
964
+ contactId: string;
965
+ name: string | null;
966
+ /** E.164. */
967
+ phone: string | null;
968
+ email: string | null;
969
+ company: string | null;
970
+ source: ConnectContactSource;
971
+ /** ISO-8601. */
972
+ occurredAt: string;
973
+ }
974
+ /**
975
+ * A known contact's details changed.
976
+ *
977
+ * `changed` names the fields that actually moved, so you can apply a patch
978
+ * rather than overwriting fields your own users may have curated - a customer
979
+ * who corrected a company name in your product should not have it replaced by
980
+ * what an agent heard over a bad line.
981
+ */
982
+ export interface ContactUpdatedEvent {
983
+ workspaceId: string;
984
+ contactId: string;
985
+ name: string | null;
986
+ /** E.164. */
987
+ phone: string | null;
988
+ email: string | null;
989
+ company: string | null;
990
+ /** The field names that changed on this update. */
991
+ changed: string[];
992
+ source: ConnectContactSource;
993
+ /** ISO-8601. */
994
+ occurredAt: string;
995
+ }
818
996
  /** Maps each event type to the shape of its `data`. */
819
997
  export interface ConnectWebhookEventMap {
820
998
  "workspace.deletion_scheduled": WorkspaceDeletionScheduledEvent;
821
999
  "workspace.deletion_cancelled": WorkspaceDeletionCancelledEvent;
822
1000
  "workspace.deleted": WorkspaceDeletedEvent;
823
1001
  "subscription.cancelled": SubscriptionCancelledEvent;
1002
+ "call.completed": CallCompletedEvent;
1003
+ "call.missed": CallMissedEvent;
1004
+ "booking.confirmed": BookingConfirmedEvent;
1005
+ "booking.cancelled": BookingCancelledEvent;
1006
+ "booking.rescheduled": BookingRescheduledEvent;
1007
+ "contact.created": ContactCreatedEvent;
1008
+ "contact.updated": ContactUpdatedEvent;
824
1009
  }
825
1010
  /** The envelope, as it arrives on the wire. */
826
1011
  export interface ConnectWebhookEnvelope<T extends ConnectWebhookEventType = ConnectWebhookEventType> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmoops/connect-sdk",
3
- "version": "0.27.0",
3
+ "version": "0.28.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",