@cosmoops/connect-sdk 0.40.0 → 0.42.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 +124 -0
- package/dist/cjs/client/components/access-gate.js +18 -40
- package/dist/cjs/client/components/apps-grid.js +11 -3
- package/dist/cjs/client/components/ask-ai-errors.js +109 -0
- package/dist/cjs/client/components/ask-ai-turns.js +12 -0
- package/dist/cjs/client/components/ask-ai.js +75 -8
- package/dist/cjs/client/components/call-button.js +398 -0
- package/dist/cjs/client/components/plans.js +8 -2
- package/dist/cjs/client/components/readiness.js +2 -1
- package/dist/cjs/client/components/subscription.js +4 -4
- package/dist/cjs/client/components/user-menu.js +16 -11
- package/dist/cjs/client/handoff.js +78 -0
- package/dist/cjs/client/index.js +15 -7
- package/dist/cjs/client/portal-links.js +1 -1
- package/dist/cjs/client/provider.js +75 -4
- package/dist/cjs/client/use-checkout.js +23 -16
- package/dist/cjs/server/client.js +5 -1
- package/dist/cjs/server/handler.js +77 -1
- package/dist/cjs/server/resources/calls.js +58 -0
- package/dist/cjs/server/resources/identity.js +12 -0
- package/dist/cjs/server/resources/whatsapp.js +58 -0
- package/dist/esm/client/components/access-gate.js +18 -40
- package/dist/esm/client/components/apps-grid.js +11 -3
- package/dist/esm/client/components/ask-ai-errors.js +102 -0
- package/dist/esm/client/components/ask-ai-turns.js +12 -0
- package/dist/esm/client/components/ask-ai.js +76 -9
- package/dist/esm/client/components/call-button.js +358 -0
- package/dist/esm/client/components/plans.js +8 -2
- package/dist/esm/client/components/readiness.js +2 -1
- package/dist/esm/client/components/subscription.js +4 -4
- package/dist/esm/client/components/user-menu.js +16 -11
- package/dist/esm/client/handoff.js +72 -0
- package/dist/esm/client/index.js +6 -4
- package/dist/esm/client/portal-links.js +1 -1
- package/dist/esm/client/provider.js +75 -4
- package/dist/esm/client/use-checkout.js +23 -16
- package/dist/esm/server/client.js +5 -1
- package/dist/esm/server/handler.js +77 -1
- package/dist/esm/server/resources/calls.js +58 -0
- package/dist/esm/server/resources/identity.js +12 -0
- package/dist/esm/server/resources/whatsapp.js +54 -0
- package/dist/types/client/components/ask-ai-errors.d.ts +41 -0
- package/dist/types/client/components/ask-ai-turns.d.ts +5 -0
- package/dist/types/client/components/call-button.d.ts +132 -0
- package/dist/types/client/handoff.d.ts +62 -0
- package/dist/types/client/index.d.ts +5 -1
- package/dist/types/client/portal-links.d.ts +1 -1
- package/dist/types/client/provider.d.ts +72 -5
- package/dist/types/client/use-checkout.d.ts +4 -1
- package/dist/types/server/client.d.ts +4 -1
- package/dist/types/server/resources/calls.d.ts +32 -1
- package/dist/types/server/resources/identity.d.ts +10 -0
- package/dist/types/server/resources/whatsapp.d.ts +44 -0
- package/dist/types/types.d.ts +152 -1
- package/package.json +4 -1
|
@@ -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,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hand-off contract with Connect's portal - the pure half, so the rules
|
|
3
|
+
* can be tested without a browser. `openConnect` (on `useConnect()`) is the
|
|
4
|
+
* half that touches `window`.
|
|
5
|
+
*
|
|
6
|
+
* Every time this SDK sends somebody to Connect for a task - a plan, a
|
|
7
|
+
* payment method, their profile - it appends three params, and Connect's
|
|
8
|
+
* portal brings them back when the task is done:
|
|
9
|
+
*
|
|
10
|
+
* | Param | |
|
|
11
|
+
* |---|---|
|
|
12
|
+
* | `client_id` | Names this application. Connect only honours a `return_to` whose origin is registered for that client. |
|
|
13
|
+
* | `return_to` | The page they left. |
|
|
14
|
+
* | `mode` | `popup` - Connect closes its window when done and posts the outcome to this page first. `redirect` - Connect navigates back here with `?connect_result=`. |
|
|
15
|
+
*/
|
|
16
|
+
/** How this application sends people to Connect - see `ConnectProviderProps.handoff`. */
|
|
17
|
+
export type ConnectHandoffMode = "popup" | "redirect";
|
|
18
|
+
/**
|
|
19
|
+
* How a trip to Connect ended, as Connect reports it.
|
|
20
|
+
*
|
|
21
|
+
* Advisory. A payment confirmed by webhook can settle a moment after the
|
|
22
|
+
* window has closed, so `"completed"` means "they finished there", not "it is
|
|
23
|
+
* live" - re-read entitlements for that. The provider already does, for every
|
|
24
|
+
* hand-off.
|
|
25
|
+
*/
|
|
26
|
+
export type ConnectHandoffResult = "completed" | "cancelled" | "closed";
|
|
27
|
+
/** `MessageEvent.data.type` of the message Connect posts before closing a popup. */
|
|
28
|
+
export declare const CONNECT_HANDOFF_MESSAGE_TYPE = "connect:handoff";
|
|
29
|
+
/** The query param Connect adds when it redirects back. */
|
|
30
|
+
export declare const CONNECT_HANDOFF_RESULT_PARAM = "connect_result";
|
|
31
|
+
export interface HandoffUrlOptions {
|
|
32
|
+
appUrl: string;
|
|
33
|
+
/** Empty when neither the provider nor the bridge knows it - the URL still works, Connect just cannot offer the way back. */
|
|
34
|
+
clientId: string;
|
|
35
|
+
mode: ConnectHandoffMode;
|
|
36
|
+
/** The page to come back to - `window.location.href` at the moment of the press. */
|
|
37
|
+
returnTo: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* `target` - a path (`"/billing"`) or an absolute Connect URL (a readiness
|
|
41
|
+
* blocker's `resolveUrl`) - with the hand-off params set.
|
|
42
|
+
*
|
|
43
|
+
* Throws for a URL on any other origin: these params tell Connect where to
|
|
44
|
+
* send somebody back, and stamping them onto a third party's URL would hand
|
|
45
|
+
* that party the page this visitor was on.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildHandoffUrl(target: string, { appUrl, clientId, mode, returnTo }: HandoffUrlOptions): string;
|
|
48
|
+
/**
|
|
49
|
+
* The result a `message` event carries, or `null` when it is not Connect's
|
|
50
|
+
* hand-off message. The origin check is the whole security story: any page
|
|
51
|
+
* can `postMessage` this window, and only Connect's verdict may trigger work.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readHandoffMessage(event: Pick<MessageEvent, "origin" | "data">, appUrl: string): ConnectHandoffResult | null;
|
|
54
|
+
/**
|
|
55
|
+
* The result a redirect-mode return carries in `href`, and `href` with it
|
|
56
|
+
* removed - so a reload does not report the same trip twice and the param
|
|
57
|
+
* does not end up in a link somebody shares.
|
|
58
|
+
*/
|
|
59
|
+
export declare function takeHandoffResult(href: string): {
|
|
60
|
+
result: ConnectHandoffResult;
|
|
61
|
+
cleaned: string;
|
|
62
|
+
} | null;
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* change lands identically in all of them.
|
|
12
12
|
*/
|
|
13
13
|
export { ConnectProvider, useConnect, useConnectOptional, useConnectUser, useConnectWorkspaceType, useConnectAudience, useConnectPlatformAccess, useConnectEntitlements, useConnectPlans, useConnectApps, useConnectCompanyProfile, useConnectAddonUsage, useConnectSessions, useConnectIntegrations, useConnectResource, CONNECT_APP_URL, } from "./provider.js";
|
|
14
|
-
export type { ConnectProviderProps, ConnectContextValue, ConnectSession, ConnectOneTapHint, ConnectOneTapFailure, UseConnectResourceOptions, } from "./provider.js";
|
|
14
|
+
export type { ConnectProviderProps, ConnectContextValue, ConnectSession, ConnectOneTapHint, ConnectOneTapFailure, UseConnectResourceOptions, OpenConnectOptions, } from "./provider.js";
|
|
15
|
+
export type { ConnectHandoffMode, ConnectHandoffResult } from "./handoff.js";
|
|
16
|
+
export { CONNECT_HANDOFF_MESSAGE_TYPE, CONNECT_HANDOFF_RESULT_PARAM } from "./handoff.js";
|
|
15
17
|
export { blockingBlockers, normalizePlanFeatures } from "../helpers.js";
|
|
16
18
|
export type { WirePlanFeature } from "../helpers.js";
|
|
17
19
|
export { ConnectError, isConnectError } from "../errors.js";
|
|
@@ -106,6 +108,8 @@ export { ConnectCreateWorkspaceModal } from "./components/create-workspace-form.
|
|
|
106
108
|
export type { ConnectCreateWorkspaceModalProps } from "./components/create-workspace-form.js";
|
|
107
109
|
export { useCreateWorkspace } from "./use-workspaces.js";
|
|
108
110
|
export type { WorkspaceActionsState } from "./use-workspaces.js";
|
|
111
|
+
export { ConnectCallProvider, ConnectCallButton, ConnectCallingStatus, useConnectCall, } from "./components/call-button.js";
|
|
112
|
+
export type { ConnectCallProviderProps, ConnectCallButtonProps, ConnectCallTarget, ConnectCallContextValue, ConnectCallingStatusProps, } from "./components/call-button.js";
|
|
109
113
|
export { ConnectBookingCalendar } from "./components/booking-calendar.js";
|
|
110
114
|
export type { ConnectBookingCalendarProps } from "./components/booking-calendar.js";
|
|
111
115
|
export { ConnectBookingDialog, ConnectBookingDetail } from "./components/booking-dialogs.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,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import { type ConnectHandoffMode, type ConnectHandoffResult } from "./handoff.js";
|
|
2
3
|
import type { AddonUsageResponse, CompanyProfileResponse, ConnectUser, IntegrationsListResponse, WorkspaceApp, UserWorkspace, ConnectWorkspaceMember, PlansResponse, ReadinessResponse, SessionsListResponse, SessionSubscription, SessionAudience, SubscriptionResponse, WorkspaceType } from "../types.js";
|
|
3
4
|
export declare const CONNECT_APP_URL = "https://connect.cosmoops.com";
|
|
4
5
|
export interface ConnectSession {
|
|
@@ -32,6 +33,13 @@ export interface ConnectSession {
|
|
|
32
33
|
hintUrl: string;
|
|
33
34
|
authorizeUrl: string;
|
|
34
35
|
} | null;
|
|
36
|
+
/**
|
|
37
|
+
* This application's public `client_id`, from the bridge - so `openConnect`
|
|
38
|
+
* can name the application on a hand-off without `clientId` being passed to
|
|
39
|
+
* `<ConnectProvider>` as well. Optional because an older bridge will not
|
|
40
|
+
* send it; the provider's own `clientId` prop wins when both exist.
|
|
41
|
+
*/
|
|
42
|
+
clientId?: string | null;
|
|
35
43
|
}
|
|
36
44
|
/**
|
|
37
45
|
* What Connect says about the visitor, before anything has been signed.
|
|
@@ -68,14 +76,39 @@ export interface ConnectOneTapHint {
|
|
|
68
76
|
export type ConnectOneTapFailure = "unavailable" | "login_required" | "consent_required" | "interaction_required" | "rate_limited" | "failed";
|
|
69
77
|
export interface ConnectContextValue {
|
|
70
78
|
/**
|
|
71
|
-
* Public OAuth client id
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
79
|
+
* Public OAuth client id - the `clientId` passed to `<ConnectProvider>`,
|
|
80
|
+
* else the one your bridge reports on `/session`, else an empty string
|
|
81
|
+
* (an older bridge, before the session read settles). Safe in a browser
|
|
82
|
+
* regardless: it only ever goes into Connect URLs. Most integrations never
|
|
83
|
+
* read this - it exists for the explicit-`redirectUri` flow and for
|
|
84
|
+
* `connectPortalUrl`'s way back.
|
|
75
85
|
*/
|
|
76
86
|
clientId: string;
|
|
77
87
|
/** Connect's own origin, for deep links out to Profile, Billing and the catalog. */
|
|
78
88
|
appUrl: string;
|
|
89
|
+
/** How `openConnect` sends people to Connect - `ConnectProviderProps.handoff`, after defaulting. */
|
|
90
|
+
handoffMode: ConnectHandoffMode;
|
|
91
|
+
/**
|
|
92
|
+
* Sends the visitor to a Connect page for a task, and brings them back when
|
|
93
|
+
* it is done. **Call it from a press handler** - a popup opened after an
|
|
94
|
+
* `await` is what pop-up blockers exist to stop.
|
|
95
|
+
*
|
|
96
|
+
* `target` is a path (`"/billing"`) or an absolute Connect URL, such as a
|
|
97
|
+
* readiness blocker's `resolveUrl`. Anything on another origin throws.
|
|
98
|
+
*
|
|
99
|
+
* - `"popup"` mode opens Connect in a new tab (or a sized window, with
|
|
100
|
+
* `features`), which closes itself when the task is done and tells this
|
|
101
|
+
* page first - every Connect component on it then re-reads. Returns the
|
|
102
|
+
* window, for a caller that wants to watch it.
|
|
103
|
+
* - `"redirect"` mode, or a popup the browser blocked, navigates this tab
|
|
104
|
+
* to Connect, which navigates back with `?connect_result=`. Returns
|
|
105
|
+
* `null`; the page is going away.
|
|
106
|
+
*
|
|
107
|
+
* Either way the way back carries this page's URL and this application's
|
|
108
|
+
* `client_id`, and Connect only honours an origin registered for that
|
|
109
|
+
* client - register your app's origin among its redirect URIs.
|
|
110
|
+
*/
|
|
111
|
+
openConnect(target: string, options?: OpenConnectOptions): Window | null;
|
|
79
112
|
session: ConnectSession | null;
|
|
80
113
|
/** `true` until the first `/session` read settles. Render skeletons, not a Login button. */
|
|
81
114
|
isLoading: boolean;
|
|
@@ -178,6 +211,16 @@ export interface ConnectContextValue {
|
|
|
178
211
|
reason: ConnectOneTapFailure;
|
|
179
212
|
}>;
|
|
180
213
|
}
|
|
214
|
+
export interface OpenConnectOptions {
|
|
215
|
+
/**
|
|
216
|
+
* `window.open` features for a sized pop-up window instead of a tab -
|
|
217
|
+
* checkout uses `"popup,width=520,height=780"`. Must not include
|
|
218
|
+
* `noopener`: the window handle is how Connect reports back and closes.
|
|
219
|
+
*/
|
|
220
|
+
features?: string;
|
|
221
|
+
/** `window.open` target name. A second `openConnect` with the same name reuses that window. */
|
|
222
|
+
name?: string;
|
|
223
|
+
}
|
|
181
224
|
export interface ConnectProviderProps {
|
|
182
225
|
/**
|
|
183
226
|
* This application's public `client_id`, from its Connect client section in Connect.
|
|
@@ -241,6 +284,30 @@ export interface ConnectProviderProps {
|
|
|
241
284
|
* to your own `/signin`, which mints the `state` server-side.
|
|
242
285
|
*/
|
|
243
286
|
silentSignIn?: boolean;
|
|
287
|
+
/**
|
|
288
|
+
* How every Connect button in this package - Billing, Profile, Manage,
|
|
289
|
+
* checkout, a readiness blocker's fix - takes the visitor to Connect.
|
|
290
|
+
*
|
|
291
|
+
* - `"popup"` (the default): Connect opens in a new tab and **closes itself**
|
|
292
|
+
* when the task is done, telling this page first, so the visitor is back
|
|
293
|
+
* where they were with everything repainted. A blocked popup falls back
|
|
294
|
+
* to `"redirect"` rather than leaving them with nothing.
|
|
295
|
+
* - `"redirect"`: this tab goes to Connect and comes back. Prefer it for an
|
|
296
|
+
* installed PWA or an app inside an iframe, where a second tab is a
|
|
297
|
+
* different window the visitor may never find.
|
|
298
|
+
*
|
|
299
|
+
* Both need this app's origin registered among the client's redirect URIs
|
|
300
|
+
* in Connect - an unregistered origin still reaches Connect, it just gets no
|
|
301
|
+
* way back.
|
|
302
|
+
*/
|
|
303
|
+
handoff?: ConnectHandoffMode;
|
|
304
|
+
/**
|
|
305
|
+
* Told how each trip to Connect ended - from the popup's message, or from
|
|
306
|
+
* `?connect_result=` on the way back from a redirect (which the provider
|
|
307
|
+
* then strips from the address bar). The provider already re-reads the
|
|
308
|
+
* session and every Connect resource; this is for your own state.
|
|
309
|
+
*/
|
|
310
|
+
onHandoffResult?: (result: ConnectHandoffResult) => void;
|
|
244
311
|
children: ReactNode;
|
|
245
312
|
}
|
|
246
313
|
/**
|
|
@@ -257,7 +324,7 @@ export interface ConnectProviderProps {
|
|
|
257
324
|
* </ConnectProvider>
|
|
258
325
|
* ```
|
|
259
326
|
*/
|
|
260
|
-
export declare function ConnectProvider({ clientId, basePath, redirectUri, appUrl, fetch: fetchImpl, silentSignIn, children, }: ConnectProviderProps): import("react").JSX.Element;
|
|
327
|
+
export declare function ConnectProvider({ clientId, basePath, redirectUri, appUrl, fetch: fetchImpl, silentSignIn, handoff, onHandoffResult, children, }: ConnectProviderProps): import("react").JSX.Element;
|
|
261
328
|
export declare function useConnect(): ConnectContextValue;
|
|
262
329
|
/**
|
|
263
330
|
* The context when there is one, `null` when there is not.
|
|
@@ -9,7 +9,10 @@ import type { ReadinessResponse, SubscriptionResponse } from "../types.js";
|
|
|
9
9
|
* closing is not one.
|
|
10
10
|
* - `abandoned` - the window closed (or the deadline passed) with the
|
|
11
11
|
* entitlement unchanged.
|
|
12
|
-
* - `blocked` -
|
|
12
|
+
* - `blocked` - **no longer produced.** A blocked window now falls back to a
|
|
13
|
+
* same-tab trip to Connect and back (see `openConnect`), which reaches the
|
|
14
|
+
* same place without asking the customer to click a fallback link. Kept in
|
|
15
|
+
* the union so code that handles it still compiles.
|
|
13
16
|
*/
|
|
14
17
|
export type ConnectCheckoutStatus = "idle" | "waiting" | "completed" | "abandoned" | "blocked";
|
|
15
18
|
export interface ConnectCheckoutState {
|
|
@@ -23,6 +23,7 @@ import { SessionsResource } from "./resources/sessions.js";
|
|
|
23
23
|
import { PlatformResource } from "./resources/platform.js";
|
|
24
24
|
import { VisitorResource } from "./resources/visitor.js";
|
|
25
25
|
import { PushResource } from "./resources/push.js";
|
|
26
|
+
import { WhatsAppResource } from "./resources/whatsapp.js";
|
|
26
27
|
export declare const DEFAULT_BASE_URL = "https://connect.cosmoops.com";
|
|
27
28
|
export interface ConnectClientOptions {
|
|
28
29
|
/**
|
|
@@ -124,6 +125,8 @@ export declare class ConnectClient {
|
|
|
124
125
|
* preferences; you supply a title, a body and a URL. See `PushResource`.
|
|
125
126
|
*/
|
|
126
127
|
readonly push: PushResource;
|
|
128
|
+
/** Your application's own approved WhatsApp templates, to a workspace's customers. */
|
|
129
|
+
readonly whatsapp: WhatsAppResource;
|
|
127
130
|
/**
|
|
128
131
|
* Relays one `/data/*` or `/kv/*` request verbatim - `createConnectHandler`'s
|
|
129
132
|
* store route and nothing else. See `storePassthrough`.
|
|
@@ -138,4 +141,4 @@ export declare class ConnectClient {
|
|
|
138
141
|
constructor(options: ConnectClientOptions);
|
|
139
142
|
}
|
|
140
143
|
/** Kept in step with `package.json` by `sdk.test.ts`. */
|
|
141
|
-
export declare const SDK_VERSION = "0.
|
|
144
|
+
export declare const SDK_VERSION = "0.42.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
|
}
|
|
@@ -77,6 +77,16 @@ export declare class IdentityResource {
|
|
|
77
77
|
hintUrl: string;
|
|
78
78
|
authorizeUrl: string;
|
|
79
79
|
} | null;
|
|
80
|
+
/**
|
|
81
|
+
* This client's public `client_id`, or `null` when none is configured.
|
|
82
|
+
*
|
|
83
|
+
* The bridge hands it to the browser on `/session` so `openConnect` can name
|
|
84
|
+
* the application on every hand-off without the host passing `clientId` to
|
|
85
|
+
* `<ConnectProvider>` too - Connect only honours a `return_to` it can match
|
|
86
|
+
* against *a client's* registered redirect origins. Public by definition:
|
|
87
|
+
* it already rides on every authorize URL.
|
|
88
|
+
*/
|
|
89
|
+
publicClientId(): string | null;
|
|
80
90
|
/** Step 2 - trade the one-time `code` for a session. Server-side only. */
|
|
81
91
|
exchangeCode(input: ExchangeCodeInput): Promise<TokenResponse>;
|
|
82
92
|
/**
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type TransportOptions } from "../http.js";
|
|
2
|
+
import type { SendWhatsAppInput, SendWhatsAppResponse, WhatsAppTemplateState } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Your application's own WhatsApp templates, sent to a workspace's customers
|
|
5
|
+
* through Connect's WhatsApp sender - no WhatsApp Business account of your
|
|
6
|
+
* own.
|
|
7
|
+
*
|
|
8
|
+
* Templates are written and submitted to Meta in Console under your
|
|
9
|
+
* application; you name them here by slug and Connect resolves
|
|
10
|
+
* `app_<yourApplicationKey>_<slug>` from your key, so a key can never send
|
|
11
|
+
* another application's message or one of Connect's own. There is no free
|
|
12
|
+
* text: outside a customer's 24-hour window WhatsApp permits nothing else.
|
|
13
|
+
*
|
|
14
|
+
* Server-to-server only - there is no browser path, by design.
|
|
15
|
+
*/
|
|
16
|
+
export declare class WhatsAppResource {
|
|
17
|
+
private readonly transport;
|
|
18
|
+
constructor(transport: TransportOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Send one template to one customer.
|
|
21
|
+
*
|
|
22
|
+
* Refusals arrive as a `ConnectError` whose `code` says what to tell the
|
|
23
|
+
* person who pressed Send - `template_not_approved`, `consent_required`,
|
|
24
|
+
* `opted_out`, `not_found`. None of them is a fault worth retrying.
|
|
25
|
+
*
|
|
26
|
+
* An `Idempotency-Key` is always sent, as on `otp.send`: a retried send
|
|
27
|
+
* without one is a second message on somebody's phone. Pass your own -
|
|
28
|
+
* derived from what is being sent, e.g. the quote number - to make a
|
|
29
|
+
* retry from a *later* request safe too.
|
|
30
|
+
*/
|
|
31
|
+
send(input: SendWhatsAppInput, options?: {
|
|
32
|
+
idempotencyKey?: string;
|
|
33
|
+
}): Promise<SendWhatsAppResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Whether a template would send right now, and the values it needs.
|
|
36
|
+
*
|
|
37
|
+
* Ask before offering WhatsApp on a screen: Meta's approval takes minutes
|
|
38
|
+
* to days, and an approved template can be paused later. A `ConnectError`
|
|
39
|
+
* with `status: 404` means your application has no such template.
|
|
40
|
+
*/
|
|
41
|
+
template(slug: string, options?: {
|
|
42
|
+
language?: string;
|
|
43
|
+
}): Promise<WhatsAppTemplateState>;
|
|
44
|
+
}
|