@cosmoops/connect-sdk 0.47.0 → 0.48.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 +18 -0
- package/dist/cjs/client/components/call-button.js +3 -2
- package/dist/cjs/server/client.js +1 -1
- package/dist/cjs/server/handler.js +6 -1
- package/dist/cjs/server/resources/calls.js +3 -2
- package/dist/esm/client/components/call-button.js +3 -2
- package/dist/esm/server/client.js +1 -1
- package/dist/esm/server/handler.js +6 -1
- package/dist/esm/server/resources/calls.js +3 -2
- package/dist/types/client/components/call-button.d.ts +7 -2
- package/dist/types/server/client.d.ts +1 -1
- package/dist/types/server/resources/calls.d.ts +4 -2
- package/dist/types/types.d.ts +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
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.48.0
|
|
7
|
+
|
|
8
|
+
### Calls declare a purpose
|
|
9
|
+
|
|
10
|
+
`<ConnectCallButton purpose="promotional">`, `startCall({ phone, purpose })`
|
|
11
|
+
and `connect.calls.startBrowserCall({ phone, asUser, purpose })` take an
|
|
12
|
+
optional `ConnectCallPurpose` - `"service"`, `"transactional"` or
|
|
13
|
+
`"promotional"`. Connect records it on the call and places the call from a
|
|
14
|
+
workspace number allowed to carry it: in India a regular number carries
|
|
15
|
+
service and transactional calls only, and promotional calls need a 140-series
|
|
16
|
+
number with an approved DLT header. Omit it and the call is placed as before.
|
|
17
|
+
|
|
18
|
+
While the workspace's Connect deployment runs `CALL_PURPOSE_ENFORCEMENT=shadow`
|
|
19
|
+
(the default), a call no number may carry is still placed and only logged;
|
|
20
|
+
under `enforce` it is refused with a `412` whose message names the number
|
|
21
|
+
series needed. The bridge drops a purpose that is not one of the three
|
|
22
|
+
rather than forwarding it to be refused.
|
|
23
|
+
|
|
6
24
|
## 0.47.0
|
|
7
25
|
|
|
8
26
|
### `connect.integrations.request()` reaches the endpoints a toolkit has no action for
|
|
@@ -243,6 +243,7 @@ function ConnectCallProvider({ children, onCallEnded, onError, className, }) {
|
|
|
243
243
|
const client = await signIn();
|
|
244
244
|
const started = await mutateResource("/calls/start", {
|
|
245
245
|
phone: target.phone,
|
|
246
|
+
...(target.purpose ? { purpose: target.purpose } : {}),
|
|
246
247
|
});
|
|
247
248
|
callIdRef.current = started.callId;
|
|
248
249
|
setCall((current) => current ? { ...current, callId: started.callId, number: started.toNumber } : current);
|
|
@@ -308,9 +309,9 @@ function ConnectCallProvider({ children, onCallEnded, onError, className, }) {
|
|
|
308
309
|
* above it, and a member with "Make calls" - render it only for them, since a
|
|
309
310
|
* button the server refuses for everyone else helps nobody.
|
|
310
311
|
*/
|
|
311
|
-
function ConnectCallButton({ phone, name, onEnded, variant = "default", children, isDisabled, className, }) {
|
|
312
|
+
function ConnectCallButton({ phone, name, purpose, onEnded, variant = "default", children, isDisabled, className, }) {
|
|
312
313
|
const { isBusy, startCall, availability } = useConnectCall();
|
|
313
|
-
const press = () => void startCall({ phone, name, onEnded });
|
|
314
|
+
const press = () => void startCall({ phone, name, purpose, onEnded });
|
|
314
315
|
// Not offered at all to someone who may not call - a button that always
|
|
315
316
|
// refuses helps nobody.
|
|
316
317
|
if (availability?.status === "no_permission")
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createConnectHandler = createConnectHandler;
|
|
4
4
|
const errors_js_1 = require("../errors.js");
|
|
5
5
|
const identity_js_1 = require("./resources/identity.js");
|
|
6
|
+
/** The purposes `/calls/start` accepts - see `ConnectCallPurpose`. */
|
|
7
|
+
const CALL_PURPOSES = ["service", "transactional", "promotional"];
|
|
6
8
|
/**
|
|
7
9
|
* A sentinel origin to resolve a candidate destination against. Never reached -
|
|
8
10
|
* `.invalid` is reserved by RFC 2606 precisely so it cannot resolve.
|
|
@@ -1260,7 +1262,10 @@ function createConnectHandler(options) {
|
|
|
1260
1262
|
endpoint: "/calls/start",
|
|
1261
1263
|
});
|
|
1262
1264
|
}
|
|
1263
|
-
|
|
1265
|
+
// Passed on only when it is one of the three - Connect validates it
|
|
1266
|
+
// again, and an unknown value is dropped rather than sent to be refused.
|
|
1267
|
+
const purpose = CALL_PURPOSES.find((value) => value === body.purpose);
|
|
1268
|
+
return json(await client.calls.startBrowserCall({ phone: body.phone, asUser, purpose }), 201);
|
|
1264
1269
|
},
|
|
1265
1270
|
"POST /calls/cancel": async (request) => {
|
|
1266
1271
|
await requireWorkspace(request);
|
|
@@ -118,13 +118,14 @@ class CallsResource {
|
|
|
118
118
|
*
|
|
119
119
|
* Throws `ConnectError` with status `412` when the workspace has no active
|
|
120
120
|
* number, is not allowed to place calls, or the member is already on one -
|
|
121
|
-
* the message is written to be shown to them.
|
|
121
|
+
* the message is written to be shown to them. With a `purpose`, also when
|
|
122
|
+
* no number may carry it and the workspace enforces purposes.
|
|
122
123
|
*/
|
|
123
124
|
startBrowserCall(input) {
|
|
124
125
|
return (0, http_js_1.request)(this.transport, {
|
|
125
126
|
method: "POST",
|
|
126
127
|
path: "/calls/start",
|
|
127
|
-
json: { phone: input.phone },
|
|
128
|
+
json: input.purpose ? { phone: input.phone, purpose: input.purpose } : { phone: input.phone },
|
|
128
129
|
headers: (0, acting_as_js_1.actingAs)(input.asUser),
|
|
129
130
|
});
|
|
130
131
|
}
|
|
@@ -203,6 +203,7 @@ export function ConnectCallProvider({ children, onCallEnded, onError, className,
|
|
|
203
203
|
const client = await signIn();
|
|
204
204
|
const started = await mutateResource("/calls/start", {
|
|
205
205
|
phone: target.phone,
|
|
206
|
+
...(target.purpose ? { purpose: target.purpose } : {}),
|
|
206
207
|
});
|
|
207
208
|
callIdRef.current = started.callId;
|
|
208
209
|
setCall((current) => current ? { ...current, callId: started.callId, number: started.toNumber } : current);
|
|
@@ -268,9 +269,9 @@ export function ConnectCallProvider({ children, onCallEnded, onError, className,
|
|
|
268
269
|
* above it, and a member with "Make calls" - render it only for them, since a
|
|
269
270
|
* button the server refuses for everyone else helps nobody.
|
|
270
271
|
*/
|
|
271
|
-
export function ConnectCallButton({ phone, name, onEnded, variant = "default", children, isDisabled, className, }) {
|
|
272
|
+
export function ConnectCallButton({ phone, name, purpose, onEnded, variant = "default", children, isDisabled, className, }) {
|
|
272
273
|
const { isBusy, startCall, availability } = useConnectCall();
|
|
273
|
-
const press = () => void startCall({ phone, name, onEnded });
|
|
274
|
+
const press = () => void startCall({ phone, name, purpose, onEnded });
|
|
274
275
|
// Not offered at all to someone who may not call - a button that always
|
|
275
276
|
// refuses helps nobody.
|
|
276
277
|
if (availability?.status === "no_permission")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ConnectError } from "../errors.js";
|
|
2
2
|
import { createPkcePair, createState } from "./resources/identity.js";
|
|
3
|
+
/** The purposes `/calls/start` accepts - see `ConnectCallPurpose`. */
|
|
4
|
+
const CALL_PURPOSES = ["service", "transactional", "promotional"];
|
|
3
5
|
/**
|
|
4
6
|
* A sentinel origin to resolve a candidate destination against. Never reached -
|
|
5
7
|
* `.invalid` is reserved by RFC 2606 precisely so it cannot resolve.
|
|
@@ -1257,7 +1259,10 @@ export function createConnectHandler(options) {
|
|
|
1257
1259
|
endpoint: "/calls/start",
|
|
1258
1260
|
});
|
|
1259
1261
|
}
|
|
1260
|
-
|
|
1262
|
+
// Passed on only when it is one of the three - Connect validates it
|
|
1263
|
+
// again, and an unknown value is dropped rather than sent to be refused.
|
|
1264
|
+
const purpose = CALL_PURPOSES.find((value) => value === body.purpose);
|
|
1265
|
+
return json(await client.calls.startBrowserCall({ phone: body.phone, asUser, purpose }), 201);
|
|
1261
1266
|
},
|
|
1262
1267
|
"POST /calls/cancel": async (request) => {
|
|
1263
1268
|
await requireWorkspace(request);
|
|
@@ -115,13 +115,14 @@ export class CallsResource {
|
|
|
115
115
|
*
|
|
116
116
|
* Throws `ConnectError` with status `412` when the workspace has no active
|
|
117
117
|
* number, is not allowed to place calls, or the member is already on one -
|
|
118
|
-
* the message is written to be shown to them.
|
|
118
|
+
* the message is written to be shown to them. With a `purpose`, also when
|
|
119
|
+
* no number may carry it and the workspace enforces purposes.
|
|
119
120
|
*/
|
|
120
121
|
startBrowserCall(input) {
|
|
121
122
|
return request(this.transport, {
|
|
122
123
|
method: "POST",
|
|
123
124
|
path: "/calls/start",
|
|
124
|
-
json: { phone: input.phone },
|
|
125
|
+
json: input.purpose ? { phone: input.phone, purpose: input.purpose } : { phone: input.phone },
|
|
125
126
|
headers: actingAs(input.asUser),
|
|
126
127
|
});
|
|
127
128
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import type { CallingAvailability } from "../../types.js";
|
|
2
|
+
import type { CallingAvailability, ConnectCallPurpose } from "../../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Calling from the browser, through the workspace's own number.
|
|
5
5
|
*
|
|
@@ -60,6 +60,11 @@ export interface ConnectCallTarget {
|
|
|
60
60
|
phone: string;
|
|
61
61
|
/** Shown on the in-call bar. Defaults to the number. */
|
|
62
62
|
name?: string;
|
|
63
|
+
/**
|
|
64
|
+
* What the call is for - Connect places it from a number allowed to carry
|
|
65
|
+
* it. See `ConnectCallPurpose`; omit it to place the call as before.
|
|
66
|
+
*/
|
|
67
|
+
purpose?: ConnectCallPurpose;
|
|
63
68
|
/**
|
|
64
69
|
* Called once the call is over, with Connect's id for it - or `null` when it
|
|
65
70
|
* never got as far as being approved. Read the outcome on your server with
|
|
@@ -118,7 +123,7 @@ export interface ConnectCallButtonProps extends ConnectCallTarget {
|
|
|
118
123
|
* above it, and a member with "Make calls" - render it only for them, since a
|
|
119
124
|
* button the server refuses for everyone else helps nobody.
|
|
120
125
|
*/
|
|
121
|
-
export declare function ConnectCallButton({ phone, name, onEnded, variant, children, isDisabled, className, }: ConnectCallButtonProps): import("react").JSX.Element | null;
|
|
126
|
+
export declare function ConnectCallButton({ phone, name, purpose, onEnded, variant, children, isDisabled, className, }: ConnectCallButtonProps): import("react").JSX.Element | null;
|
|
122
127
|
export interface ConnectCallingStatusProps {
|
|
123
128
|
/** Merged with `cn`. */
|
|
124
129
|
className?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type TransportOptions } from "../http.js";
|
|
2
|
-
import type { BrowserCallingToken, CallingAvailability, CallSettings, CallDetail, CallsPage, StartedBrowserCall } from "../../types.js";
|
|
2
|
+
import type { BrowserCallingToken, CallingAvailability, CallSettings, CallDetail, CallsPage, ConnectCallPurpose, 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;
|
|
@@ -84,11 +84,13 @@ export declare class CallsResource {
|
|
|
84
84
|
*
|
|
85
85
|
* Throws `ConnectError` with status `412` when the workspace has no active
|
|
86
86
|
* number, is not allowed to place calls, or the member is already on one -
|
|
87
|
-
* the message is written to be shown to them.
|
|
87
|
+
* the message is written to be shown to them. With a `purpose`, also when
|
|
88
|
+
* no number may carry it and the workspace enforces purposes.
|
|
88
89
|
*/
|
|
89
90
|
startBrowserCall(input: {
|
|
90
91
|
phone: string;
|
|
91
92
|
asUser: string;
|
|
93
|
+
purpose?: ConnectCallPurpose;
|
|
92
94
|
}): Promise<StartedBrowserCall>;
|
|
93
95
|
/**
|
|
94
96
|
* Closes a call the browser never managed to place - recorded as
|
package/dist/types/types.d.ts
CHANGED
|
@@ -2911,6 +2911,14 @@ export interface ConnectCallAnalysis {
|
|
|
2911
2911
|
* carry a one-time key, valid for two minutes, that lets the call be placed
|
|
2912
2912
|
* once and by nobody else.
|
|
2913
2913
|
*/
|
|
2914
|
+
/**
|
|
2915
|
+
* What a call is for, declared by the caller - Connect places it from a
|
|
2916
|
+
* workspace number allowed to carry it. In India the series decides: regular
|
|
2917
|
+
* numbers carry `service` and `transactional`, 140-series numbers carry
|
|
2918
|
+
* `promotional` only. Omit it and the call is placed as before and recorded
|
|
2919
|
+
* as undeclared.
|
|
2920
|
+
*/
|
|
2921
|
+
export type ConnectCallPurpose = "service" | "transactional" | "promotional";
|
|
2914
2922
|
export interface StartedBrowserCall {
|
|
2915
2923
|
callId: string;
|
|
2916
2924
|
/** The number being rung, E.164. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmoops/connect-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.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",
|