@eyepop.ai/eyepop 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/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __commonJS = (cb, mod) => function __require() {
7
9
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
@@ -18,6 +20,14 @@ var __copyProps = (to, from, except, desc) => {
18
20
  }
19
21
  return to;
20
22
  };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
21
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
32
 
23
33
  // node_modules/mime-db/db.json
@@ -9054,6 +9064,39 @@ var LoadFromJob = class extends AbstractJob {
9054
9064
  return response;
9055
9065
  }
9056
9066
  };
9067
+ var LoadLiveIngressJob = class extends AbstractJob {
9068
+ constructor(ingressId, getSession, client, requestLogger) {
9069
+ super(getSession, client, requestLogger);
9070
+ this._ingressId = ingressId;
9071
+ }
9072
+ get [Symbol.toStringTag]() {
9073
+ return "loadLiveIngressJob";
9074
+ }
9075
+ async startJob() {
9076
+ const body = {
9077
+ "sourceType": "LIVE_INGRESS",
9078
+ "liveIngressId": this._ingressId
9079
+ };
9080
+ const session = await this._getSession();
9081
+ const headers = {
9082
+ "Authorization": `Bearer ${session.accessToken}`,
9083
+ "Accept": "application/jsonl",
9084
+ "Content-Type": "application/json"
9085
+ };
9086
+ const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
9087
+ this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._ingressId);
9088
+ const response = await this._client.fetch(patchUrl, {
9089
+ headers,
9090
+ method: "PATCH",
9091
+ body: JSON.stringify(body),
9092
+ signal: this._controller.signal,
9093
+ // @ts-ignore
9094
+ dispatcher: this._dispatcher
9095
+ });
9096
+ this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._ingressId);
9097
+ return response;
9098
+ }
9099
+ };
9057
9100
 
9058
9101
  // src/shims/http_client.ts
9059
9102
  var createHttpClient;
@@ -9222,6 +9265,374 @@ var Semaphore = class {
9222
9265
  }
9223
9266
  };
9224
9267
 
