@babelforce/babelconnect-sdk 0.10.0 → 0.11.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/dist/client.d.ts CHANGED
@@ -150,3 +150,8 @@ export declare class BabelconnectClient {
150
150
  private rawSend;
151
151
  private closeAllMedia;
152
152
  }
153
+ /**
154
+ * Stamp the SDK identity (name + build version) onto a request's headers — sent
155
+ * on every unary + streaming call so the server can identify the client (APP-A5).
156
+ */
157
+ export declare function applySdkHeaders(header: Headers): void;
package/dist/client.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { createClient, } from "@connectrpc/connect";
2
2
  import { createGrpcWebTransport } from "@connectrpc/connect-web";
3
+ import { SDK_VERSION } from "./version.js";
3
4
  import { Agent } from "./gen/babelconnect/v1/babelconnect_connect.js";
4
- import { AddConferenceMember, AnswerCall, CallDirection, CallLifecycle, CallSource, Command, EndConference, Error as BcError, FlagRecording, Hangup, HistoryRequest, SmsThreadRequest, PhonebookRequest, HoldConferenceMember, Hold, KickConferenceMember, LeaveConference, MarkConversationRead, Mute, MuteConferenceMember, PlaceCall, 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, 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
6
  import { browserMediaFactory, MediaError, toRTCIceServers, } from "./media.js";
6
7
  import { StateCache } from "./state-cache.js";
7
8
  /**
@@ -346,6 +347,15 @@ export class BabelconnectClient {
346
347
  // pass so a 15s heartbeat doesn't trigger a no-op reconcile every tick.
347
348
  if (u.update.case === "keepalive")
348
349
  return;
350
+ // Ping: reply with a Pong echoing the seq so the server can measure RTT +
351
+ // liveness (CALL-M6). Control-only, like keepalive — short-circuited before the
352
+ // cache and the ready/flush logic so it is never mistaken for the snapshot.
353
+ if (u.update.case === "ping") {
354
+ void this.rawSend(new Command({
355
+ command: { case: "pong", value: new Pong({ seq: u.update.value.seq }) },
356
+ }));
357
+ return;
358
+ }
349
359
  // First message = the snapshot ⇒ the session is registered server-side, so
350
360
  // flush intents queued during connect() (register(), an early dial, …).
351
361
  if (!this.ready) {
@@ -464,10 +474,22 @@ export class BabelconnectClient {
464
474
  await Promise.all(all.map((m) => m.close()));
465
475
  }
466
476
  }
467
- /** An interceptor that attaches the bearer token to every gRPC-web call. */
477
+ /**
478
+ * Stamp the SDK identity (name + build version) onto a request's headers — sent
479
+ * on every unary + streaming call so the server can identify the client (APP-A5).
480
+ */
481
+ export function applySdkHeaders(header) {
482
+ header.set("x-babelconnect-sdk", "ts");
483
+ header.set("x-babelconnect-sdk-version", SDK_VERSION);
484
+ }
485
+ /**
486
+ * An interceptor that attaches the bearer token and the SDK identity headers to
487
+ * every gRPC-web call (unary + the long-lived Subscribe stream).
488
+ */
468
489
  function authInterceptor(token) {
469
490
  return (next) => (req) => {
470
491
  req.header.set("Authorization", `Bearer ${token}`);
492
+ applySdkHeaders(req.header);
471
493
  return next(req);
472
494
  };
473
495
  }
@@ -1098,6 +1098,12 @@ export declare class StateUpdate extends Message<StateUpdate> {
1098
1098
  */
1099
1099
  value: Keepalive;
1100
1100
  case: "keepalive";
1101
+ } | {
1102
+ /**
1103
+ * @generated from field: babelconnect.v1.Ping ping = 6;
1104
+ */
1105
+ value: Ping;
1106
+ case: "ping";
1101
1107
  } | {
1102
1108
  case: undefined;
1103
1109
  value?: undefined;
@@ -1131,6 +1137,30 @@ export declare class Keepalive extends Message<Keepalive> {
1131
1137
  static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Keepalive;
1132
1138
  static equals(a: Keepalive | PlainMessage<Keepalive> | undefined, b: Keepalive | PlainMessage<Keepalive> | undefined): boolean;
1133
1139
  }
1140
+ /**
1141
+ * Ping is a liveness probe the server sends on the heartbeat tick (replacing the
1142
+ * bare Keepalive frame). The client echoes `seq` back in a Pong command; the server
1143
+ * measures round-trip time (RTT) from the reply and tracks per-session liveness.
1144
+ * Like Keepalive it keeps the connection warm, carries no state, and does NOT
1145
+ * advance `seq` — caches ignore it, and the reply is handled in the client's stream
1146
+ * loop, not the state reducer. (APP-A5/CALL-M6.)
1147
+ *
1148
+ * @generated from message babelconnect.v1.Ping
1149
+ */
1150
+ export declare class Ping extends Message<Ping> {
1151
+ /**
1152
+ * @generated from field: uint64 seq = 1;
1153
+ */
1154
+ seq: bigint;
1155
+ constructor(data?: PartialMessage<Ping>);
1156
+ static readonly runtime: typeof proto3;
1157
+ static readonly typeName = "babelconnect.v1.Ping";
1158
+ static readonly fields: FieldList;
1159
+ static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Ping;
1160
+ static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Ping;
1161
+ static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Ping;
1162
+ static equals(a: Ping | PlainMessage<Ping> | undefined, b: Ping | PlainMessage<Ping> | undefined): boolean;
1163
+ }
1134
1164
  /**
1135
1165
  * Patch is an entity-level delta applied mechanically by the client cache:
1136
1166
  * replace the agent block, upsert/remove a call by id, or set wrap-up.
@@ -1516,6 +1546,14 @@ export declare class Command extends Message<Command> {
1516
1546
  */
1517
1547
  value: MarkConversationRead;
1518
1548
  case: "markConversationRead";
1549
+ } | {
1550
+ /**
1551
+ * reply to a server Ping (liveness + RTT); echoes Ping.seq
1552
+ *
1553
+ * @generated from field: babelconnect.v1.Pong pong = 30;
1554
+ */
1555
+ value: Pong;
1556
+ case: "pong";
1519
1557
  } | {
1520
1558
  case: undefined;
1521
1559
  value?: undefined;
@@ -1529,6 +1567,27 @@ export declare class Command extends Message<Command> {
1529
1567
  static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Command;
1530
1568
  static equals(a: Command | PlainMessage<Command> | undefined, b: Command | PlainMessage<Command> | undefined): boolean;
1531
1569
  }
1570
+ /**
1571
+ * Pong replies to a server Ping (StateUpdate.ping), echoing its `seq` so the server
1572
+ * can match it to the outstanding ping and compute RTT. Sent automatically by the
1573
+ * SDK from its stream-receive loop — not a user intent. (APP-A5/CALL-M6.)
1574
+ *
1575
+ * @generated from message babelconnect.v1.Pong
1576
+ */
1577
+ export declare class Pong extends Message<Pong> {
1578
+ /**
1579
+ * @generated from field: uint64 seq = 1;
1580
+ */
1581
+ seq: bigint;
1582
+ constructor(data?: PartialMessage<Pong>);
1583
+ static readonly runtime: typeof proto3;
1584
+ static readonly typeName = "babelconnect.v1.Pong";
1585
+ static readonly fields: FieldList;
1586
+ static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Pong;
1587
+ static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Pong;
1588
+ static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Pong;
1589
+ static equals(a: Pong | PlainMessage<Pong> | undefined, b: Pong | PlainMessage<Pong> | undefined): boolean;
1590
+ }
1532
1591
  /**
1533
1592
  * @generated from message babelconnect.v1.Register
1534
1593
  */
@@ -1545,6 +1545,7 @@ export class StateUpdate extends Message {
1545
1545
  { no: 3, name: "patch", kind: "message", T: Patch, oneof: "update" },
1546
1546
  { no: 4, name: "error", kind: "message", T: Error, oneof: "update" },
1547
1547
  { no: 5, name: "keepalive", kind: "message", T: Keepalive, oneof: "update" },
1548
+ { no: 6, name: "ping", kind: "message", T: Ping, oneof: "update" },
1548
1549
  ]);
1549
1550
  static fromBinary(bytes, options) {
1550
1551
  return new StateUpdate().fromBinary(bytes, options);
@@ -1590,6 +1591,43 @@ export class Keepalive extends Message {
1590
1591
  return proto3.util.equals(Keepalive, a, b);
1591
1592
  }
1592
1593
  }
1594
+ /**
1595
+ * Ping is a liveness probe the server sends on the heartbeat tick (replacing the
1596
+ * bare Keepalive frame). The client echoes `seq` back in a Pong command; the server
1597
+ * measures round-trip time (RTT) from the reply and tracks per-session liveness.
1598
+ * Like Keepalive it keeps the connection warm, carries no state, and does NOT
1599
+ * advance `seq` — caches ignore it, and the reply is handled in the client's stream
1600
+ * loop, not the state reducer. (APP-A5/CALL-M6.)
1601
+ *
1602
+ * @generated from message babelconnect.v1.Ping
1603
+ */
1604
+ export class Ping extends Message {
1605
+ /**
1606
+ * @generated from field: uint64 seq = 1;
1607
+ */
1608
+ seq = protoInt64.zero;
1609
+ constructor(data) {
1610
+ super();
1611
+ proto3.util.initPartial(data, this);
1612
+ }
1613
+ static runtime = proto3;
1614
+ static typeName = "babelconnect.v1.Ping";
1615
+ static fields = proto3.util.newFieldList(() => [
1616
+ { no: 1, name: "seq", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
1617
+ ]);
1618
+ static fromBinary(bytes, options) {
1619
+ return new Ping().fromBinary(bytes, options);
1620
+ }
1621
+ static fromJson(jsonValue, options) {
1622
+ return new Ping().fromJson(jsonValue, options);
1623
+ }
1624
+ static fromJsonString(jsonString, options) {
1625
+ return new Ping().fromJsonString(jsonString, options);
1626
+ }
1627
+ static equals(a, b) {
1628
+ return proto3.util.equals(Ping, a, b);
1629
+ }
1630
+ }
1593
1631
  /**
1594
1632
  * Patch is an entity-level delta applied mechanically by the client cache:
1595
1633
  * replace the agent block, upsert/remove a call by id, or set wrap-up.
@@ -1775,6 +1813,7 @@ export class Command extends Message {
1775
1813
  { no: 27, name: "mute_conference_member", kind: "message", T: MuteConferenceMember, oneof: "command" },
1776
1814
  { no: 28, name: "set_conversation_open", kind: "message", T: SetConversationOpen, oneof: "command" },
1777
1815
  { no: 29, name: "mark_conversation_read", kind: "message", T: MarkConversationRead, oneof: "command" },
1816
+ { no: 30, name: "pong", kind: "message", T: Pong, oneof: "command" },
1778
1817
  ]);
1779
1818
  static fromBinary(bytes, options) {
1780
1819
  return new Command().fromBinary(bytes, options);
@@ -1789,6 +1828,40 @@ export class Command extends Message {
1789
1828
  return proto3.util.equals(Command, a, b);
1790
1829
  }
1791
1830
  }
1831
+ /**
1832
+ * Pong replies to a server Ping (StateUpdate.ping), echoing its `seq` so the server
1833
+ * can match it to the outstanding ping and compute RTT. Sent automatically by the
1834
+ * SDK from its stream-receive loop — not a user intent. (APP-A5/CALL-M6.)
1835
+ *
1836
+ * @generated from message babelconnect.v1.Pong
1837
+ */
1838
+ export class Pong extends Message {
1839
+ /**
1840
+ * @generated from field: uint64 seq = 1;
1841
+ */
1842
+ seq = protoInt64.zero;
1843
+ constructor(data) {
1844
+ super();
1845
+ proto3.util.initPartial(data, this);
1846
+ }
1847
+ static runtime = proto3;
1848
+ static typeName = "babelconnect.v1.Pong";
1849
+ static fields = proto3.util.newFieldList(() => [
1850
+ { no: 1, name: "seq", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
1851
+ ]);
1852
+ static fromBinary(bytes, options) {
1853
+ return new Pong().fromBinary(bytes, options);
1854
+ }
1855
+ static fromJson(jsonValue, options) {
1856
+ return new Pong().fromJson(jsonValue, options);
1857
+ }
1858
+ static fromJsonString(jsonString, options) {
1859
+ return new Pong().fromJsonString(jsonString, options);
1860
+ }
1861
+ static equals(a, b) {
1862
+ return proto3.util.equals(Pong, a, b);
1863
+ }
1864
+ }
1792
1865
  /**
1793
1866
  * @generated from message babelconnect.v1.Register
1794
1867
  */
@@ -0,0 +1 @@
1
+ export declare const SDK_VERSION = "0.11.0";
@@ -0,0 +1,3 @@
1
+ // Generated by scripts/gen-version.mjs (npm prebuild) from package.json.
2
+ // Do not edit by hand.
3
+ export const SDK_VERSION = "0.11.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babelforce/babelconnect-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "TypeScript SDK for babelconnect — server-authoritative agent state over gRPC-web, native WebRTC audio, and an embeddable widget (iframe + postMessage) for the Flutter web app.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://babelforce.github.io/babelconnect-sdk/",
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "scripts": {
26
26
  "generate": "echo 'run `task gen` at the repo root (buf generate emits src/gen)'",
27
+ "prebuild": "node scripts/gen-version.mjs",
27
28
  "build": "tsc -p tsconfig.json",
28
29
  "typecheck": "tsc -p tsconfig.json --noEmit",
29
30
  "test": "npm run build && node --test test/*.test.mjs",