@babelforce/babelconnect-sdk 0.11.0 → 0.13.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 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
- /** Invite a participant — pass exactly one of `agentId` or `number`. Starts a conference first if none is active. */
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
- /** Invite a participant — pass exactly one of `agentId` or `number`. Starts a conference first if none is active. */
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;
@@ -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 calls}, {@link session},
41
- * {@link context}, {@link app}) to drive the app, and {@link on} to receive
42
- * app→host events (`agent.loaded`, `cti.call`, `cti.error`, …).
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
  }
@@ -18,20 +18,31 @@
18
18
  * ```
19
19
  */
20
20
  /**
21
- * A mounted embed. Use the verb groups ({@link calls}, {@link session},
22
- * {@link context}, {@link app}) to drive the app, and {@link on} to receive
23
- * app→host events (`agent.loaded`, `cti.call`, `cti.error`, …).
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 (+ optional
101
- // initial session/context) over postMessage — never via the iframe URL.
102
- if (msg.name === "ready") {
103
- this.post("auth", "auth.set", {
104
- token: this.opts.token,
105
- session: this.opts.session,
106
- context: this.opts.context,
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
- fn(data);
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
@@ -19,28 +19,15 @@ export declare const Agent: {
19
19
  readonly kind: MethodKind.Unary;
20
20
  };
21
21
  /**
22
- * Session opens the long-lived control stream. The client sends Command
23
- * intents; the server streams StateUpdate (one snapshot on open, then
24
- * entity-level patches). UI = f(AgentView).
25
- *
26
- * Native clients (Go/Dart desktop/mobile over HTTP/2) use this bidi stream.
27
- *
28
- * @generated from rpc babelconnect.v1.Agent.Session
29
- */
30
- readonly session: {
31
- readonly name: "Session";
32
- readonly I: typeof Command;
33
- readonly O: typeof StateUpdate;
34
- readonly kind: MethodKind.BiDiStreaming;
35
- };
36
- /**
37
- * Subscribe + Send are the browser-friendly split of Session: a browser speaks
38
- * gRPC-web, which cannot client-stream, so the bidi Session is impossible there.
39
- * Subscribe is the server→client half (the StateUpdate stream); Send is the
40
- * client→server half (one Command per unary call). Together they are equivalent
41
- * to Session for a single agent — the server keys both to the agent's one state
42
- * store. Command rejections still arrive as an Error on the Subscribe stream
43
- * (never on Send's reply), exactly as on Session.
22
+ * Subscribe + Send are the control stream, split into its server→client and
23
+ * client→server halves — the one shape every client uses (RPC-A4 retired the
24
+ * earlier bidi `Session` RPC, which needed HTTP/2 end-to-end and couldn't
25
+ * ride gRPC-web or a plain HTTP/1.1 ingress). Subscribe is the server→client
26
+ * half (StateUpdate: one snapshot on open, then entity-level patches; UI =
27
+ * f(AgentView)). Send is the client→server half (one Command per unary
28
+ * call). Together they key to the agent's one state store. Command
29
+ * rejections arrive as an Error on the Subscribe stream, never on Send's
30
+ * reply.
44
31
  *
45
32
  * @generated from rpc babelconnect.v1.Agent.Subscribe
46
33
  */
@@ -101,6 +88,24 @@ export declare const Agent: {
101
88
  readonly O: typeof PhonebookResponse;
102
89
  readonly kind: MethodKind.Unary;
103
90
  };
91
+ /**
92
+ * GetTransferTargets autocompletes blind-transfer / add-member targets as the
93
+ * agent types — agents, raw numbers, and IVR applications (GET
94
+ * /agent/calls/transfer/targets?query=, bc-standalone-2
95
+ * src/components/Common/NumberListSelect.vue:59). `query` filters server-side
96
+ * (substring across name/email/number for agents, name for applications); the
97
+ * backend has no call-context param, so eligibility by call direction is a
98
+ * separate, already-server-computed flag the client applies itself
99
+ * (CallState.can_transfer_to_application hides APPLICATION results — CALL-I3).
100
+ *
101
+ * @generated from rpc babelconnect.v1.Agent.GetTransferTargets
102
+ */
103
+ readonly getTransferTargets: {
104
+ readonly name: "GetTransferTargets";
105
+ readonly I: typeof TransferTargetsRequest;
106
+ readonly O: typeof TransferTargetsResponse;
107
+ readonly kind: MethodKind.Unary;
108
+ };
104
109
  /**
105
110
  * GetState returns the agent's current AgentView as a single unary call — the
106
111
  * REST/web "get current state" (the Subscribe stream is the realtime twin). When
@@ -128,5 +133,35 @@ export declare const Agent: {
128
133
  readonly O: typeof SmsConversation;
129
134
  readonly kind: MethodKind.Unary;
130
135
  };
136
+ /**
137
+ * ListCampaigns lists the outbound-dialer campaigns the agent may join (the
138
+ * Outbound tab's campaign picker, OBDA1) — on-demand reference data like
139
+ * GetPhonebook/GetTransferTargets, backed by GET /api/v2/agent/outbound/
140
+ * campaigns?active=true (sbf/services ObdController#listCampaigns).
141
+ *
142
+ * @generated from rpc babelconnect.v1.Agent.ListCampaigns
143
+ */
144
+ readonly listCampaigns: {
145
+ readonly name: "ListCampaigns";
146
+ readonly I: typeof ListCampaignsRequest;
147
+ readonly O: typeof ListCampaignsResponse;
148
+ readonly kind: MethodKind.Unary;
149
+ };
150
+ /**
151
+ * ListDispositions lists the available call-outcome codes for the disposition
152
+ * picker (OBDC1) — on-demand reference data like ListCampaigns, backed by GET
153
+ * /api/v2/agent/outbound/campaigns/{id}/dispositions (sbf/services
154
+ * ObdController#listDispositions). Grounded: the `{id}` path segment is never
155
+ * read server-side — the list is a static global, not campaign-scoped — so the
156
+ * request carries no campaign id either.
157
+ *
158
+ * @generated from rpc babelconnect.v1.Agent.ListDispositions
159
+ */
160
+ readonly listDispositions: {
161
+ readonly name: "ListDispositions";
162
+ readonly I: typeof ListDispositionsRequest;
163
+ readonly O: typeof ListDispositionsResponse;
164
+ readonly kind: MethodKind.Unary;
165
+ };
131
166
  };
132
167
  };