9268
+ // node_modules/uuid/dist/esm-node/rng.js
9269
+ var import_crypto = __toESM(require("crypto"));
9270
+ var rnds8Pool = new Uint8Array(256);
9271
+ var poolPtr = rnds8Pool.length;
9272
+ function rng() {
9273
+ if (poolPtr > rnds8Pool.length - 16) {
9274
+ import_crypto.default.randomFillSync(rnds8Pool);
9275
+ poolPtr = 0;
9276
+ }
9277
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
9278
+ }
9279
+
9280
+ // node_modules/uuid/dist/esm-node/stringify.js
9281
+ var byteToHex = [];
9282
+ for (let i = 0; i < 256; ++i) {
9283
+ byteToHex.push((i + 256).toString(16).slice(1));
9284
+ }
9285
+ function unsafeStringify(arr, offset = 0) {
9286
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
9287
+ }
9288
+
9289
+ // node_modules/uuid/dist/esm-node/native.js
9290
+ var import_crypto2 = __toESM(require("crypto"));
9291
+ var native_default = {
9292
+ randomUUID: import_crypto2.default.randomUUID
9293
+ };
9294
+
9295
+ // node_modules/uuid/dist/esm-node/v4.js
9296
+ function v4(options, buf, offset) {
9297
+ if (native_default.randomUUID && !buf && !options) {
9298
+ return native_default.randomUUID();
9299
+ }
9300
+ options = options || {};
9301
+ const rnds = options.random || (options.rng || rng)();
9302
+ rnds[6] = rnds[6] & 15 | 64;
9303
+ rnds[8] = rnds[8] & 63 | 128;
9304
+ if (buf) {
9305
+ offset = offset || 0;
9306
+ for (let i = 0; i < 16; ++i) {
9307
+ buf[offset + i] = rnds[i];
9308
+ }
9309
+ return buf;
9310
+ }
9311
+ return unsafeStringify(rnds);
9312
+ }
9313
+ var v4_default = v4;
9314
+
9315
+ // src/web_rtc_base.ts
9316
+ var WebRtcBase = class {
9317
+ constructor(getSession, client, requestLogger) {
9318
+ this._pc = null;
9319
+ this._getSession = getSession;
9320
+ this._client = client;
9321
+ this._requestLogger = requestLogger;
9322
+ this._eTag = "";
9323
+ this._queuedCandidates = [];
9324
+ this._offerData = null;
9325
+ }
9326
+ static linkToIceServers(links) {
9327
+ const servers = links !== null ? links.split(", ").map((link) => {
9328
+ const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
9329
+ if (!m) {
9330
+ return null;
9331
+ }
9332
+ const iceServer = {
9333
+ urls: [m[1]],
9334
+ username: Whip.unquoteCredential(m[3]),
9335
+ credential: Whip.unquoteCredential(m[4])
9336
+ // credentialType: m[3]? "password" : undefined
9337
+ };
9338
+ return iceServer;
9339
+ }) : [];
9340
+ return servers.filter(function(el) {
9341
+ return el != null;
9342
+ });
9343
+ }
9344
+ static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
9345
+ const sections = answer.split("m=");
9346
+ for (let i = 0; i < sections.length; i++) {
9347
+ const section = sections[i];
9348
+ if (section.startsWith("video")) {
9349
+ sections[i] = Whip.setVideoBitrate(Whip.setCodec(section, videoCodec), videoBitrate);
9350
+ } else if (section.startsWith("audio")) {
9351
+ sections[i] = Whip.setAudioBitrate(Whip.setCodec(section, audioCodec), audioBitrate, audioVoice);
9352
+ }
9353
+ }
9354
+ return sections.join("m=");
9355
+ }
9356
+ static setCodec(section, codec) {
9357
+ const lines = section.split("\r\n");
9358
+ const lines2 = [];
9359
+ const payloadFormats = [];
9360
+ for (const line of lines) {
9361
+ if (!line.startsWith("a=rtpmap:")) {
9362
+ lines2.push(line);
9363
+ } else {
9364
+ if (codec && line.toLowerCase().includes(codec)) {
9365
+ payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
9366
+ lines2.push(line);
9367
+ }
9368
+ }
9369
+ }
9370
+ const lines3 = [];
9371
+ for (const line of lines2) {
9372
+ if (line.startsWith("a=fmtp:")) {
9373
+ if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
9374
+ lines3.push(line);
9375
+ }
9376
+ } else if (line.startsWith("a=rtcp-fb:")) {
9377
+ if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
9378
+ lines3.push(line);
9379
+ }
9380
+ } else {
9381
+ lines3.push(line);
9382
+ }
9383
+ }
9384
+ return lines3.join("\r\n");
9385
+ }
9386
+ static setVideoBitrate(section, bitrate) {
9387
+ let lines = section.split("\r\n");
9388
+ for (let i = 0; i < lines.length; i++) {
9389
+ if (lines[i].startsWith("c=")) {
9390
+ lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
9391
+ break;
9392
+ }
9393
+ }
9394
+ return lines.join("\r\n");
9395
+ }
9396
+ static setAudioBitrate(section, bitrate, voice) {
9397
+ let opusPayloadFormat = "";
9398
+ let lines = section.split("\r\n");
9399
+ for (let i = 0; i < lines.length; i++) {
9400
+ if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
9401
+ opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
9402
+ break;
9403
+ }
9404
+ }
9405
+ if (opusPayloadFormat === "") {
9406
+ return section;
9407
+ }
9408
+ for (let i = 0; i < lines.length; i++) {
9409
+ if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
9410
+ if (voice) {
9411
+ lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
9412
+ } else {
9413
+ lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
9414
+ }
9415
+ }
9416
+ }
9417
+ return lines.join("\r\n");
9418
+ }
9419
+ static parseOffer(offer) {
9420
+ let medias = [];
9421
+ let iceUfrag = "";
9422
+ let icePwd = "";
9423
+ for (const line of offer.split("\r\n")) {
9424
+ if (line.startsWith("m=")) {
9425
+ medias.push(line.slice("m=".length));
9426
+ } else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
9427
+ iceUfrag = line.slice("a=ice-ufrag:".length);
9428
+ } else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
9429
+ icePwd = line.slice("a=ice-pwd:".length);
9430
+ }
9431
+ }
9432
+ return {
9433
+ iceUfrag,
9434
+ icePwd,
9435
+ medias
9436
+ };
9437
+ }
9438
+ static generateSdpFragment(offerData, candidates) {
9439
+ const candidatesByMedia = /* @__PURE__ */ new Map();
9440
+ for (const candidate of candidates) {
9441
+ if (candidate.sdpMLineIndex !== null) {
9442
+ const mid2 = candidate.sdpMLineIndex;
9443
+ let matched = candidatesByMedia.get(mid2);
9444
+ if (matched === void 0) {
9445
+ matched = [];
9446
+ candidatesByMedia.set(mid2, matched);
9447
+ }
9448
+ matched.push(candidate);
9449
+ }
9450
+ }
9451
+ let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
9452
+ let mid = 0;
9453
+ for (const media of offerData.medias) {
9454
+ let matched = candidatesByMedia.get(mid);
9455
+ if (matched !== void 0) {
9456
+ frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
9457
+ for (const candidate of matched) {
9458
+ frag += "a=" + candidate.candidate + "\r\n";
9459
+ }
9460
+ }
9461
+ mid++;
9462
+ }
9463
+ return frag;
9464
+ }
9465
+ static unquoteCredential(v) {
9466
+ if (!v) {
9467
+ return "";
9468
+ }
9469
+ return JSON.parse(`"${v}"`);
9470
+ }
9471
+ };
9472
+
9473
+ // src/whip.ts
9474
+ var Whip = class _Whip extends WebRtcBase {
9475
+ constructor(stream, getSession, client, requestLogger) {
9476
+ super(getSession, client, requestLogger);
9477
+ this._ingressId = v4_default().toString();
9478
+ this._stream = stream;
9479
+ }
9480
+ ingressId() {
9481
+ if (!this._ingressId) {
9482
+ throw new Error("not initialized");
9483
+ }
9484
+ return this._ingressId;
9485
+ }
9486
+ async start() {
9487
+ const session = await this._getSession();
9488
+ const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
9489
+ this._requestLogger.debug("before GET: %s", ingressUrl);
9490
+ const headers = {
9491
+ "Authorization": `Bearer ${session.accessToken}`
9492
+ };
9493
+ const response = await this._client.fetch(ingressUrl, {
9494
+ headers,
9495
+ method: "GET"
9496
+ });
9497
+ if (response.status >= 300) {
9498
+ return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
9499
+ }
9500
+ return this.onIceServers(response);
9501
+ }
9502
+ async onIceServers(response) {
9503
+ if (!this._stream) {
9504
+ throw new Error("onIceServers no stream");
9505
+ }
9506
+ const stream = this._stream;
9507
+ const pc = new RTCPeerConnection({
9508
+ iceServers: _Whip.linkToIceServers(response.headers.get("Link"))
9509
+ });
9510
+ this._pc = pc;
9511
+ pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
9512
+ return new Promise(async (resolve2, reject) => {
9513
+ pc.oniceconnectionstatechange = () => {
9514
+ switch (pc.iceConnectionState) {
9515
+ case "failed":
9516
+ case "disconnected":
9517
+ reject(`peer connection: ${pc.iceConnectionState}`);
9518
+ break;
9519
+ case "connected":
9520
+ resolve2(this);
9521
+ break;
9522
+ }
9523
+ };
9524
+ stream.getTracks().forEach((track) => {
9525
+ this._requestLogger.debug("onIceServers our stream has track: %s", track);
9526
+ pc.addTrack(track, stream);
9527
+ });
9528
+ stream.addEventListener("addtrack", (trackEvent) => {
9529
+ this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
9530
+ pc.addTrack(trackEvent.track, stream);
9531
+ });
9532
+ await this.onLocalOffer(await pc.createOffer());
9533
+ });
9534
+ }
9535
+ async onLocalCandidate(evt) {
9536
+ if (evt.candidate !== null) {
9537
+ if (this._eTag === "") {
9538
+ this._queuedCandidates.push(evt.candidate);
9539
+ } else {
9540
+ await this.sendLocalCandidates([evt.candidate]);
9541
+ }
9542
+ }
9543
+ return this;
9544
+ }
9545
+ async onLocalOffer(offer) {
9546
+ if (!this._pc) {
9547
+ throw new Error("onLocalOffer no peer connection");
9548
+ }
9549
+ if (!offer.sdp) {
9550
+ throw new Error("onLocalOffer no sdp");
9551
+ }
9552
+ this._offerData = _Whip.parseOffer(offer.sdp);
9553
+ await this._pc.setLocalDescription(offer);
9554
+ const session = await this._getSession();
9555
+ const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
9556
+ this._requestLogger.debug("before GET: %s", ingressUrl);
9557
+ const headers = {
9558
+ "Authorization": `Bearer ${session.accessToken}`,
9559
+ "Content-Type": "application/sdp"
9560
+ };
9561
+ const response = await this._client.fetch(ingressUrl, {
9562
+ headers,
9563
+ method: "POST",
9564
+ body: offer.sdp
9565
+ });
9566
+ if (response.status != 201) {
9567
+ return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
9568
+ }
9569
+ this._eTag = response.headers.get("ETag") ?? "";
9570
+ return this.onRemoteAnswer(new RTCSessionDescription({
9571
+ type: "answer",
9572
+ sdp: await response.text()
9573
+ }));
9574
+ }
9575
+ async onRemoteAnswer(answer) {
9576
+ if (!this._pc) {
9577
+ throw new Error("onLocalOffer no peer connection");
9578
+ }
9579
+ answer = new RTCSessionDescription({
9580
+ type: "answer",
9581
+ sdp: _Whip.editAnswer(
9582
+ answer.sdp,
9583
+ "h264/90000",
9584
+ void 0,
9585
+ 5e3,
9586
+ void 0,
9587
+ true
9588
+ )
9589
+ });
9590
+ await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
9591
+ if (this._queuedCandidates.length !== 0) {
9592
+ await this.sendLocalCandidates(this._queuedCandidates);
9593
+ this._queuedCandidates = [];
9594
+ }
9595
+ return this;
9596
+ }
9597
+ async sendLocalCandidates(candidates) {
9598
+ if (!this._offerData) {
9599
+ throw new Error("sendLocalCandidates no offerData");
9600
+ }
9601
+ const session = await this._getSession();
9602
+ const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
9603
+ this._requestLogger.debug("before PATCH: %s", ingressUrl);
9604
+ const headers = {
9605
+ "Authorization": `Bearer ${session.accessToken}`,
9606
+ "Content-Type": "application/trickle-ice-sdpfrag",
9607
+ "If-Match": this._eTag
9608
+ };
9609
+ const response = await this._client.fetch(ingressUrl, {
9610
+ headers,
9611
+ method: "PATCH",
9612
+ body: _Whip.generateSdpFragment(this._offerData, candidates)
9613
+ });
9614
+ if (response.status != 204) {
9615
+ return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
9616
+ }
9617
+ return this;
9618
+ }
9619
+ async close() {
9620
+ const pc = this._pc;
9621
+ const stream = this._stream;
9622
+ this._stream = null;
9623
+ this._pc = null;
9624
+ if (stream) {
9625
+ const tracks = stream.getTracks();
9626
+ tracks.forEach((track) => {
9627
+ track.stop();
9628
+ });
9629
+ }
9630
+ if (pc) {
9631
+ return pc.close();
9632
+ }
9633
+ }
9634
+ };
9635
+
9225
9636
  // src/shims/local_file.ts
