@babelforce/babelconnect-sdk 0.11.0 → 0.12.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/README.md +5 -0
- package/dist/client.d.ts +46 -1
- package/dist/client.js +86 -2
- package/dist/embed/iife-entry.d.ts +32 -0
- package/dist/embed/iife-entry.js +28 -0
- package/dist/embed/index.d.ts +44 -4
- package/dist/embed/index.js +68 -16
- package/dist/gen/babelconnect/v1/babelconnect_connect.d.ts +49 -1
- package/dist/gen/babelconnect/v1/babelconnect_connect.js +49 -1
- package/dist/gen/babelconnect/v1/babelconnect_pb.d.ts +652 -1
- package/dist/gen/babelconnect/v1/babelconnect_pb.js +861 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web/babelconnect-embed.iife.js +1 -0
- package/package.json +4 -2
- package/CHANGELOG.md +0 -18
package/README.md
CHANGED
|
@@ -74,6 +74,11 @@ bc.calls.dial("+49301234567"); // click-to-dial from your CRM
|
|
|
74
74
|
bc.session.set({ number: "+49301234567" }); // correlate / prefill
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
No bundler? Load `<script src="https://agent.example.com/embed/babelconnect-embed.iife.js">` instead — it
|
|
78
|
+
defines `window.BabelconnectEmbed` with the same API, no `import` needed. See the
|
|
79
|
+
**[embedding guide](https://babelforce.github.io/babelconnect-sdk/docs/typescript/embedding)**, "Script tag
|
|
80
|
+
(no bundler)".
|
|
81
|
+
|
|
77
82
|
## API overview
|
|
78
83
|
|
|
79
84
|
| Area | Exports |
|
package/dist/client.d.ts
CHANGED
|
@@ -88,10 +88,18 @@ export declare class BabelconnectClient {
|
|
|
88
88
|
}): void;
|
|
89
89
|
/** Open a conference around the current call. `hold` parks that call while you add members and consult. */
|
|
90
90
|
startConference(hold?: boolean): void;
|
|
91
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Invite a participant — pass exactly one of `agentId` or `number`. Starts a
|
|
93
|
+
* conference first if none is active. `holdOthers` parks every other live
|
|
94
|
+
* member of the CURRENT conference before the invite goes out (CA4's "hold
|
|
95
|
+
* others" checkbox, default off) so they don't overhear the invitee
|
|
96
|
+
* ringing; the server unholds them again once the invitee joins or the
|
|
97
|
+
* invite fails.
|
|
98
|
+
*/
|
|
92
99
|
addConferenceMember(opts: {
|
|
93
100
|
agentId?: string;
|
|
94
101
|
number?: string;
|
|
102
|
+
holdOthers?: boolean;
|
|
95
103
|
}): void;
|
|
96
104
|
/** Remove a member from the conference (moderator only). */
|
|
97
105
|
kickConferenceMember(memberId: string): void;
|
|
@@ -103,6 +111,37 @@ export declare class BabelconnectClient {
|
|
|
103
111
|
endConference(): void;
|
|
104
112
|
/** Drop only the agent's own leg; the other members stay connected. */
|
|
105
113
|
leaveConference(): void;
|
|
114
|
+
/**
|
|
115
|
+
* Enter a campaign (the picker's "Enter"). `paused` false (default) starts
|
|
116
|
+
* the agent `waiting` for a lead right away; true enters already idle.
|
|
117
|
+
*/
|
|
118
|
+
joinCampaign(campaignId: string, paused?: boolean): void;
|
|
119
|
+
/** Exit the current campaign (selector row or in-call). */
|
|
120
|
+
leaveCampaign(): void;
|
|
121
|
+
/** Pause (`on` true) or resume (`on` false) the campaign. */
|
|
122
|
+
pauseCampaign(on: boolean): void;
|
|
123
|
+
/**
|
|
124
|
+
* List the active outbound-dialer campaigns the agent may join (the
|
|
125
|
+
* Outbound tab's campaign picker, OBDA1).
|
|
126
|
+
*/
|
|
127
|
+
listCampaigns(): Promise<import("./gen/babelconnect/v1/babelconnect_pb.js").Campaign[]>;
|
|
128
|
+
/**
|
|
129
|
+
* End the agent's live campaign call (OBDB2) — distinct from `hangup`: the
|
|
130
|
+
* backend both releases the Vicidial-side channel and drives the campaign
|
|
131
|
+
* member state to DISPOSITION.
|
|
132
|
+
*/
|
|
133
|
+
endCampaignCall(): void;
|
|
134
|
+
/**
|
|
135
|
+
* Record the outcome of a campaign call (OBDC1). `callbackDate` is ISO
|
|
136
|
+
* `YYYY-MM-DDTHH:mmZZ` and should be left empty except for the "callback"
|
|
137
|
+
* disposition (OBDC2).
|
|
138
|
+
*/
|
|
139
|
+
disposeCall(code: string, callbackDate?: string): void;
|
|
140
|
+
/**
|
|
141
|
+
* List the available call-outcome codes for the disposition picker
|
|
142
|
+
* (OBDC1) — a static global list, not campaign-scoped.
|
|
143
|
+
*/
|
|
144
|
+
listDispositions(): Promise<string[]>;
|
|
106
145
|
/** Add seconds to the after-call-work countdown (default 30). Show only when `wrapUp.canExtend`. */
|
|
107
146
|
wrapUpExtend(seconds?: number): void;
|
|
108
147
|
/** End after-call work early. Show only when `wrapUp.canCancel`. */
|
|
@@ -140,6 +179,12 @@ export declare class BabelconnectClient {
|
|
|
140
179
|
* `query` filters by label/number.
|
|
141
180
|
*/
|
|
142
181
|
getPhonebook(max?: number, page?: number, query?: string): Promise<import("./gen/babelconnect/v1/babelconnect_pb.js").PhonebookEntry[]>;
|
|
182
|
+
/**
|
|
183
|
+
* Autocomplete blind-transfer / add-member targets — agents, raw numbers,
|
|
184
|
+
* and IVR applications — as the caller types. `query` filters server-side;
|
|
185
|
+
* empty returns the default result set.
|
|
186
|
+
*/
|
|
187
|
+
getTransferTargets(query?: string): Promise<import("./gen/babelconnect/v1/babelconnect_pb.js").TransferTarget[]>;
|
|
143
188
|
/** Tear down media legs and the connection. */
|
|
144
189
|
close(): Promise<void>;
|
|
145
190
|
private runSubscribe;
|
package/dist/client.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createClient, } from "@connectrpc/connect";
|
|
|
2
2
|
import { createGrpcWebTransport } from "@connectrpc/connect-web";
|
|
3
3
|
import { SDK_VERSION } from "./version.js";
|
|
4
4
|
import { Agent } from "./gen/babelconnect/v1/babelconnect_connect.js";
|
|
5
|
-
import { AddConferenceMember, AnswerCall, CallDirection, CallLifecycle, CallSource, Command, EndConference, Error as BcError, FlagRecording, Hangup, HistoryRequest, SmsThreadRequest, PhonebookRequest, HoldConferenceMember, Hold, KickConferenceMember, LeaveConference, MarkConversationRead, Mute, MuteConferenceMember, PlaceCall, Pong, Register, ResetLineStatus, SendDigits, SendSmsRequest, SetAgentNumber, SetConversationOpen, SetDisplayAs, SetPresence, SetWebrtc, StartConference, StartRecording, StopRecording, SetRecordingTags, SubscribeRequest, Transfer, WrapUpCancel, WrapUpExtend, } from "./gen/babelconnect/v1/babelconnect_pb.js";
|
|
5
|
+
import { AddConferenceMember, AnswerCall, CallDirection, CallLifecycle, CallSource, Command, DisposeCall, EndCampaignCall, EndConference, Error as BcError, FlagRecording, Hangup, HistoryRequest, SmsThreadRequest, PhonebookRequest, HoldConferenceMember, Hold, JoinCampaign, KickConferenceMember, LeaveCampaign, LeaveConference, ListCampaignsRequest, ListDispositionsRequest, MarkConversationRead, Mute, MuteConferenceMember, PauseCampaign, PlaceCall, Pong, Register, ResetLineStatus, SendDigits, SendSmsRequest, SetAgentNumber, SetConversationOpen, SetDisplayAs, SetPresence, SetWebrtc, StartConference, StartRecording, StopRecording, SetRecordingTags, SubscribeRequest, Transfer, TransferTargetsRequest, WrapUpCancel, WrapUpExtend, } from "./gen/babelconnect/v1/babelconnect_pb.js";
|
|
6
6
|
import { browserMediaFactory, MediaError, toRTCIceServers, } from "./media.js";
|
|
7
7
|
import { StateCache } from "./state-cache.js";
|
|
8
8
|
/**
|
|
@@ -151,7 +151,14 @@ export class BabelconnectClient {
|
|
|
151
151
|
},
|
|
152
152
|
}));
|
|
153
153
|
}
|
|
154
|
-
/**
|
|
154
|
+
/**
|
|
155
|
+
* Invite a participant — pass exactly one of `agentId` or `number`. Starts a
|
|
156
|
+
* conference first if none is active. `holdOthers` parks every other live
|
|
157
|
+
* member of the CURRENT conference before the invite goes out (CA4's "hold
|
|
158
|
+
* others" checkbox, default off) so they don't overhear the invitee
|
|
159
|
+
* ringing; the server unholds them again once the invitee joins or the
|
|
160
|
+
* invite fails.
|
|
161
|
+
*/
|
|
155
162
|
addConferenceMember(opts) {
|
|
156
163
|
this.send(new Command({
|
|
157
164
|
command: {
|
|
@@ -159,6 +166,7 @@ export class BabelconnectClient {
|
|
|
159
166
|
value: new AddConferenceMember({
|
|
160
167
|
agentId: opts.agentId ?? "",
|
|
161
168
|
number: opts.number ?? "",
|
|
169
|
+
holdOthers: opts.holdOthers ?? false,
|
|
162
170
|
}),
|
|
163
171
|
},
|
|
164
172
|
}));
|
|
@@ -202,6 +210,73 @@ export class BabelconnectClient {
|
|
|
202
210
|
command: { case: "leaveConference", value: new LeaveConference({}) },
|
|
203
211
|
}));
|
|
204
212
|
}
|
|
213
|
+
// --- Outbound dialer (campaign mode, OBDA1–3) ---
|
|
214
|
+
/**
|
|
215
|
+
* Enter a campaign (the picker's "Enter"). `paused` false (default) starts
|
|
216
|
+
* the agent `waiting` for a lead right away; true enters already idle.
|
|
217
|
+
*/
|
|
218
|
+
joinCampaign(campaignId, paused = false) {
|
|
219
|
+
this.send(new Command({
|
|
220
|
+
command: {
|
|
221
|
+
case: "joinCampaign",
|
|
222
|
+
value: new JoinCampaign({ campaignId, paused }),
|
|
223
|
+
},
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
/** Exit the current campaign (selector row or in-call). */
|
|
227
|
+
leaveCampaign() {
|
|
228
|
+
this.send(new Command({
|
|
229
|
+
command: { case: "leaveCampaign", value: new LeaveCampaign({}) },
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
232
|
+
/** Pause (`on` true) or resume (`on` false) the campaign. */
|
|
233
|
+
pauseCampaign(on) {
|
|
234
|
+
this.send(new Command({
|
|
235
|
+
command: { case: "pauseCampaign", value: new PauseCampaign({ on }) },
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* List the active outbound-dialer campaigns the agent may join (the
|
|
240
|
+
* Outbound tab's campaign picker, OBDA1).
|
|
241
|
+
*/
|
|
242
|
+
async listCampaigns() {
|
|
243
|
+
const resp = await this.rpc.listCampaigns(new ListCampaignsRequest({}));
|
|
244
|
+
return resp.campaigns;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* End the agent's live campaign call (OBDB2) — distinct from `hangup`: the
|
|
248
|
+
* backend both releases the Vicidial-side channel and drives the campaign
|
|
249
|
+
* member state to DISPOSITION.
|
|
250
|
+
*/
|
|
251
|
+
endCampaignCall() {
|
|
252
|
+
this.send(new Command({
|
|
253
|
+
command: {
|
|
254
|
+
case: "endCampaignCall",
|
|
255
|
+
value: new EndCampaignCall({}),
|
|
256
|
+
},
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Record the outcome of a campaign call (OBDC1). `callbackDate` is ISO
|
|
261
|
+
* `YYYY-MM-DDTHH:mmZZ` and should be left empty except for the "callback"
|
|
262
|
+
* disposition (OBDC2).
|
|
263
|
+
*/
|
|
264
|
+
disposeCall(code, callbackDate = "") {
|
|
265
|
+
this.send(new Command({
|
|
266
|
+
command: {
|
|
267
|
+
case: "disposeCall",
|
|
268
|
+
value: new DisposeCall({ code, callbackDate }),
|
|
269
|
+
},
|
|
270
|
+
}));
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* List the available call-outcome codes for the disposition picker
|
|
274
|
+
* (OBDC1) — a static global list, not campaign-scoped.
|
|
275
|
+
*/
|
|
276
|
+
async listDispositions() {
|
|
277
|
+
const resp = await this.rpc.listDispositions(new ListDispositionsRequest({}));
|
|
278
|
+
return resp.reasons;
|
|
279
|
+
}
|
|
205
280
|
/** Add seconds to the after-call-work countdown (default 30). Show only when `wrapUp.canExtend`. */
|
|
206
281
|
wrapUpExtend(seconds = 30) {
|
|
207
282
|
this.send(new Command({
|
|
@@ -322,6 +397,15 @@ export class BabelconnectClient {
|
|
|
322
397
|
const resp = await this.rpc.getPhonebook(new PhonebookRequest({ max, page, query }));
|
|
323
398
|
return resp.entries;
|
|
324
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Autocomplete blind-transfer / add-member targets — agents, raw numbers,
|
|
402
|
+
* and IVR applications — as the caller types. `query` filters server-side;
|
|
403
|
+
* empty returns the default result set.
|
|
404
|
+
*/
|
|
405
|
+
async getTransferTargets(query = "") {
|
|
406
|
+
const resp = await this.rpc.getTransferTargets(new TransferTargetsRequest({ query }));
|
|
407
|
+
return resp.targets;
|
|
408
|
+
}
|
|
325
409
|
/** Tear down media legs and the connection. */
|
|
326
410
|
async close() {
|
|
327
411
|
this.closed = true;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script-tag build entry (EMB21) — bundled by esbuild (not `tsc`, which only emits
|
|
3
|
+
* the ESM `dist/embed/index.js`) into a self-contained IIFE at
|
|
4
|
+
* `dist/web/babelconnect-embed.iife.js`, for CRM hosts with no bundler/ESM support:
|
|
5
|
+
*
|
|
6
|
+
* ```html
|
|
7
|
+
* <script src="https://agent.example.com/embed/babelconnect-embed.iife.js"></script>
|
|
8
|
+
* <script>
|
|
9
|
+
* const bc = BabelconnectEmbed.mount({ container, serverUrl, token });
|
|
10
|
+
* </script>
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Loading this file defines a single global, `window.BabelconnectEmbed` — the same
|
|
14
|
+
* class exported as `BabelconnectEmbed` from `@babelforce/babelconnect-sdk/embed`,
|
|
15
|
+
* so `BabelconnectEmbed.mount({...})` here is identical to the ESM
|
|
16
|
+
* `BabelconnectEmbed.mount({...})`. The name is deliberately **distinct** from the
|
|
17
|
+
* legacy `@babelforce/bc-connect` global (`BabelconnectConnect`) — the two APIs
|
|
18
|
+
* differ and a compatibility shim is out of scope; see EMBEDDING.md for the
|
|
19
|
+
* migration.
|
|
20
|
+
*
|
|
21
|
+
* This file has no `export` statement on purpose: esbuild's `--format=iife` wraps
|
|
22
|
+
* an entry's *exports* into a namespace object under `--global-name`, which would
|
|
23
|
+
* put the class at `window.BabelconnectEmbed.BabelconnectEmbed` instead of
|
|
24
|
+
* `window.BabelconnectEmbed` itself. Assigning to `globalThis` directly here keeps
|
|
25
|
+
* the global exactly the class.
|
|
26
|
+
*/
|
|
27
|
+
import { BabelconnectEmbed } from "./index.js";
|
|
28
|
+
declare global {
|
|
29
|
+
interface Window {
|
|
30
|
+
BabelconnectEmbed: typeof BabelconnectEmbed;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script-tag build entry (EMB21) — bundled by esbuild (not `tsc`, which only emits
|
|
3
|
+
* the ESM `dist/embed/index.js`) into a self-contained IIFE at
|
|
4
|
+
* `dist/web/babelconnect-embed.iife.js`, for CRM hosts with no bundler/ESM support:
|
|
5
|
+
*
|
|
6
|
+
* ```html
|
|
7
|
+
* <script src="https://agent.example.com/embed/babelconnect-embed.iife.js"></script>
|
|
8
|
+
* <script>
|
|
9
|
+
* const bc = BabelconnectEmbed.mount({ container, serverUrl, token });
|
|
10
|
+
* </script>
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Loading this file defines a single global, `window.BabelconnectEmbed` — the same
|
|
14
|
+
* class exported as `BabelconnectEmbed` from `@babelforce/babelconnect-sdk/embed`,
|
|
15
|
+
* so `BabelconnectEmbed.mount({...})` here is identical to the ESM
|
|
16
|
+
* `BabelconnectEmbed.mount({...})`. The name is deliberately **distinct** from the
|
|
17
|
+
* legacy `@babelforce/bc-connect` global (`BabelconnectConnect`) — the two APIs
|
|
18
|
+
* differ and a compatibility shim is out of scope; see EMBEDDING.md for the
|
|
19
|
+
* migration.
|
|
20
|
+
*
|
|
21
|
+
* This file has no `export` statement on purpose: esbuild's `--format=iife` wraps
|
|
22
|
+
* an entry's *exports* into a namespace object under `--global-name`, which would
|
|
23
|
+
* put the class at `window.BabelconnectEmbed.BabelconnectEmbed` instead of
|
|
24
|
+
* `window.BabelconnectEmbed` itself. Assigning to `globalThis` directly here keeps
|
|
25
|
+
* the global exactly the class.
|
|
26
|
+
*/
|
|
27
|
+
import { BabelconnectEmbed } from "./index.js";
|
|
28
|
+
globalThis.BabelconnectEmbed = BabelconnectEmbed;
|
package/dist/embed/index.d.ts
CHANGED
|
@@ -29,6 +29,17 @@ export interface EmbedOptions {
|
|
|
29
29
|
session?: Record<string, unknown>;
|
|
30
30
|
/** Optional initial shared context (also settable later via {@link context}). */
|
|
31
31
|
context?: Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* The `agent.loaded`/`user.loaded` event-payload schema version (EMB20).
|
|
34
|
+
* Omit for the app's current default (`"v3"` — just the top-level
|
|
35
|
+
* `agentId`, no legacy struct nesting). Pass `"v1"` to opt into the
|
|
36
|
+
* bc-connect-compatible shape (`agent.loaded` → `{agentId,
|
|
37
|
+
* agent:{id,name,email,number}}`, `user.loaded` → `{agentId,
|
|
38
|
+
* user:{email}}`) for a host still doing bc-v2-style CRM matching by email
|
|
39
|
+
* or routing by number. See the Embedding guide, "Loaded event schema
|
|
40
|
+
* version".
|
|
41
|
+
*/
|
|
42
|
+
eventsVersion?: string;
|
|
32
43
|
/** Path within the app (default `/`). */
|
|
33
44
|
path?: string;
|
|
34
45
|
/** Optional className for the iframe. */
|
|
@@ -36,21 +47,49 @@ export interface EmbedOptions {
|
|
|
36
47
|
}
|
|
37
48
|
/** A handler for an app→host event's `data` payload. */
|
|
38
49
|
export type EmbedEventHandler = (data: unknown) => void;
|
|
50
|
+
/** Args for {@link BabelconnectEmbed.auth}'s `set`. */
|
|
51
|
+
export interface AuthSetArgs {
|
|
52
|
+
/** New bearer token. */
|
|
53
|
+
token: string;
|
|
54
|
+
/** Updated session correlation. Omit to leave the currently-tracked value unchanged. */
|
|
55
|
+
session?: Record<string, unknown>;
|
|
56
|
+
/** Updated shared context. Omit to leave the currently-tracked value unchanged. */
|
|
57
|
+
context?: Record<string, unknown>;
|
|
58
|
+
/** Updated events-schema version (EMB20, see {@link EmbedOptions.eventsVersion}). Only takes
|
|
59
|
+
* effect on the NEXT `ready` handshake (an iframe reload) — a live session's already-emitted
|
|
60
|
+
* `agent.loaded`/`user.loaded` don't refire. Omit to leave the currently-tracked value unchanged. */
|
|
61
|
+
eventsVersion?: string;
|
|
62
|
+
}
|
|
39
63
|
/**
|
|
40
|
-
* A mounted embed. Use the verb groups ({@link
|
|
41
|
-
* {@link context}, {@link app}) to drive the app, and
|
|
42
|
-
* app→host events (`agent.loaded`, `cti.call`,
|
|
64
|
+
* A mounted embed. Use the verb groups ({@link auth}, {@link calls},
|
|
65
|
+
* {@link session}, {@link context}, {@link app}) to drive the app, and
|
|
66
|
+
* {@link on} to receive app→host events (`agent.loaded`, `cti.call`,
|
|
67
|
+
* `cti.error`, …).
|
|
43
68
|
*/
|
|
44
69
|
export declare class BabelconnectEmbed {
|
|
45
|
-
private readonly opts;
|
|
46
70
|
private readonly iframe;
|
|
47
71
|
private readonly serverOrigin;
|
|
48
72
|
private readonly handlers;
|
|
49
73
|
private readonly onMessage;
|
|
50
74
|
private disposed;
|
|
75
|
+
private currentToken;
|
|
76
|
+
private currentSession;
|
|
77
|
+
private currentContext;
|
|
78
|
+
private currentEventsVersion;
|
|
51
79
|
private constructor();
|
|
52
80
|
/** Mount the embed: inject the iframe and start the bridge. */
|
|
53
81
|
static mount(opts: EmbedOptions): BabelconnectEmbed;
|
|
82
|
+
/**
|
|
83
|
+
* Refresh the bearer token (and optionally session/context) mid-session —
|
|
84
|
+
* e.g. ahead of expiry on a long shift. Posts `auth.set` immediately; the
|
|
85
|
+
* live app applies it in place without interrupting the session or any
|
|
86
|
+
* active call (EMB15). Also remembers the values as *current*, so if the
|
|
87
|
+
* iframe later reloads and re-emits `ready`, the handshake hands off this
|
|
88
|
+
* refreshed token rather than the one passed to {@link BabelconnectEmbed.mount}.
|
|
89
|
+
*/
|
|
90
|
+
readonly auth: {
|
|
91
|
+
set: (args: AuthSetArgs) => void;
|
|
92
|
+
};
|
|
54
93
|
/** Click-to-dial: place a call (or `dial=false` to only pre-fill the dialer). */
|
|
55
94
|
readonly calls: {
|
|
56
95
|
dial: (number: string, dial?: boolean) => void;
|
|
@@ -74,6 +113,7 @@ export declare class BabelconnectEmbed {
|
|
|
74
113
|
/** Remove the iframe and stop listening. */
|
|
75
114
|
dispose(): void;
|
|
76
115
|
private post;
|
|
116
|
+
private postAuthSet;
|
|
77
117
|
private handleMessage;
|
|
78
118
|
private emit;
|
|
79
119
|
}
|
package/dist/embed/index.js
CHANGED
|
@@ -18,20 +18,31 @@
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
/**
|
|
21
|
-
* A mounted embed. Use the verb groups ({@link
|
|
22
|
-
* {@link context}, {@link app}) to drive the app, and
|
|
23
|
-
* app→host events (`agent.loaded`, `cti.call`,
|
|
21
|
+
* A mounted embed. Use the verb groups ({@link auth}, {@link calls},
|
|
22
|
+
* {@link session}, {@link context}, {@link app}) to drive the app, and
|
|
23
|
+
* {@link on} to receive app→host events (`agent.loaded`, `cti.call`,
|
|
24
|
+
* `cti.error`, …).
|
|
24
25
|
*/
|
|
25
26
|
export class BabelconnectEmbed {
|
|
26
|
-
opts;
|
|
27
27
|
iframe;
|
|
28
28
|
serverOrigin;
|
|
29
29
|
handlers = new Map();
|
|
30
30
|
onMessage;
|
|
31
31
|
disposed = false;
|
|
32
|
+
// The token/session/context/eventsVersion currently in effect — seeded from
|
|
33
|
+
// `opts` at mount() and updated in place by `auth.set()`, so a later `ready`
|
|
34
|
+
// (an iframe reload) re-sends whatever is *current*, not the mount()-time
|
|
35
|
+
// value.
|
|
36
|
+
currentToken;
|
|
37
|
+
currentSession;
|
|
38
|
+
currentContext;
|
|
39
|
+
currentEventsVersion;
|
|
32
40
|
constructor(opts) {
|
|
33
|
-
this.opts = opts;
|
|
34
41
|
this.serverOrigin = new URL(opts.serverUrl).origin;
|
|
42
|
+
this.currentToken = opts.token;
|
|
43
|
+
this.currentSession = opts.session;
|
|
44
|
+
this.currentContext = opts.context;
|
|
45
|
+
this.currentEventsVersion = opts.eventsVersion;
|
|
35
46
|
const iframe = document.createElement("iframe");
|
|
36
47
|
iframe.src = opts.serverUrl.replace(/\/+$/, "") + (opts.path ?? "/");
|
|
37
48
|
iframe.allow = "microphone; autoplay";
|
|
@@ -49,6 +60,26 @@ export class BabelconnectEmbed {
|
|
|
49
60
|
static mount(opts) {
|
|
50
61
|
return new BabelconnectEmbed(opts);
|
|
51
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Refresh the bearer token (and optionally session/context) mid-session —
|
|
65
|
+
* e.g. ahead of expiry on a long shift. Posts `auth.set` immediately; the
|
|
66
|
+
* live app applies it in place without interrupting the session or any
|
|
67
|
+
* active call (EMB15). Also remembers the values as *current*, so if the
|
|
68
|
+
* iframe later reloads and re-emits `ready`, the handshake hands off this
|
|
69
|
+
* refreshed token rather than the one passed to {@link BabelconnectEmbed.mount}.
|
|
70
|
+
*/
|
|
71
|
+
auth = {
|
|
72
|
+
set: (args) => {
|
|
73
|
+
this.currentToken = args.token;
|
|
74
|
+
if (args.session !== undefined)
|
|
75
|
+
this.currentSession = args.session;
|
|
76
|
+
if (args.context !== undefined)
|
|
77
|
+
this.currentContext = args.context;
|
|
78
|
+
if (args.eventsVersion !== undefined)
|
|
79
|
+
this.currentEventsVersion = args.eventsVersion;
|
|
80
|
+
this.postAuthSet();
|
|
81
|
+
},
|
|
82
|
+
};
|
|
52
83
|
/** Click-to-dial: place a call (or `dial=false` to only pre-fill the dialer). */
|
|
53
84
|
calls = {
|
|
54
85
|
dial: (number, dial = true) => this.post("calls", "calls.dial", { number, dial }),
|
|
@@ -91,25 +122,46 @@ export class BabelconnectEmbed {
|
|
|
91
122
|
post(module, name, args) {
|
|
92
123
|
this.iframe.contentWindow?.postMessage({ type: "connect", module, name, args }, this.serverOrigin);
|
|
93
124
|
}
|
|
125
|
+
// Posts the current token/session/context (+ eventsVersion, EMB20) as an
|
|
126
|
+
// auth.set envelope. `eventsVersion` is only included when the host set
|
|
127
|
+
// one — an absent key (rather than an explicit `undefined`) keeps the args
|
|
128
|
+
// shape unchanged for hosts that never opted in, and lets the app apply its
|
|
129
|
+
// own default unambiguously.
|
|
130
|
+
postAuthSet() {
|
|
131
|
+
this.post("auth", "auth.set", {
|
|
132
|
+
token: this.currentToken,
|
|
133
|
+
session: this.currentSession,
|
|
134
|
+
context: this.currentContext,
|
|
135
|
+
...(this.currentEventsVersion !== undefined ? { eventsVersion: this.currentEventsVersion } : {}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
94
138
|
handleMessage(e) {
|
|
95
139
|
if (e.origin !== this.serverOrigin)
|
|
96
140
|
return; // only trust the app's origin
|
|
97
141
|
const msg = e.data;
|
|
98
142
|
if (!msg || msg.type !== "bcConnect" || typeof msg.name !== "string")
|
|
99
143
|
return;
|
|
100
|
-
// Token handoff: on the app's `ready`, hand off the bearer token
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
});
|
|
108
|
-
}
|
|
144
|
+
// Token handoff: on the app's `ready`, hand off the current bearer token
|
|
145
|
+
// (+ session/context/eventsVersion) over postMessage — never via the
|
|
146
|
+
// iframe URL. `ready` also fires on an iframe reload, so this re-sends
|
|
147
|
+
// whatever is current (see `auth.set`), not necessarily the value passed
|
|
148
|
+
// to `mount()`.
|
|
149
|
+
if (msg.name === "ready")
|
|
150
|
+
this.postAuthSet();
|
|
109
151
|
this.emit(msg.name, msg.data);
|
|
110
152
|
}
|
|
111
153
|
emit(name, data) {
|
|
112
|
-
for (const fn of this.handlers.get(name) ?? [])
|
|
113
|
-
|
|
154
|
+
for (const fn of this.handlers.get(name) ?? []) {
|
|
155
|
+
try {
|
|
156
|
+
fn(data);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
// A subscriber's handler is host code, not ours — one throwing
|
|
160
|
+
// handler must not stop sibling handlers from receiving the event,
|
|
161
|
+
// nor escape into the window `message` dispatch (which would break
|
|
162
|
+
// unrelated listeners on the host page).
|
|
163
|
+
console.error("[babelconnect-embed] on() handler threw", err);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
114
166
|
}
|
|
115
167
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ack, AgentView, AuthenticateRequest, Command, GetStateRequest, HistoryRequest, HistoryResponse, Identity, PhonebookRequest, PhonebookResponse, SendSmsRequest, SmsConversation, SmsThreadRequest, SmsThreadResponse, StateUpdate, SubscribeRequest } from "./babelconnect_pb.js";
|
|
1
|
+
import { Ack, AgentView, AuthenticateRequest, Command, GetStateRequest, HistoryRequest, HistoryResponse, Identity, ListCampaignsRequest, ListCampaignsResponse, ListDispositionsRequest, ListDispositionsResponse, PhonebookRequest, PhonebookResponse, SendSmsRequest, SmsConversation, SmsThreadRequest, SmsThreadResponse, StateUpdate, SubscribeRequest, TransferTargetsRequest, TransferTargetsResponse } from "./babelconnect_pb.js";
|
|
2
2
|
import { MethodKind } from "@bufbuild/protobuf";
|
|
3
3
|
/**
|
|
4
4
|
* @generated from service babelconnect.v1.Agent
|
|
@@ -101,6 +101,24 @@ export declare const Agent: {
|
|
|
101
101
|
readonly O: typeof PhonebookResponse;
|
|
102
102
|
readonly kind: MethodKind.Unary;
|
|
103
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* GetTransferTargets autocompletes blind-transfer / add-member targets as the
|
|
106
|
+
* agent types — agents, raw numbers, and IVR applications (GET
|
|
107
|
+
* /agent/calls/transfer/targets?query=, bc-standalone-2
|
|
108
|
+
* src/components/Common/NumberListSelect.vue:59). `query` filters server-side
|
|
109
|
+
* (substring across name/email/number for agents, name for applications); the
|
|
110
|
+
* backend has no call-context param, so eligibility by call direction is a
|
|
111
|
+
* separate, already-server-computed flag the client applies itself
|
|
112
|
+
* (CallState.can_transfer_to_application hides APPLICATION results — CALL-I3).
|
|
113
|
+
*
|
|
114
|
+
* @generated from rpc babelconnect.v1.Agent.GetTransferTargets
|
|
115
|
+
*/
|
|
116
|
+
readonly getTransferTargets: {
|
|
117
|
+
readonly name: "GetTransferTargets";
|
|
118
|
+
readonly I: typeof TransferTargetsRequest;
|
|
119
|
+
readonly O: typeof TransferTargetsResponse;
|
|
120
|
+
readonly kind: MethodKind.Unary;
|
|
121
|
+
};
|
|
104
122
|
/**
|
|
105
123
|
* GetState returns the agent's current AgentView as a single unary call — the
|
|
106
124
|
* REST/web "get current state" (the Subscribe stream is the realtime twin). When
|
|
@@ -128,5 +146,35 @@ export declare const Agent: {
|
|
|
128
146
|
readonly O: typeof SmsConversation;
|
|
129
147
|
readonly kind: MethodKind.Unary;
|
|
130
148
|
};
|
|
149
|
+
/**
|
|
150
|
+
* ListCampaigns lists the outbound-dialer campaigns the agent may join (the
|
|
151
|
+
* Outbound tab's campaign picker, OBDA1) — on-demand reference data like
|
|
152
|
+
* GetPhonebook/GetTransferTargets, backed by GET /api/v2/agent/outbound/
|
|
153
|
+
* campaigns?active=true (sbf/services ObdController#listCampaigns).
|
|
154
|
+
*
|
|
155
|
+
* @generated from rpc babelconnect.v1.Agent.ListCampaigns
|
|
156
|
+
*/
|
|
157
|
+
readonly listCampaigns: {
|
|
158
|
+
readonly name: "ListCampaigns";
|
|
159
|
+
readonly I: typeof ListCampaignsRequest;
|
|
160
|
+
readonly O: typeof ListCampaignsResponse;
|
|
161
|
+
readonly kind: MethodKind.Unary;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* ListDispositions lists the available call-outcome codes for the disposition
|
|
165
|
+
* picker (OBDC1) — on-demand reference data like ListCampaigns, backed by GET
|
|
166
|
+
* /api/v2/agent/outbound/campaigns/{id}/dispositions (sbf/services
|
|
167
|
+
* ObdController#listDispositions). Grounded: the `{id}` path segment is never
|
|
168
|
+
* read server-side — the list is a static global, not campaign-scoped — so the
|
|
169
|
+
* request carries no campaign id either.
|
|
170
|
+
*
|
|
171
|
+
* @generated from rpc babelconnect.v1.Agent.ListDispositions
|
|
172
|
+
*/
|
|
173
|
+
readonly listDispositions: {
|
|
174
|
+
readonly name: "ListDispositions";
|
|
175
|
+
readonly I: typeof ListDispositionsRequest;
|
|
176
|
+
readonly O: typeof ListDispositionsResponse;
|
|
177
|
+
readonly kind: MethodKind.Unary;
|
|
178
|
+
};
|
|
131
179
|
};
|
|
132
180
|
};
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// In addition to gRPC/gRPC-web, the unary RPCs are exposed as a REST+JSON surface
|
|
28
28
|
// via grpc-gateway (the google.api.http annotations below) with an OpenAPI v2 spec
|
|
29
29
|
// — one proto source of truth, two wire surfaces. Streaming stays gRPC/gRPC-web.
|
|
30
|
-
import { Ack, AgentView, AuthenticateRequest, Command, GetStateRequest, HistoryRequest, HistoryResponse, Identity, PhonebookRequest, PhonebookResponse, SendSmsRequest, SmsConversation, SmsThreadRequest, SmsThreadResponse, StateUpdate, SubscribeRequest } from "./babelconnect_pb.js";
|
|
30
|
+
import { Ack, AgentView, AuthenticateRequest, Command, GetStateRequest, HistoryRequest, HistoryResponse, Identity, ListCampaignsRequest, ListCampaignsResponse, ListDispositionsRequest, ListDispositionsResponse, PhonebookRequest, PhonebookResponse, SendSmsRequest, SmsConversation, SmsThreadRequest, SmsThreadResponse, StateUpdate, SubscribeRequest, TransferTargetsRequest, TransferTargetsResponse } from "./babelconnect_pb.js";
|
|
31
31
|
import { MethodKind } from "@bufbuild/protobuf";
|
|
32
32
|
/**
|
|
33
33
|
* @generated from service babelconnect.v1.Agent
|
|
@@ -130,6 +130,24 @@ export const Agent = {
|
|
|
130
130
|
O: PhonebookResponse,
|
|
131
131
|
kind: MethodKind.Unary,
|
|
132
132
|
},
|
|
133
|
+
/**
|
|
134
|
+
* GetTransferTargets autocompletes blind-transfer / add-member targets as the
|
|
135
|
+
* agent types — agents, raw numbers, and IVR applications (GET
|
|
136
|
+
* /agent/calls/transfer/targets?query=, bc-standalone-2
|
|
137
|
+
* src/components/Common/NumberListSelect.vue:59). `query` filters server-side
|
|
138
|
+
* (substring across name/email/number for agents, name for applications); the
|
|
139
|
+
* backend has no call-context param, so eligibility by call direction is a
|
|
140
|
+
* separate, already-server-computed flag the client applies itself
|
|
141
|
+
* (CallState.can_transfer_to_application hides APPLICATION results — CALL-I3).
|
|
142
|
+
*
|
|
143
|
+
* @generated from rpc babelconnect.v1.Agent.GetTransferTargets
|
|
144
|
+
*/
|
|
145
|
+
getTransferTargets: {
|
|
146
|
+
name: "GetTransferTargets",
|
|
147
|
+
I: TransferTargetsRequest,
|
|
148
|
+
O: TransferTargetsResponse,
|
|
149
|
+
kind: MethodKind.Unary,
|
|
150
|
+
},
|
|
133
151
|
/**
|
|
134
152
|
* GetState returns the agent's current AgentView as a single unary call — the
|
|
135
153
|
* REST/web "get current state" (the Subscribe stream is the realtime twin). When
|
|
@@ -157,5 +175,35 @@ export const Agent = {
|
|
|
157
175
|
O: SmsConversation,
|
|
158
176
|
kind: MethodKind.Unary,
|
|
159
177
|
},
|
|
178
|
+
/**
|
|
179
|
+
* ListCampaigns lists the outbound-dialer campaigns the agent may join (the
|
|
180
|
+
* Outbound tab's campaign picker, OBDA1) — on-demand reference data like
|
|
181
|
+
* GetPhonebook/GetTransferTargets, backed by GET /api/v2/agent/outbound/
|
|
182
|
+
* campaigns?active=true (sbf/services ObdController#listCampaigns).
|
|
183
|
+
*
|
|
184
|
+
* @generated from rpc babelconnect.v1.Agent.ListCampaigns
|
|
185
|
+
*/
|
|
186
|
+
listCampaigns: {
|
|
187
|
+
name: "ListCampaigns",
|
|
188
|
+
I: ListCampaignsRequest,
|
|
189
|
+
O: ListCampaignsResponse,
|
|
190
|
+
kind: MethodKind.Unary,
|
|
191
|
+
},
|
|
192
|
+
/**
|
|
193
|
+
* ListDispositions lists the available call-outcome codes for the disposition
|
|
194
|
+
* picker (OBDC1) — on-demand reference data like ListCampaigns, backed by GET
|
|
195
|
+
* /api/v2/agent/outbound/campaigns/{id}/dispositions (sbf/services
|
|
196
|
+
* ObdController#listDispositions). Grounded: the `{id}` path segment is never
|
|
197
|
+
* read server-side — the list is a static global, not campaign-scoped — so the
|
|
198
|
+
* request carries no campaign id either.
|
|
199
|
+
*
|
|
200
|
+
* @generated from rpc babelconnect.v1.Agent.ListDispositions
|
|
201
|
+
*/
|
|
202
|
+
listDispositions: {
|
|
203
|
+
name: "ListDispositions",
|
|
204
|
+
I: ListDispositionsRequest,
|
|
205
|
+
O: ListDispositionsResponse,
|
|
206
|
+
kind: MethodKind.Unary,
|
|
207
|
+
},
|
|
160
208
|
}
|
|
161
209
|
};
|