9226
9637
  var resolve;
9227
9638
  if ("document" in globalThis && "implementation" in globalThis.document) {
@@ -9277,6 +9688,8 @@ var Endpoint = class {
9277
9688
  this._client = null;
9278
9689
  this._state = "Idle" /* Idle */;
9279
9690
  this._stateChangeHandler = null;
9691
+ this._ingressEventHandler = null;
9692
+ this._ingressEventWs = null;
9280
9693
  this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
9281
9694
  let rootLogger;
9282
9695
  if (options.logger) {
@@ -9291,6 +9704,51 @@ var Endpoint = class {
9291
9704
  this._stateChangeHandler = handler;
9292
9705
  return this;
9293
9706
  }
9707
+ async startIngressWs() {
9708
+ if (this._ingressEventWs || !this._baseUrl || !this._client) {
9709
+ return;
9710
+ }
9711
+ try {
9712
+ const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
9713
+ const headers = {
9714
+ "Authorization": await this.authorizationHeader()
9715
+ };
9716
+ this._requestLogger.debug("before GET %s", getTokenUrl);
9717
+ let response = await this._client.fetch(getTokenUrl, { headers });
9718
+ if (response.status == 401) {
9719
+ this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
9720
+ this._token = null;
9721
+ const headers2 = {
9722
+ "Authorization": await this.authorizationHeader()
9723
+ };
9724
+ this.updateState("FetchConfig" /* FetchConfig */);
9725
+ response = await this._client.fetch(getTokenUrl, { headers: headers2 });
9726
+ }
9727
+ if (response.status != 200) {
9728
+ const message = await response.text();
9729
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9730
+ }
9731
+ const wsAuthToken = await response.json();
9732
+ const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
9733
+ this._ingressEventWs = new WebSocket(wsUrl);
9734
+ this._ingressEventWs.addEventListener("message", (event) => {
9735
+ const ingressEvent = JSON.parse(event.data);
9736
+ if (this._ingressEventHandler) {
9737
+ this._ingressEventHandler(ingressEvent);
9738
+ }
9739
+ });
9740
+ } finally {
9741
+ this.updateState();
9742
+ }
9743
+ }
9744
+ onIngressEvent(handler) {
9745
+ this._ingressEventHandler = handler;
9746
+ this.startIngressWs().then(() => {
9747
+ }).catch((reason) => {
9748
+ this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
9749
+ });
9750
+ return this;
9751
+ }
9294
9752
  state() {
9295
9753
  return this._state;
9296
9754
  }
@@ -9323,9 +9781,18 @@ var Endpoint = class {
9323
9781
  pipelineId: this._pipelineId
9324
9782
  };
9325
9783
  }
9784
+ async liveIngress(stream) {
9785
+ if (!this._baseUrl || !this._client) {
9786
+ return Promise.reject("endpoint not connected, use connect() before ingress()");
9787
+ }
9788
+ const job = new Whip(stream, async () => {
9789
+ return this.session();
9790
+ }, this._client, this._requestLogger);
9791
+ return job.start();
9792
+ }
9326
9793
  async upload(params) {
9327
9794
  if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
9328
- return Promise.reject("endpoint not connected, use open() before upload()");
9795
+ return Promise.reject("endpoint not connected, use connect() before upload()");
9329
9796
  }
9330
9797
  params = await resolve(params);
9331
9798
  if (!params.mimeType) {
@@ -9344,7 +9811,7 @@ var Endpoint = class {
9344
9811
  }
9345
9812
  async loadFrom(location) {
9346
9813
  if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
9347
- throw new Error("endpoint not connected, use open() before loadFrom()");
9814
+ throw new Error("endpoint not connected, use connect() before loadFrom()");
9348
9815
  }
9349
9816
  await this._limit.acquire();
9350
9817
  this.updateState();
@@ -9357,6 +9824,21 @@ var Endpoint = class {
9357
9824
  this.jobStatus(job, statusCode);
9358
9825
  });
9359
9826
  }
9827
+ async loadLiveIngress(ingressId) {
9828
+ if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
9829
+ throw new Error("endpoint not connected, use connect() before loadLiveIngress()");
9830
+ }
9831
+ await this._limit.acquire();
9832
+ this.updateState();
9833
+ const job = new LoadLiveIngressJob(ingressId, async () => {
9834
+ return this.session();
9835
+ }, this._client, this._requestLogger);
9836
+ return job.start(() => {
9837
+ this.jobDone(job);
9838
+ }, (statusCode) => {
9839
+ this.jobStatus(job, statusCode);
9840
+ });
9841
+ }
9360
9842
  // noinspection TypeScriptValidateTypes
9361
9843
  async connect() {
9362
9844
  if (this._client) {
@@ -9394,6 +9876,9 @@ var Endpoint = class {
9394
9876
  }
9395
9877
  this._requestLogger.debug("after PATCH %s", stop_url);
9396
9878
  }
9879
+ if (!this._ingressEventWs && this._ingressEventHandler) {
9880
+ await this.startIngressWs();
9881
+ }
9397
9882
  return result;
9398
9883
  }
9399
9884
  jobDone(job) {
@@ -9556,7 +10041,7 @@ var _EyePopPlot = class _EyePopPlot {
9556
10041
  }
9557
10042
  }
9558
10043
  }
9559
- object(obj, x_scale, y_scale) {
10044
+ object(obj, x_scale = 1, y_scale = 1) {
9560
10045
  const context = this._context;
9561
10046
  const x = obj.x * x_scale;
9562
10047
  const y = obj.y * y_scale;